a_hash_map.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  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. #pragma once
  31. #include "core/templates/hash_map.h"
  32. struct HashMapData {
  33. union {
  34. uint64_t data;
  35. struct
  36. {
  37. uint32_t hash;
  38. uint32_t hash_to_key;
  39. };
  40. };
  41. };
  42. static_assert(sizeof(HashMapData) == 8);
  43. /**
  44. * An array-based implementation of a hash map. It is very efficient in terms of performance and
  45. * memory usage. Works like a dynamic array, adding elements to the end of the array, and
  46. * allows you to access array elements by their index by using `get_by_index` method.
  47. * Example:
  48. * ```
  49. * AHashMap<int, Object *> map;
  50. *
  51. * int get_object_id_by_number(int p_number) {
  52. * int id = map.get_index(p_number);
  53. * return id;
  54. * }
  55. *
  56. * Object *get_object_by_id(int p_id) {
  57. * map.get_by_index(p_id).value;
  58. * }
  59. * ```
  60. * Still, don`t erase the elements because ID can break.
  61. *
  62. * When an element erase, its place is taken by the element from the end.
  63. *
  64. * <-------------
  65. * | |
  66. * 6 8 X 9 32 -1 5 -10 7 X X X
  67. * 6 8 7 9 32 -1 5 -10 X X X X
  68. *
  69. *
  70. * Use RBMap if you need to iterate over sorted elements.
  71. *
  72. * Use HashMap if:
  73. * - You need to keep an iterator or const pointer to Key and you intend to add/remove elements in the meantime.
  74. * - You need to preserve the insertion order when using erase.
  75. *
  76. * It is recommended to use `HashMap` if `KeyValue` size is very large.
  77. */
  78. template <typename TKey, typename TValue,
  79. typename Hasher = HashMapHasherDefault,
  80. typename Comparator = HashMapComparatorDefault<TKey>>
  81. class AHashMap {
  82. public:
  83. // Must be a power of two.
  84. static constexpr uint32_t INITIAL_CAPACITY = 16;
  85. static constexpr uint32_t EMPTY_HASH = 0;
  86. static_assert(EMPTY_HASH == 0, "EMPTY_HASH must always be 0 for the memcpy() optimization.");
  87. private:
  88. typedef KeyValue<TKey, TValue> MapKeyValue;
  89. MapKeyValue *elements = nullptr;
  90. HashMapData *map_data = nullptr;
  91. // Due to optimization, this is `capacity - 1`. Use + 1 to get normal capacity.
  92. uint32_t capacity = 0;
  93. uint32_t num_elements = 0;
  94. uint32_t _hash(const TKey &p_key) const {
  95. uint32_t hash = Hasher::hash(p_key);
  96. if (unlikely(hash == EMPTY_HASH)) {
  97. hash = EMPTY_HASH + 1;
  98. }
  99. return hash;
  100. }
  101. static _FORCE_INLINE_ uint32_t _get_resize_count(uint32_t p_capacity) {
  102. return p_capacity ^ (p_capacity + 1) >> 2; // = get_capacity() * 0.75 - 1; Works only if p_capacity = 2^n - 1.
  103. }
  104. static _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_local_capacity) {
  105. const uint32_t original_pos = p_hash & p_local_capacity;
  106. return (p_pos - original_pos + p_local_capacity + 1) & p_local_capacity;
  107. }
  108. bool _lookup_pos(const TKey &p_key, uint32_t &r_pos, uint32_t &r_hash_pos) const {
  109. if (unlikely(elements == nullptr)) {
  110. return false; // Failed lookups, no elements.
  111. }
  112. return _lookup_pos_with_hash(p_key, r_pos, r_hash_pos, _hash(p_key));
  113. }
  114. bool _lookup_pos_with_hash(const TKey &p_key, uint32_t &r_pos, uint32_t &r_hash_pos, uint32_t p_hash) const {
  115. if (unlikely(elements == nullptr)) {
  116. return false; // Failed lookups, no elements.
  117. }
  118. uint32_t pos = p_hash & capacity;
  119. HashMapData data = map_data[pos];
  120. if (data.hash == p_hash && Comparator::compare(elements[data.hash_to_key].key, p_key)) {
  121. r_pos = data.hash_to_key;
  122. r_hash_pos = pos;
  123. return true;
  124. }
  125. if (data.data == EMPTY_HASH) {
  126. return false;
  127. }
  128. // A collision occurred.
  129. pos = (pos + 1) & capacity;
  130. uint32_t distance = 1;
  131. while (true) {
  132. data = map_data[pos];
  133. if (data.hash == p_hash && Comparator::compare(elements[data.hash_to_key].key, p_key)) {
  134. r_pos = data.hash_to_key;
  135. r_hash_pos = pos;
  136. return true;
  137. }
  138. if (data.data == EMPTY_HASH) {
  139. return false;
  140. }
  141. if (distance > _get_probe_length(pos, data.hash, capacity)) {
  142. return false;
  143. }
  144. pos = (pos + 1) & capacity;
  145. distance++;
  146. }
  147. }
  148. uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
  149. uint32_t pos = p_hash & capacity;
  150. if (map_data[pos].data == EMPTY_HASH) {
  151. uint64_t data = ((uint64_t)p_index << 32) | p_hash;
  152. map_data[pos].data = data;
  153. return pos;
  154. }
  155. uint32_t distance = 1;
  156. pos = (pos + 1) & capacity;
  157. HashMapData c_data;
  158. c_data.hash = p_hash;
  159. c_data.hash_to_key = p_index;
  160. while (true) {
  161. if (map_data[pos].data == EMPTY_HASH) {
  162. #ifdef DEV_ENABLED
  163. if (unlikely(distance > 12)) {
  164. WARN_PRINT("Excessive collision count (" +
  165. itos(distance) + "), is the right hash function being used?");
  166. }
  167. #endif
  168. map_data[pos] = c_data;
  169. return pos;
  170. }
  171. // Not an empty slot, let's check the probing length of the existing one.
  172. uint32_t existing_probe_len = _get_probe_length(pos, map_data[pos].hash, capacity);
  173. if (existing_probe_len < distance) {
  174. SWAP(c_data, map_data[pos]);
  175. distance = existing_probe_len;
  176. }
  177. pos = (pos + 1) & capacity;
  178. distance++;
  179. }
  180. }
  181. void _resize_and_rehash(uint32_t p_new_capacity) {
  182. uint32_t real_old_capacity = capacity + 1;
  183. // Capacity can't be 0 and must be 2^n - 1.
  184. capacity = MAX(4u, p_new_capacity);
  185. uint32_t real_capacity = next_power_of_2(capacity);
  186. capacity = real_capacity - 1;
  187. HashMapData *old_map_data = map_data;
  188. map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static_zeroed(sizeof(HashMapData) * real_capacity));
  189. elements = reinterpret_cast<MapKeyValue *>(Memory::realloc_static(elements, sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
  190. if (num_elements != 0) {
  191. for (uint32_t i = 0; i < real_old_capacity; i++) {
  192. HashMapData data = old_map_data[i];
  193. if (data.data != EMPTY_HASH) {
  194. _insert_with_hash(data.hash, data.hash_to_key);
  195. }
  196. }
  197. }
  198. Memory::free_static(old_map_data);
  199. }
  200. int32_t _insert_element(const TKey &p_key, const TValue &p_value, uint32_t p_hash) {
  201. if (unlikely(elements == nullptr)) {
  202. // Allocate on demand to save memory.
  203. uint32_t real_capacity = capacity + 1;
  204. map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static_zeroed(sizeof(HashMapData) * real_capacity));
  205. elements = reinterpret_cast<MapKeyValue *>(Memory::alloc_static(sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
  206. }
  207. if (unlikely(num_elements > _get_resize_count(capacity))) {
  208. _resize_and_rehash(capacity * 2);
  209. }
  210. memnew_placement(&elements[num_elements], MapKeyValue(p_key, p_value));
  211. _insert_with_hash(p_hash, num_elements);
  212. num_elements++;
  213. return num_elements - 1;
  214. }
  215. void _init_from(const AHashMap &p_other) {
  216. capacity = p_other.capacity;
  217. uint32_t real_capacity = capacity + 1;
  218. num_elements = p_other.num_elements;
  219. if (p_other.num_elements == 0) {
  220. return;
  221. }
  222. map_data = reinterpret_cast<HashMapData *>(Memory::alloc_static(sizeof(HashMapData) * real_capacity));
  223. elements = reinterpret_cast<MapKeyValue *>(Memory::alloc_static(sizeof(MapKeyValue) * (_get_resize_count(capacity) + 1)));
  224. if constexpr (std::is_trivially_copyable_v<TKey> && std::is_trivially_copyable_v<TValue>) {
  225. void *destination = elements;
  226. const void *source = p_other.elements;
  227. memcpy(destination, source, sizeof(MapKeyValue) * num_elements);
  228. } else {
  229. for (uint32_t i = 0; i < num_elements; i++) {
  230. memnew_placement(&elements[i], MapKeyValue(p_other.elements[i]));
  231. }
  232. }
  233. memcpy(map_data, p_other.map_data, sizeof(HashMapData) * real_capacity);
  234. }
  235. public:
  236. /* Standard Godot Container API */
  237. _FORCE_INLINE_ uint32_t get_capacity() const { return capacity + 1; }
  238. _FORCE_INLINE_ uint32_t size() const { return num_elements; }
  239. _FORCE_INLINE_ bool is_empty() const {
  240. return num_elements == 0;
  241. }
  242. void clear() {
  243. if (elements == nullptr || num_elements == 0) {
  244. return;
  245. }
  246. memset(map_data, EMPTY_HASH, (capacity + 1) * sizeof(HashMapData));
  247. if constexpr (!(std::is_trivially_destructible_v<TKey> && std::is_trivially_destructible_v<TValue>)) {
  248. for (uint32_t i = 0; i < num_elements; i++) {
  249. elements[i].key.~TKey();
  250. elements[i].value.~TValue();
  251. }
  252. }
  253. num_elements = 0;
  254. }
  255. TValue &get(const TKey &p_key) {
  256. uint32_t pos = 0;
  257. uint32_t hash_pos = 0;
  258. bool exists = _lookup_pos(p_key, pos, hash_pos);
  259. CRASH_COND_MSG(!exists, "AHashMap key not found.");
  260. return elements[pos].value;
  261. }
  262. const TValue &get(const TKey &p_key) const {
  263. uint32_t pos = 0;
  264. uint32_t hash_pos = 0;
  265. bool exists = _lookup_pos(p_key, pos, hash_pos);
  266. CRASH_COND_MSG(!exists, "AHashMap key not found.");
  267. return elements[pos].value;
  268. }
  269. const TValue *getptr(const TKey &p_key) const {
  270. uint32_t pos = 0;
  271. uint32_t hash_pos = 0;
  272. bool exists = _lookup_pos(p_key, pos, hash_pos);
  273. if (exists) {
  274. return &elements[pos].value;
  275. }
  276. return nullptr;
  277. }
  278. TValue *getptr(const TKey &p_key) {
  279. uint32_t pos = 0;
  280. uint32_t hash_pos = 0;
  281. bool exists = _lookup_pos(p_key, pos, hash_pos);
  282. if (exists) {
  283. return &elements[pos].value;
  284. }
  285. return nullptr;
  286. }
  287. bool has(const TKey &p_key) const {
  288. uint32_t _pos = 0;
  289. uint32_t h_pos = 0;
  290. return _lookup_pos(p_key, _pos, h_pos);
  291. }
  292. bool erase(const TKey &p_key) {
  293. uint32_t pos = 0;
  294. uint32_t element_pos = 0;
  295. bool exists = _lookup_pos(p_key, element_pos, pos);
  296. if (!exists) {
  297. return false;
  298. }
  299. uint32_t next_pos = (pos + 1) & capacity;
  300. while (map_data[next_pos].hash != EMPTY_HASH && _get_probe_length(next_pos, map_data[next_pos].hash, capacity) != 0) {
  301. SWAP(map_data[next_pos], map_data[pos]);
  302. pos = next_pos;
  303. next_pos = (next_pos + 1) & capacity;
  304. }
  305. map_data[pos].data = EMPTY_HASH;
  306. elements[element_pos].key.~TKey();
  307. elements[element_pos].value.~TValue();
  308. num_elements--;
  309. if (element_pos < num_elements) {
  310. void *destination = &elements[element_pos];
  311. const void *source = &elements[num_elements];
  312. memcpy(destination, source, sizeof(MapKeyValue));
  313. uint32_t h_pos = 0;
  314. _lookup_pos(elements[num_elements].key, pos, h_pos);
  315. map_data[h_pos].hash_to_key = element_pos;
  316. }
  317. return true;
  318. }
  319. // Replace the key of an entry in-place, without invalidating iterators or changing the entries position during iteration.
  320. // p_old_key must exist in the map and p_new_key must not, unless it is equal to p_old_key.
  321. bool replace_key(const TKey &p_old_key, const TKey &p_new_key) {
  322. if (p_old_key == p_new_key) {
  323. return true;
  324. }
  325. uint32_t pos = 0;
  326. uint32_t element_pos = 0;
  327. ERR_FAIL_COND_V(_lookup_pos(p_new_key, element_pos, pos), false);
  328. ERR_FAIL_COND_V(!_lookup_pos(p_old_key, element_pos, pos), false);
  329. MapKeyValue &element = elements[element_pos];
  330. const_cast<TKey &>(element.key) = p_new_key;
  331. uint32_t next_pos = (pos + 1) & capacity;
  332. while (map_data[next_pos].hash != EMPTY_HASH && _get_probe_length(next_pos, map_data[next_pos].hash, capacity) != 0) {
  333. SWAP(map_data[next_pos], map_data[pos]);
  334. pos = next_pos;
  335. next_pos = (next_pos + 1) & capacity;
  336. }
  337. map_data[pos].data = EMPTY_HASH;
  338. uint32_t hash = _hash(p_new_key);
  339. _insert_with_hash(hash, element_pos);
  340. return true;
  341. }
  342. // Reserves space for a number of elements, useful to avoid many resizes and rehashes.
  343. // If adding a known (possibly large) number of elements at once, must be larger than old capacity.
  344. void reserve(uint32_t p_new_capacity) {
  345. ERR_FAIL_COND_MSG(p_new_capacity < size(), "reserve() called with a capacity smaller than the current size. This is likely a mistake.");
  346. if (elements == nullptr) {
  347. capacity = MAX(4u, p_new_capacity);
  348. capacity = next_power_of_2(capacity) - 1;
  349. return; // Unallocated yet.
  350. }
  351. if (p_new_capacity <= get_capacity()) {
  352. return;
  353. }
  354. _resize_and_rehash(p_new_capacity);
  355. }
  356. /** Iterator API **/
  357. struct ConstIterator {
  358. _FORCE_INLINE_ const MapKeyValue &operator*() const {
  359. return *pair;
  360. }
  361. _FORCE_INLINE_ const MapKeyValue *operator->() const {
  362. return pair;
  363. }
  364. _FORCE_INLINE_ ConstIterator &operator++() {
  365. pair++;
  366. return *this;
  367. }
  368. _FORCE_INLINE_ ConstIterator &operator--() {
  369. pair--;
  370. if (pair < begin) {
  371. pair = end;
  372. }
  373. return *this;
  374. }
  375. _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return pair == b.pair; }
  376. _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return pair != b.pair; }
  377. _FORCE_INLINE_ explicit operator bool() const {
  378. return pair != end;
  379. }
  380. _FORCE_INLINE_ ConstIterator(MapKeyValue *p_key, MapKeyValue *p_begin, MapKeyValue *p_end) {
  381. pair = p_key;
  382. begin = p_begin;
  383. end = p_end;
  384. }
  385. _FORCE_INLINE_ ConstIterator() {}
  386. _FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) {
  387. pair = p_it.pair;
  388. begin = p_it.begin;
  389. end = p_it.end;
  390. }
  391. _FORCE_INLINE_ void operator=(const ConstIterator &p_it) {
  392. pair = p_it.pair;
  393. begin = p_it.begin;
  394. end = p_it.end;
  395. }
  396. private:
  397. MapKeyValue *pair = nullptr;
  398. MapKeyValue *begin = nullptr;
  399. MapKeyValue *end = nullptr;
  400. };
  401. struct Iterator {
  402. _FORCE_INLINE_ MapKeyValue &operator*() const {
  403. return *pair;
  404. }
  405. _FORCE_INLINE_ MapKeyValue *operator->() const {
  406. return pair;
  407. }
  408. _FORCE_INLINE_ Iterator &operator++() {
  409. pair++;
  410. return *this;
  411. }
  412. _FORCE_INLINE_ Iterator &operator--() {
  413. pair--;
  414. if (pair < begin) {
  415. pair = end;
  416. }
  417. return *this;
  418. }
  419. _FORCE_INLINE_ bool operator==(const Iterator &b) const { return pair == b.pair; }
  420. _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return pair != b.pair; }
  421. _FORCE_INLINE_ explicit operator bool() const {
  422. return pair != end;
  423. }
  424. _FORCE_INLINE_ Iterator(MapKeyValue *p_key, MapKeyValue *p_begin, MapKeyValue *p_end) {
  425. pair = p_key;
  426. begin = p_begin;
  427. end = p_end;
  428. }
  429. _FORCE_INLINE_ Iterator() {}
  430. _FORCE_INLINE_ Iterator(const Iterator &p_it) {
  431. pair = p_it.pair;
  432. begin = p_it.begin;
  433. end = p_it.end;
  434. }
  435. _FORCE_INLINE_ void operator=(const Iterator &p_it) {
  436. pair = p_it.pair;
  437. begin = p_it.begin;
  438. end = p_it.end;
  439. }
  440. operator ConstIterator() const {
  441. return ConstIterator(pair, begin, end);
  442. }
  443. private:
  444. MapKeyValue *pair = nullptr;
  445. MapKeyValue *begin = nullptr;
  446. MapKeyValue *end = nullptr;
  447. };
  448. _FORCE_INLINE_ Iterator begin() {
  449. return Iterator(elements, elements, elements + num_elements);
  450. }
  451. _FORCE_INLINE_ Iterator end() {
  452. return Iterator(elements + num_elements, elements, elements + num_elements);
  453. }
  454. _FORCE_INLINE_ Iterator last() {
  455. if (unlikely(num_elements == 0)) {
  456. return Iterator(nullptr, nullptr, nullptr);
  457. }
  458. return Iterator(elements + num_elements - 1, elements, elements + num_elements);
  459. }
  460. Iterator find(const TKey &p_key) {
  461. uint32_t pos = 0;
  462. uint32_t h_pos = 0;
  463. bool exists = _lookup_pos(p_key, pos, h_pos);
  464. if (!exists) {
  465. return end();
  466. }
  467. return Iterator(elements + pos, elements, elements + num_elements);
  468. }
  469. void remove(const Iterator &p_iter) {
  470. if (p_iter) {
  471. erase(p_iter->key);
  472. }
  473. }
  474. _FORCE_INLINE_ ConstIterator begin() const {
  475. return ConstIterator(elements, elements, elements + num_elements);
  476. }
  477. _FORCE_INLINE_ ConstIterator end() const {
  478. return ConstIterator(elements + num_elements, elements, elements + num_elements);
  479. }
  480. _FORCE_INLINE_ ConstIterator last() const {
  481. if (unlikely(num_elements == 0)) {
  482. return ConstIterator(nullptr, nullptr, nullptr);
  483. }
  484. return ConstIterator(elements + num_elements - 1, elements, elements + num_elements);
  485. }
  486. ConstIterator find(const TKey &p_key) const {
  487. uint32_t pos = 0;
  488. uint32_t h_pos = 0;
  489. bool exists = _lookup_pos(p_key, pos, h_pos);
  490. if (!exists) {
  491. return end();
  492. }
  493. return ConstIterator(elements + pos, elements, elements + num_elements);
  494. }
  495. /* Indexing */
  496. const TValue &operator[](const TKey &p_key) const {
  497. uint32_t pos = 0;
  498. uint32_t h_pos = 0;
  499. bool exists = _lookup_pos(p_key, pos, h_pos);
  500. CRASH_COND(!exists);
  501. return elements[pos].value;
  502. }
  503. TValue &operator[](const TKey &p_key) {
  504. uint32_t pos = 0;
  505. uint32_t h_pos = 0;
  506. uint32_t hash = _hash(p_key);
  507. bool exists = _lookup_pos_with_hash(p_key, pos, h_pos, hash);
  508. if (exists) {
  509. return elements[pos].value;
  510. } else {
  511. pos = _insert_element(p_key, TValue(), hash);
  512. return elements[pos].value;
  513. }
  514. }
  515. /* Insert */
  516. Iterator insert(const TKey &p_key, const TValue &p_value) {
  517. uint32_t pos = 0;
  518. uint32_t h_pos = 0;
  519. uint32_t hash = _hash(p_key);
  520. bool exists = _lookup_pos_with_hash(p_key, pos, h_pos, hash);
  521. if (!exists) {
  522. pos = _insert_element(p_key, p_value, hash);
  523. } else {
  524. elements[pos].value = p_value;
  525. }
  526. return Iterator(elements + pos, elements, elements + num_elements);
  527. }
  528. // Inserts an element without checking if it already exists.
  529. Iterator insert_new(const TKey &p_key, const TValue &p_value) {
  530. DEV_ASSERT(!has(p_key));
  531. uint32_t hash = _hash(p_key);
  532. uint32_t pos = _insert_element(p_key, p_value, hash);
  533. return Iterator(elements + pos, elements, elements + num_elements);
  534. }
  535. /* Array methods. */
  536. // Unsafe. Changing keys and going outside the bounds of an array can lead to undefined behavior.
  537. KeyValue<TKey, TValue> *get_elements_ptr() {
  538. return elements;
  539. }
  540. // Returns the element index. If not found, returns -1.
  541. int get_index(const TKey &p_key) {
  542. uint32_t pos = 0;
  543. uint32_t h_pos = 0;
  544. bool exists = _lookup_pos(p_key, pos, h_pos);
  545. if (!exists) {
  546. return -1;
  547. }
  548. return pos;
  549. }
  550. KeyValue<TKey, TValue> &get_by_index(uint32_t p_index) {
  551. CRASH_BAD_UNSIGNED_INDEX(p_index, num_elements);
  552. return elements[p_index];
  553. }
  554. bool erase_by_index(uint32_t p_index) {
  555. if (p_index >= size()) {
  556. return false;
  557. }
  558. return erase(elements[p_index].key);
  559. }
  560. /* Constructors */
  561. AHashMap(const AHashMap &p_other) {
  562. _init_from(p_other);
  563. }
  564. AHashMap(const HashMap<TKey, TValue> &p_other) {
  565. reserve(p_other.size());
  566. for (const KeyValue<TKey, TValue> &E : p_other) {
  567. uint32_t hash = _hash(E.key);
  568. _insert_element(E.key, E.value, hash);
  569. }
  570. }
  571. void operator=(const AHashMap &p_other) {
  572. if (this == &p_other) {
  573. return; // Ignore self assignment.
  574. }
  575. reset();
  576. _init_from(p_other);
  577. }
  578. void operator=(const HashMap<TKey, TValue> &p_other) {
  579. reset();
  580. reserve(p_other.size());
  581. for (const KeyValue<TKey, TValue> &E : p_other) {
  582. uint32_t hash = _hash(E.key);
  583. _insert_element(E.key, E.value, hash);
  584. }
  585. }
  586. AHashMap(uint32_t p_initial_capacity) {
  587. // Capacity can't be 0 and must be 2^n - 1.
  588. capacity = MAX(4u, p_initial_capacity);
  589. capacity = next_power_of_2(capacity) - 1;
  590. }
  591. AHashMap() :
  592. capacity(INITIAL_CAPACITY - 1) {
  593. }
  594. AHashMap(std::initializer_list<KeyValue<TKey, TValue>> p_init) {
  595. reserve(p_init.size());
  596. for (const KeyValue<TKey, TValue> &E : p_init) {
  597. insert(E.key, E.value);
  598. }
  599. }
  600. void reset() {
  601. if (elements != nullptr) {
  602. if constexpr (!(std::is_trivially_destructible_v<TKey> && std::is_trivially_destructible_v<TValue>)) {
  603. for (uint32_t i = 0; i < num_elements; i++) {
  604. elements[i].key.~TKey();
  605. elements[i].value.~TValue();
  606. }
  607. }
  608. Memory::free_static(elements);
  609. Memory::free_static(map_data);
  610. elements = nullptr;
  611. }
  612. capacity = INITIAL_CAPACITY - 1;
  613. num_elements = 0;
  614. }
  615. ~AHashMap() {
  616. reset();
  617. }
  618. };
  619. extern template class AHashMap<int, int>;
  620. extern template class AHashMap<String, int>;
  621. extern template class AHashMap<StringName, StringName>;
  622. extern template class AHashMap<StringName, Variant>;
  623. extern template class AHashMap<StringName, int>;