Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/templates/a_hash_map.h
9973 views
1
/**************************************************************************/
2
/* a_hash_map.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "core/templates/hash_map.h"
34
35
struct HashMapData {
36
union {
37
uint64_t data;
38
struct
39
{
40
uint32_t hash;
41
uint32_t hash_to_key;
42
};
43
};
44
};
45
46
static_assert(sizeof(HashMapData) == 8);
47
48
/**
49
* An array-based implementation of a hash map. It is very efficient in terms of performance and
50
* memory usage. Works like a dynamic array, adding elements to the end of the array, and
51
* allows you to access array elements by their index by using `get_by_index` method.
52
* Example:
53
* ```
54
* AHashMap<int, Object *> map;
55
*
56
* int get_object_id_by_number(int p_number) {
57
* int id = map.get_index(p_number);
58
* return id;
59
* }
60
*
61
* Object *get_object_by_id(int p_id) {
62
* map.get_by_index(p_id).value;
63
* }
64
* ```
65
* Still, don`t erase the elements because ID can break.
66
*
67
* When an element erase, its place is taken by the element from the end.
68
*
69
* <-------------
70
* | |
71
* 6 8 X 9 32 -1 5 -10 7 X X X
72
* 6 8 7 9 32 -1 5 -10 X X X X
73
*
74
*
75
* Use RBMap if you need to iterate over sorted elements.
76
*
77
* Use HashMap if:
78
* - You need to keep an iterator or const pointer to Key and you intend to add/remove elements in the meantime.
79
* - You need to preserve the insertion order when using erase.
80
*
81
* It is recommended to use `HashMap` if `KeyValue` size is very large.
82
*/
83
template <typename TKey, typename TValue,
84
typename Hasher = HashMapHasherDefault,
85
typename Comparator = HashMapComparatorDefault<TKey>>
86
class AHashMap {
87
public:
88
// Must be a power of two.
89
static constexpr uint32_t INITIAL_CAPACITY = 16;
90
static constexpr uint32_t EMPTY_HASH = 0;
91
static_assert(EMPTY_HASH == 0, "EMPTY_HASH must always be 0 for the memcpy() optimization.");
92
93
private:
94
typedef KeyValue<TKey, TValue> MapKeyValue;
95
MapKeyValue *elements = nullptr;
96
HashMapData *map_data = nullptr;
97
98
// Due to optimization, this is `capacity - 1`. Use + 1 to get normal capacity.
99
uint32_t capacity = 0;
100
uint32_t num_elements = 0;
101
102
uint32_t _hash(const TKey &p_key) const {
103
uint32_t hash = Hasher::hash(p_key);
104
105
if (unlikely(hash == EMPTY_HASH)) {
106
hash = EMPTY_HASH + 1;
107
}
108
109
return hash;
110
}
111
112
static _FORCE_INLINE_ uint32_t _get_resize_count(uint32_t p_capacity) {
113
return p_capacity ^ (p_capacity + 1) >> 2; // = get_capacity() * 0.75 - 1; Works only if p_capacity = 2^n - 1.
114
}
115
116
static _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_local_capacity) {
117
const uint32_t original_pos = p_hash & p_local_capacity;
118
return (p_pos - original_pos + p_local_capacity + 1) & p_local_capacity;
119
}
120
121
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos, uint32_t &r_hash_pos) const {
122
if (unlikely(elements == nullptr)) {
123
return false; // Failed lookups, no elements.
124
}
125
return _lookup_pos_with_hash(p_key, r_pos, r_hash_pos, _hash(p_key));
126
}
127
128
bool _lookup_pos_with_hash(const TKey &p_key, uint32_t &r_pos, uint32_t &r_hash_pos, uint32_t p_hash) const {
129
if (unlikely(elements == nullptr)) {
130
return false; // Failed lookups, no elements.
131
}
132
133
uint32_t pos = p_hash & capacity;
134
HashMapData data = map_data[pos];
135
if (data.hash == p_hash && Comparator::compare(elements[data.hash_to_key].key, p_key)) {
136
r_pos = data.hash_to_key;
137
r_hash_pos = pos;
138
return true;
139
}
140
141
if (data.data == EMPTY_HASH) {
142
return false;
143
}
144
145
// A collision occurred.
146
pos = (pos + 1) & capacity;
147
uint32_t distance = 1;
148
while (true) {
149
data = map_data[pos];
150
if (data.hash == p_hash && Comparator::compare(elements[data.hash_to_key].key, p_key)) {
151
r_pos = data.hash_to_key;
152
r_hash_pos = pos;
153
return true;
154
}
155
156
if (data.data == EMPTY_HASH) {
157
return false;
158
}
159
160
if (distance > _get_probe_length(pos, data.hash, capacity)) {
161
return false;
162
}
163
164
pos = (pos + 1) & capacity;
165
distance++;
166
}
167
}
168
169
uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
170
uint32_t pos = p_hash & capacity;
171
172
if (map_data[pos].data == EMPTY_HASH) {
173
uint64_t data = ((uint64_t)p_index << 32) | p_hash;
174
map_data[pos].data = data;
175
return pos;
176
}
177
178
uint32_t distance = 1;
179
pos = (pos + 1) & capacity;
180
HashMapData c_data;
181
c_data.hash = p_hash;
182
c_data.hash_to_key = p_index;
183
184
while (true) {
185
if (map_data[pos].data == EMPTY_HASH) {
186
#ifdef DEV_ENABLED
187
if (unlikely(distance > 12)) {
188
WARN_PRINT("Excessive collision count (" +
189
itos(distance) + "), is the right hash function being used?");
190
}
191
#endif
192
map_data[pos] = c_data;
193
return pos;
194
}
195
196
// Not an empty slot, let's check the probing length of the existing one.
197
uint32_t existing_probe_len = _get_probe_length(pos, map_data[pos].hash, capacity);
198
if (existing_probe_len < distance) {
199
SWAP(c_data, map_data[pos]);
200
distance = existing_probe_len;
201
}
202
203
pos = (pos + 1) & capacity;
204
distance++;
205
}
206
}
207
208
void _resize_and_rehash(uint32_t p_new_capacity) {
209
uint32_t real_old_capacity = capacity + 1;
210
// Capacity can't be 0 and must be 2^n - 1.
211
capacity = MAX(4u, p_new_capacity);
212
uint32_t real_capacity = next_power_of_2(capacity);
213
capacity = real_capacity - 1;
214
215
HashMapData *old_map_data = map_data;
216
217
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static_zeroed(sizeof(HashMapData) * real_capacity));
218
elements = reinterpret_cast<MapKeyValue *>(Memory::realloc_static(elements, sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
219
220
if (num_elements != 0) {
221
for (uint32_t i = 0; i < real_old_capacity; i++) {
222
HashMapData data = old_map_data[i];
223
if (data.data != EMPTY_HASH) {
224
_insert_with_hash(data.hash, data.hash_to_key);
225
}
226
}
227
}
228
229
Memory::free_static(old_map_data);
230
}
231
232
int32_t _insert_element(const TKey &p_key, const TValue &p_value, uint32_t p_hash) {
233
if (unlikely(elements == nullptr)) {
234
// Allocate on demand to save memory.
235
236
uint32_t real_capacity = capacity + 1;
237
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static_zeroed(sizeof(HashMapData) * real_capacity));
238
elements = reinterpret_cast<MapKeyValue *>(Memory::alloc_static(sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
239
}
240
241
if (unlikely(num_elements > _get_resize_count(capacity))) {
242
_resize_and_rehash(capacity * 2);
243
}
244
245
memnew_placement(&elements[num_elements], MapKeyValue(p_key, p_value));
246
247
_insert_with_hash(p_hash, num_elements);
248
num_elements++;
249
return num_elements - 1;
250
}
251
252
void _init_from(const AHashMap &p_other) {
253
capacity = p_other.capacity;
254
uint32_t real_capacity = capacity + 1;
255
num_elements = p_other.num_elements;
256
257
if (p_other.num_elements == 0) {
258
return;
259
}
260
261
map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static(sizeof(HashMapData) * real_capacity));
262
elements = reinterpret_cast<MapKeyValue *>(Memory::alloc_static(sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
263
264
if constexpr (std::is_trivially_copyable_v<TKey> && std::is_trivially_copyable_v<TValue>) {
265
void *destination = elements;
266
const void *source = p_other.elements;
267
memcpy(destination, source, sizeof(MapKeyValue) * num_elements);
268
} else {
269
for (uint32_t i = 0; i < num_elements; i++) {
270
memnew_placement(&elements[i], MapKeyValue(p_other.elements[i]));
271
}
272
}
273
274
memcpy(map_data, p_other.map_data, sizeof(HashMapData) * real_capacity);
275
}
276
277
public:
278
/* Standard Godot Container API */
279
280
_FORCE_INLINE_ uint32_t get_capacity() const { return capacity + 1; }
281
_FORCE_INLINE_ uint32_t size() const { return num_elements; }
282
283
_FORCE_INLINE_ bool is_empty() const {
284
return num_elements == 0;
285
}
286
287
void clear() {
288
if (elements == nullptr || num_elements == 0) {
289
return;
290
}
291
292
memset(map_data, EMPTY_HASH, (capacity + 1) * sizeof(HashMapData));
293
if constexpr (!(std::is_trivially_destructible_v<TKey> && std::is_trivially_destructible_v<TValue>)) {
294
for (uint32_t i = 0; i < num_elements; i++) {
295
elements[i].key.~TKey();
296
elements[i].value.~TValue();
297
}
298
}
299
300
num_elements = 0;
301
}
302
303
TValue &get(const TKey &p_key) {
304
uint32_t pos = 0;
305
uint32_t hash_pos = 0;
306
bool exists = _lookup_pos(p_key, pos, hash_pos);
307
CRASH_COND_MSG(!exists, "AHashMap key not found.");
308
return elements[pos].value;
309
}
310
311
const TValue &get(const TKey &p_key) const {
312
uint32_t pos = 0;
313
uint32_t hash_pos = 0;
314
bool exists = _lookup_pos(p_key, pos, hash_pos);
315
CRASH_COND_MSG(!exists, "AHashMap key not found.");
316
return elements[pos].value;
317
}
318
319
const TValue *getptr(const TKey &p_key) const {
320
uint32_t pos = 0;
321
uint32_t hash_pos = 0;
322
bool exists = _lookup_pos(p_key, pos, hash_pos);
323
324
if (exists) {
325
return &elements[pos].value;
326
}
327
return nullptr;
328
}
329
330
TValue *getptr(const TKey &p_key) {
331
uint32_t pos = 0;
332
uint32_t hash_pos = 0;
333
bool exists = _lookup_pos(p_key, pos, hash_pos);
334
335
if (exists) {
336
return &elements[pos].value;
337
}
338
return nullptr;
339
}
340
341
bool has(const TKey &p_key) const {
342
uint32_t _pos = 0;
343
uint32_t h_pos = 0;
344
return _lookup_pos(p_key, _pos, h_pos);
345
}
346
347
bool erase(const TKey &p_key) {
348
uint32_t pos = 0;
349
uint32_t element_pos = 0;
350
bool exists = _lookup_pos(p_key, element_pos, pos);
351
352
if (!exists) {
353
return false;
354
}
355
356
uint32_t next_pos = (pos + 1) & capacity;
357
while (map_data[next_pos].hash != EMPTY_HASH && _get_probe_length(next_pos, map_data[next_pos].hash, capacity) != 0) {
358
SWAP(map_data[next_pos], map_data[pos]);
359
360
pos = next_pos;
361
next_pos = (next_pos + 1) & capacity;
362
}
363
364
map_data[pos].data = EMPTY_HASH;
365
elements[element_pos].key.~TKey();
366
elements[element_pos].value.~TValue();
367
num_elements--;
368
369
if (element_pos < num_elements) {
370
void *destination = &elements[element_pos];
371
const void *source = &elements[num_elements];
372
memcpy(destination, source, sizeof(MapKeyValue));
373
uint32_t h_pos = 0;
374
_lookup_pos(elements[num_elements].key, pos, h_pos);
375
map_data[h_pos].hash_to_key = element_pos;
376
}
377
378
return true;
379
}
380
381
// Replace the key of an entry in-place, without invalidating iterators or changing the entries position during iteration.
382
// p_old_key must exist in the map and p_new_key must not, unless it is equal to p_old_key.
383
bool replace_key(const TKey &p_old_key, const TKey &p_new_key) {
384
if (p_old_key == p_new_key) {
385
return true;
386
}
387
uint32_t pos = 0;
388
uint32_t element_pos = 0;
389
ERR_FAIL_COND_V(_lookup_pos(p_new_key, element_pos, pos), false);
390
ERR_FAIL_COND_V(!_lookup_pos(p_old_key, element_pos, pos), false);
391
MapKeyValue &element = elements[element_pos];
392
const_cast<TKey &>(element.key) = p_new_key;
393
394
uint32_t next_pos = (pos + 1) & capacity;
395
while (map_data[next_pos].hash != EMPTY_HASH && _get_probe_length(next_pos, map_data[next_pos].hash, capacity) != 0) {
396
SWAP(map_data[next_pos], map_data[pos]);
397
398
pos = next_pos;
399
next_pos = (next_pos + 1) & capacity;
400
}
401
402
map_data[pos].data = EMPTY_HASH;
403
404
uint32_t hash = _hash(p_new_key);
405
_insert_with_hash(hash, element_pos);
406
407
return true;
408
}
409
410
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
411
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
412
void reserve(uint32_t p_new_capacity) {
413
ERR_FAIL_COND_MSG(p_new_capacity < size(), "reserve() called with a capacity smaller than the current size. This is likely a mistake.");
414
if (elements == nullptr) {
415
capacity = MAX(4u, p_new_capacity);
416
capacity = next_power_of_2(capacity) - 1;
417
return; // Unallocated yet.
418
}
419
if (p_new_capacity <= get_capacity()) {
420
return;
421
}
422
_resize_and_rehash(p_new_capacity);
423
}
424
425
/** Iterator API **/
426
427
struct ConstIterator {
428
_FORCE_INLINE_ const MapKeyValue &operator*() const {
429
return *pair;
430
}
431
_FORCE_INLINE_ const MapKeyValue *operator->() const {
432
return pair;
433
}
434
_FORCE_INLINE_ ConstIterator &operator++() {
435
pair++;
436
return *this;
437
}
438
439
_FORCE_INLINE_ ConstIterator &operator--() {
440
pair--;
441
if (pair < begin) {
442
pair = end;
443
}
444
return *this;
445
}
446
447
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return pair == b.pair; }
448
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return pair != b.pair; }
449
450
_FORCE_INLINE_ explicit operator bool() const {
451
return pair != end;
452
}
453
454
_FORCE_INLINE_ ConstIterator(MapKeyValue *p_key, MapKeyValue *p_begin, MapKeyValue *p_end) {
455
pair = p_key;
456
begin = p_begin;
457
end = p_end;
458
}
459
_FORCE_INLINE_ ConstIterator() {}
460
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) {
461
pair = p_it.pair;
462
begin = p_it.begin;
463
end = p_it.end;
464
}
465
_FORCE_INLINE_ void operator=(const ConstIterator &p_it) {
466
pair = p_it.pair;
467
begin = p_it.begin;
468
end = p_it.end;
469
}
470
471
private:
472
MapKeyValue *pair = nullptr;
473
MapKeyValue *begin = nullptr;
474
MapKeyValue *end = nullptr;
475
};
476
477
struct Iterator {
478
_FORCE_INLINE_ MapKeyValue &operator*() const {
479
return *pair;
480
}
481
_FORCE_INLINE_ MapKeyValue *operator->() const {
482
return pair;
483
}
484
_FORCE_INLINE_ Iterator &operator++() {
485
pair++;
486
return *this;
487
}
488
_FORCE_INLINE_ Iterator &operator--() {
489
pair--;
490
if (pair < begin) {
491
pair = end;
492
}
493
return *this;
494
}
495
496
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return pair == b.pair; }
497
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return pair != b.pair; }
498
499
_FORCE_INLINE_ explicit operator bool() const {
500
return pair != end;
501
}
502
503
_FORCE_INLINE_ Iterator(MapKeyValue *p_key, MapKeyValue *p_begin, MapKeyValue *p_end) {
504
pair = p_key;
505
begin = p_begin;
506
end = p_end;
507
}
508
_FORCE_INLINE_ Iterator() {}
509
_FORCE_INLINE_ Iterator(const Iterator &p_it) {
510
pair = p_it.pair;
511
begin = p_it.begin;
512
end = p_it.end;
513
}
514
_FORCE_INLINE_ void operator=(const Iterator &p_it) {
515
pair = p_it.pair;
516
begin = p_it.begin;
517
end = p_it.end;
518
}
519
520
operator ConstIterator() const {
521
return ConstIterator(pair, begin, end);
522
}
523
524
private:
525
MapKeyValue *pair = nullptr;
526
MapKeyValue *begin = nullptr;
527
MapKeyValue *end = nullptr;
528
};
529
530
_FORCE_INLINE_ Iterator begin() {
531
return Iterator(elements, elements, elements + num_elements);
532
}
533
_FORCE_INLINE_ Iterator end() {
534
return Iterator(elements + num_elements, elements, elements + num_elements);
535
}
536
_FORCE_INLINE_ Iterator last() {
537
if (unlikely(num_elements == 0)) {
538
return Iterator(nullptr, nullptr, nullptr);
539
}
540
return Iterator(elements + num_elements - 1, elements, elements + num_elements);
541
}
542
543
Iterator find(const TKey &p_key) {
544
uint32_t pos = 0;
545
uint32_t h_pos = 0;
546
bool exists = _lookup_pos(p_key, pos, h_pos);
547
if (!exists) {
548
return end();
549
}
550
return Iterator(elements + pos, elements, elements + num_elements);
551
}
552
553
void remove(const Iterator &p_iter) {
554
if (p_iter) {
555
erase(p_iter->key);
556
}
557
}
558
559
_FORCE_INLINE_ ConstIterator begin() const {
560
return ConstIterator(elements, elements, elements + num_elements);
561
}
562
_FORCE_INLINE_ ConstIterator end() const {
563
return ConstIterator(elements + num_elements, elements, elements + num_elements);
564
}
565
_FORCE_INLINE_ ConstIterator last() const {
566
if (unlikely(num_elements == 0)) {
567
return ConstIterator(nullptr, nullptr, nullptr);
568
}
569
return ConstIterator(elements + num_elements - 1, elements, elements + num_elements);
570
}
571
572
ConstIterator find(const TKey &p_key) const {
573
uint32_t pos = 0;
574
uint32_t h_pos = 0;
575
bool exists = _lookup_pos(p_key, pos, h_pos);
576
if (!exists) {
577
return end();
578
}
579
return ConstIterator(elements + pos, elements, elements + num_elements);
580
}
581
582
/* Indexing */
583
584
const TValue &operator[](const TKey &p_key) const {
585
uint32_t pos = 0;
586
uint32_t h_pos = 0;
587
bool exists = _lookup_pos(p_key, pos, h_pos);
588
CRASH_COND(!exists);
589
return elements[pos].value;
590
}
591
592
TValue &operator[](const TKey &p_key) {
593
uint32_t pos = 0;
594
uint32_t h_pos = 0;
595
uint32_t hash = _hash(p_key);
596
bool exists = _lookup_pos_with_hash(p_key, pos, h_pos, hash);
597
598
if (exists) {
599
return elements[pos].value;
600
} else {
601
pos = _insert_element(p_key, TValue(), hash);
602
return elements[pos].value;
603
}
604
}
605
606
/* Insert */
607
608
Iterator insert(const TKey &p_key, const TValue &p_value) {
609
uint32_t pos = 0;
610
uint32_t h_pos = 0;
611
uint32_t hash = _hash(p_key);
612
bool exists = _lookup_pos_with_hash(p_key, pos, h_pos, hash);
613
614
if (!exists) {
615
pos = _insert_element(p_key, p_value, hash);
616
} else {
617
elements[pos].value = p_value;
618
}
619
return Iterator(elements + pos, elements, elements + num_elements);
620
}
621
622
// Inserts an element without checking if it already exists.
623
Iterator insert_new(const TKey &p_key, const TValue &p_value) {
624
DEV_ASSERT(!has(p_key));
625
uint32_t hash = _hash(p_key);
626
uint32_t pos = _insert_element(p_key, p_value, hash);
627
return Iterator(elements + pos, elements, elements + num_elements);
628
}
629
630
/* Array methods. */
631
632
// Unsafe. Changing keys and going outside the bounds of an array can lead to undefined behavior.
633
KeyValue<TKey, TValue> *get_elements_ptr() {
634
return elements;
635
}
636
637
// Returns the element index. If not found, returns -1.
638
int get_index(const TKey &p_key) {
639
uint32_t pos = 0;
640
uint32_t h_pos = 0;
641
bool exists = _lookup_pos(p_key, pos, h_pos);
642
if (!exists) {
643
return -1;
644
}
645
return pos;
646
}
647
648
KeyValue<TKey, TValue> &get_by_index(uint32_t p_index) {
649
CRASH_BAD_UNSIGNED_INDEX(p_index, num_elements);
650
return elements[p_index];
651
}
652
653
bool erase_by_index(uint32_t p_index) {
654
if (p_index >= size()) {
655
return false;
656
}
657
return erase(elements[p_index].key);
658
}
659
660
/* Constructors */
661
662
AHashMap(const AHashMap &p_other) {
663
_init_from(p_other);
664
}
665
666
AHashMap(const HashMap<TKey, TValue> &p_other) {
667
reserve(p_other.size());
668
for (const KeyValue<TKey, TValue> &E : p_other) {
669
uint32_t hash = _hash(E.key);
670
_insert_element(E.key, E.value, hash);
671
}
672
}
673
674
void operator=(const AHashMap &p_other) {
675
if (this == &p_other) {
676
return; // Ignore self assignment.
677
}
678
679
reset();
680
681
_init_from(p_other);
682
}
683
684
void operator=(const HashMap<TKey, TValue> &p_other) {
685
reset();
686
reserve(p_other.size());
687
for (const KeyValue<TKey, TValue> &E : p_other) {
688
uint32_t hash = _hash(E.key);
689
_insert_element(E.key, E.value, hash);
690
}
691
}
692
693
AHashMap(uint32_t p_initial_capacity) {
694
// Capacity can't be 0 and must be 2^n - 1.
695
capacity = MAX(4u, p_initial_capacity);
696
capacity = next_power_of_2(capacity) - 1;
697
}
698
AHashMap() :
699
capacity(INITIAL_CAPACITY - 1) {
700
}
701
702
AHashMap(std::initializer_list<KeyValue<TKey, TValue>> p_init) {
703
reserve(p_init.size());
704
for (const KeyValue<TKey, TValue> &E : p_init) {
705
insert(E.key, E.value);
706
}
707
}
708
709
void reset() {
710
if (elements != nullptr) {
711
if constexpr (!(std::is_trivially_destructible_v<TKey> && std::is_trivially_destructible_v<TValue>)) {
712
for (uint32_t i = 0; i < num_elements; i++) {
713
elements[i].key.~TKey();
714
elements[i].value.~TValue();
715
}
716
}
717
Memory::free_static(elements);
718
Memory::free_static(map_data);
719
elements = nullptr;
720
}
721
capacity = INITIAL_CAPACITY - 1;
722
num_elements = 0;
723
}
724
725
~AHashMap() {
726
reset();
727
}
728
};
729
730
extern template class AHashMap<int, int>;
731
extern template class AHashMap<String, int>;
732
extern template class AHashMap<StringName, StringName>;
733
extern template class AHashMap<StringName, Variant>;
734
extern template class AHashMap<StringName, int>;
735
736