diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h index a3e8c2c788c6..bb102506704e 100644 --- a/core/templates/hash_map.h +++ b/core/templates/hash_map.h @@ -81,8 +81,19 @@ class HashMap { uint32_t capacity_index = 0; uint32_t num_elements = 0; - _FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const { - uint32_t hash = Hasher::hash(p_key); + _FORCE_INLINE_ uint32_t _hash(TKey &&p_key) const { + uint32_t hash = Hasher::hash(static_cast(p_key)); + + if (unlikely(hash == EMPTY_HASH)) { + hash = EMPTY_HASH + 1; + } + + return hash; + } + + template + _FORCE_INLINE_ uint32_t _hash(TKeyParam &&p_key) const { + uint32_t hash = Hasher::hash(static_cast(p_key)); if (unlikely(hash == EMPTY_HASH)) { hash = EMPTY_HASH + 1; @@ -96,14 +107,15 @@ class HashMap { return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity); } - bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const { + template + bool _lookup_pos(TKeyParam &&p_key, uint32_t &r_pos) const { if (elements == nullptr || num_elements == 0) { return false; // Failed lookups, no elements } const uint32_t capacity = hash_table_size_primes[capacity_index]; const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; - uint32_t hash = _hash(p_key); + uint32_t hash = _hash(static_cast(p_key)); uint32_t pos = fastmod(hash, capacity_inv, capacity); uint32_t distance = 0; @@ -116,7 +128,7 @@ class HashMap { return false; } - if (hashes[pos] == hash && Comparator::compare(elements[pos]->data.key, p_key)) { + if (hashes[pos] == hash && Comparator::compare(elements[pos]->data.key, static_cast(p_key))) { r_pos = pos; return true; } @@ -194,7 +206,8 @@ class HashMap { Memory::free_static(old_hashes); } - _FORCE_INLINE_ HashMapElement *_insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) { + template + _FORCE_INLINE_ HashMapElement *_insert(TKeyParam &&p_key, TValueParam &&p_value, bool p_front_insert = false) { uint32_t capacity = hash_table_size_primes[capacity_index]; if (unlikely(elements == nullptr)) { // Allocate on demand to save memory. @@ -209,10 +222,10 @@ class HashMap { } uint32_t pos = 0; - bool exists = _lookup_pos(p_key, pos); + bool exists = _lookup_pos(static_cast(p_key), pos); if (exists) { - elements[pos]->data.value = p_value; + elements[pos]->data.value = static_cast(p_value); return elements[pos]; } else { if (num_elements + 1 > MAX_OCCUPANCY * capacity) { @@ -220,7 +233,7 @@ class HashMap { _resize_and_rehash(capacity_index + 1); } - HashMapElement *elem = element_alloc.new_allocation(HashMapElement(p_key, p_value)); + HashMapElement *elem = element_alloc.new_allocation(HashMapElement(static_cast(p_key), static_cast(p_value))); if (tail_element == nullptr) { head_element = elem; @@ -235,7 +248,7 @@ class HashMap { tail_element = elem; } - uint32_t hash = _hash(p_key); + uint32_t hash = _hash(static_cast(p_key)); _insert_with_hash(hash, elem); return elem; } @@ -271,23 +284,26 @@ class HashMap { num_elements = 0; } - TValue &get(const TKey &p_key) { + template + TValue &get(TKeyParam &&p_key) { uint32_t pos = 0; - bool exists = _lookup_pos(p_key, pos); + bool exists = _lookup_pos(static_cast(p_key), pos); CRASH_COND_MSG(!exists, "HashMap key not found."); return elements[pos]->data.value; } - const TValue &get(const TKey &p_key) const { + template + const TValue &get(TKeyParam &&p_key) const { uint32_t pos = 0; - bool exists = _lookup_pos(p_key, pos); + bool exists = _lookup_pos(static_cast(p_key), pos); CRASH_COND_MSG(!exists, "HashMap key not found."); return elements[pos]->data.value; } - const TValue *getptr(const TKey &p_key) const { + template + const TValue *getptr(TKeyParam &&p_key) const { uint32_t pos = 0; - bool exists = _lookup_pos(p_key, pos); + bool exists = _lookup_pos(static_cast(p_key), pos); if (exists) { return &elements[pos]->data.value; @@ -295,9 +311,10 @@ class HashMap { return nullptr; } - TValue *getptr(const TKey &p_key) { + template + TValue *getptr(TKeyParam &&p_key) { uint32_t pos = 0; - bool exists = _lookup_pos(p_key, pos); + bool exists = _lookup_pos(static_cast(p_key), pos); if (exists) { return &elements[pos]->data.value; @@ -305,14 +322,16 @@ class HashMap { return nullptr; } - _FORCE_INLINE_ bool has(const TKey &p_key) const { + template + _FORCE_INLINE_ bool has(TKeyParam &&p_key) const { uint32_t _pos = 0; - return _lookup_pos(p_key, _pos); + return _lookup_pos(static_cast(p_key), _pos); } - bool erase(const TKey &p_key) { + template + bool erase(TKeyParam &&p_key) { uint32_t pos = 0; - bool exists = _lookup_pos(p_key, pos); + bool exists = _lookup_pos(static_cast(p_key), pos); if (!exists) { return false; @@ -355,13 +374,14 @@ class HashMap { // Replace the key of an entry in-place, without invalidating iterators or changing the entries position during iteration. // p_old_key must exist in the map and p_new_key must not, unless it is equal to p_old_key. - bool replace_key(const TKey &p_old_key, const TKey &p_new_key) { - if (p_old_key == p_new_key) { + template + bool replace_key(TKeyParamOld &&p_old_key, TKeyParamNew &&p_new_key) { + if (static_cast(p_old_key) == static_cast(p_new_key)) { return true; } uint32_t pos = 0; - ERR_FAIL_COND_V(_lookup_pos(p_new_key, pos), false); - ERR_FAIL_COND_V(!_lookup_pos(p_old_key, pos), false); + ERR_FAIL_COND_V(_lookup_pos(static_cast(p_new_key), pos), false); + ERR_FAIL_COND_V(!_lookup_pos(static_cast(p_old_key), pos), false); HashMapElement *element = elements[pos]; // Delete the old entries in hashes and elements. @@ -380,8 +400,8 @@ class HashMap { num_elements--; // Update the HashMapElement with the new key and reinsert it. - const_cast(element->data.key) = p_new_key; - uint32_t hash = _hash(p_new_key); + const_cast(element->data.key) = static_cast(p_new_key); + uint32_t hash = _hash(static_cast(p_new_key)); _insert_with_hash(hash, element); return true; @@ -496,9 +516,10 @@ class HashMap { return Iterator(tail_element); } - _FORCE_INLINE_ Iterator find(const TKey &p_key) { + template + _FORCE_INLINE_ Iterator find(TKeyParam &&p_key) { uint32_t pos = 0; - bool exists = _lookup_pos(p_key, pos); + bool exists = _lookup_pos(static_cast(p_key), pos); if (!exists) { return end(); } @@ -521,9 +542,10 @@ class HashMap { return ConstIterator(tail_element); } - _FORCE_INLINE_ ConstIterator find(const TKey &p_key) const { + template + _FORCE_INLINE_ ConstIterator find(TKeyParam &&p_key) const { uint32_t pos = 0; - bool exists = _lookup_pos(p_key, pos); + bool exists = _lookup_pos(static_cast(p_key), pos); if (!exists) { return end(); } @@ -532,18 +554,20 @@ class HashMap { /* Indexing */ - const TValue &operator[](const TKey &p_key) const { + template + const TValue &operator[](TKeyParam &&p_key) const { uint32_t pos = 0; - bool exists = _lookup_pos(p_key, pos); + bool exists = _lookup_pos(static_cast(p_key), pos); CRASH_COND(!exists); return elements[pos]->data.value; } - TValue &operator[](const TKey &p_key) { + template + TValue &operator[](TKeyParam &&p_key) { uint32_t pos = 0; - bool exists = _lookup_pos(p_key, pos); + bool exists = _lookup_pos(static_cast(p_key), pos); if (!exists) { - return _insert(p_key, TValue())->data.value; + return _insert(static_cast(p_key), TValue())->data.value; } else { return elements[pos]->data.value; } @@ -551,8 +575,9 @@ class HashMap { /* Insert */ - Iterator insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) { - return Iterator(_insert(p_key, p_value, p_front_insert)); + template + Iterator insert(TKeyParam &&p_key, TValue p_value, bool p_front_insert = false) { + return Iterator(_insert(static_cast(p_key), static_cast(p_value), p_front_insert)); } /* Constructors */ @@ -569,9 +594,19 @@ class HashMap { } } - void operator=(const HashMap &p_other) { + HashMap(HashMap &&p_other) { + SWAP(element_alloc, p_other.element_alloc); + SWAP(elements, p_other.elements); + SWAP(hashes, p_other.hashes); + SWAP(head_element, p_other.head_element); + SWAP(tail_element, p_other.tail_element); + SWAP(capacity_index, p_other.capacity_index); + SWAP(num_elements, p_other.num_elements); + } + + HashMap &operator=(const HashMap &p_other) { if (this == &p_other) { - return; // Ignore self assignment. + return *this; // Ignore self assignment. } if (num_elements != 0) { clear(); @@ -580,12 +615,25 @@ class HashMap { reserve(hash_table_size_primes[p_other.capacity_index]); if (p_other.elements == nullptr) { - return; // Nothing to copy. + return *this; // Nothing to copy. } for (const KeyValue &E : p_other) { insert(E.key, E.value); } + + return *this; + } + + HashMap &operator=(HashMap &&p_other) { + SWAP(element_alloc, p_other.element_alloc); + SWAP(elements, p_other.elements); + SWAP(hashes, p_other.hashes); + SWAP(head_element, p_other.head_element); + SWAP(tail_element, p_other.tail_element); + SWAP(capacity_index, p_other.capacity_index); + SWAP(num_elements, p_other.num_elements); + return *this; } HashMap(uint32_t p_initial_capacity) {