string_map.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. GB_STATIC_ASSERT(sizeof(MapIndex) == sizeof(u32));
  2. struct StringHashKey {
  3. u32 hash;
  4. String string;
  5. operator String() const noexcept {
  6. return this->string;
  7. }
  8. operator String const &() const noexcept {
  9. return this->string;
  10. }
  11. };
  12. gb_internal gb_inline u32 string_hash(String const &s) {
  13. return fnv32a(s.text, s.len) & 0x7fffffff;
  14. }
  15. gb_internal gb_inline StringHashKey string_hash_string(String const &s) {
  16. StringHashKey hash_key = {};
  17. hash_key.hash = string_hash(s);
  18. hash_key.string = s;
  19. return hash_key;
  20. }
  21. template <typename T>
  22. struct StringMapEntry {
  23. String key;
  24. u32 hash;
  25. MapIndex next;
  26. T value;
  27. };
  28. template <typename T>
  29. struct StringMap {
  30. MapIndex * hashes;
  31. usize hashes_count;
  32. StringMapEntry<T> *entries;
  33. u32 count;
  34. u32 entries_capacity;
  35. };
  36. template <typename T> gb_internal void string_map_init (StringMap<T> *h, usize capacity = 16);
  37. template <typename T> gb_internal void string_map_destroy (StringMap<T> *h);
  38. template <typename T> gb_internal T * string_map_get (StringMap<T> *h, char const *key);
  39. template <typename T> gb_internal T * string_map_get (StringMap<T> *h, String const &key);
  40. template <typename T> gb_internal T * string_map_get (StringMap<T> *h, StringHashKey const &key);
  41. template <typename T> gb_internal T & string_map_must_get(StringMap<T> *h, char const *key);
  42. template <typename T> gb_internal T & string_map_must_get(StringMap<T> *h, String const &key);
  43. template <typename T> gb_internal T & string_map_must_get(StringMap<T> *h, StringHashKey const &key);
  44. template <typename T> gb_internal void string_map_set (StringMap<T> *h, char const *key, T const &value);
  45. template <typename T> gb_internal void string_map_set (StringMap<T> *h, String const &key, T const &value);
  46. template <typename T> gb_internal void string_map_set (StringMap<T> *h, StringHashKey const &key, T const &value);
  47. // template <typename T> gb_internal void string_map_remove (StringMap<T> *h, StringHashKey const &key);
  48. template <typename T> gb_internal void string_map_clear (StringMap<T> *h);
  49. template <typename T> gb_internal void string_map_grow (StringMap<T> *h);
  50. template <typename T> gb_internal void string_map_reserve (StringMap<T> *h, usize new_count);
  51. gb_internal gbAllocator string_map_allocator(void) {
  52. return heap_allocator();
  53. }
  54. template <typename T>
  55. gb_internal gb_inline void string_map_init(StringMap<T> *h, usize capacity) {
  56. capacity = next_pow2_isize(capacity);
  57. string_map_reserve(h, capacity);
  58. }
  59. template <typename T>
  60. gb_internal gb_inline void string_map_destroy(StringMap<T> *h) {
  61. gb_free(string_map_allocator(), h->hashes);
  62. gb_free(string_map_allocator(), h->entries);
  63. }
  64. template <typename T>
  65. gb_internal void string_map__resize_hashes(StringMap<T> *h, usize count) {
  66. h->hashes_count = cast(u32)resize_array_raw(&h->hashes, string_map_allocator(), h->hashes_count, count);
  67. }
  68. template <typename T>
  69. gb_internal void string_map__reserve_entries(StringMap<T> *h, usize capacity) {
  70. h->entries_capacity = cast(u32)resize_array_raw(&h->entries, string_map_allocator(), h->entries_capacity, capacity);
  71. }
  72. template <typename T>
  73. gb_internal MapIndex string_map__add_entry(StringMap<T> *h, u32 hash, String const &key) {
  74. StringMapEntry<T> e = {};
  75. e.key = key;
  76. e.hash = hash;
  77. e.next = MAP_SENTINEL;
  78. string_map__reserve_entries(h, h->count+1);
  79. h->entries[h->count++] = e;
  80. return cast(MapIndex)(h->count-1);
  81. }
  82. template <typename T>
  83. gb_internal MapFindResult string_map__find(StringMap<T> *h, u32 hash, String const &key) {
  84. MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
  85. if (h->hashes_count != 0) {
  86. fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
  87. fr.entry_index = h->hashes[fr.hash_index];
  88. while (fr.entry_index != MAP_SENTINEL) {
  89. auto *entry = &h->entries[fr.entry_index];
  90. if (entry->hash == hash && entry->key == key) {
  91. return fr;
  92. }
  93. fr.entry_prev = fr.entry_index;
  94. fr.entry_index = entry->next;
  95. }
  96. }
  97. return fr;
  98. }
  99. template <typename T>
  100. gb_internal MapFindResult string_map__find_from_entry(StringMap<T> *h, StringMapEntry<T> *e) {
  101. MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
  102. if (h->hashes_count != 0) {
  103. fr.hash_index = cast(MapIndex)(e->hash & (h->hashes_count-1));
  104. fr.entry_index = h->hashes[fr.hash_index];
  105. while (fr.entry_index != MAP_SENTINEL) {
  106. auto *entry = &h->entries[fr.entry_index];
  107. if (entry == e) {
  108. return fr;
  109. }
  110. fr.entry_prev = fr.entry_index;
  111. fr.entry_index = entry->next;
  112. }
  113. }
  114. return fr;
  115. }
  116. template <typename T>
  117. gb_internal b32 string_map__full(StringMap<T> *h) {
  118. return 0.75f * h->hashes_count <= h->count;
  119. }
  120. template <typename T>
  121. gb_inline void string_map_grow(StringMap<T> *h) {
  122. isize new_count = gb_max(h->hashes_count<<1, 16);
  123. string_map_reserve(h, new_count);
  124. }
  125. template <typename T>
  126. gb_internal void string_map_reset_entries(StringMap<T> *h) {
  127. for (u32 i = 0; i < h->hashes_count; i++) {
  128. h->hashes[i] = MAP_SENTINEL;
  129. }
  130. for (isize i = 0; i < h->count; i++) {
  131. MapFindResult fr;
  132. StringMapEntry<T> *e = &h->entries[i];
  133. e->next = MAP_SENTINEL;
  134. fr = string_map__find_from_entry(h, e);
  135. if (fr.entry_prev == MAP_SENTINEL) {
  136. h->hashes[fr.hash_index] = cast(MapIndex)i;
  137. } else {
  138. h->entries[fr.entry_prev].next = cast(MapIndex)i;
  139. }
  140. }
  141. }
  142. template <typename T>
  143. gb_internal void string_map_reserve(StringMap<T> *h, usize cap) {
  144. if (h->count*2 < h->hashes_count) {
  145. return;
  146. }
  147. string_map__reserve_entries(h, cap);
  148. string_map__resize_hashes(h, cap*2);
  149. string_map_reset_entries(h);
  150. }
  151. template <typename T>
  152. gb_internal T *string_map_get(StringMap<T> *h, u32 hash, String const &key) {
  153. MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
  154. if (h->hashes_count != 0) {
  155. fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
  156. fr.entry_index = h->hashes[fr.hash_index];
  157. while (fr.entry_index != MAP_SENTINEL) {
  158. auto *entry = &h->entries[fr.entry_index];
  159. if (entry->hash == hash && entry->key == key) {
  160. return &entry->value;
  161. }
  162. fr.entry_prev = fr.entry_index;
  163. fr.entry_index = entry->next;
  164. }
  165. }
  166. return nullptr;
  167. }
  168. template <typename T>
  169. gb_internal gb_inline T *string_map_get(StringMap<T> *h, StringHashKey const &key) {
  170. return string_map_get(h, key.hash, key.string);
  171. }
  172. template <typename T>
  173. gb_internal gb_inline T *string_map_get(StringMap<T> *h, String const &key) {
  174. return string_map_get(h, string_hash(key), key);
  175. }
  176. template <typename T>
  177. gb_internal gb_inline T *string_map_get(StringMap<T> *h, char const *key) {
  178. String k = make_string_c(key);
  179. return string_map_get(h, string_hash(k), k);
  180. }
  181. template <typename T>
  182. gb_internal T &string_map_must_get(StringMap<T> *h, u32 hash, String const &key) {
  183. isize index = string_map__find(h, hash, key).entry_index;
  184. GB_ASSERT(index != MAP_SENTINEL);
  185. return h->entries[index].value;
  186. }
  187. template <typename T>
  188. gb_internal T &string_map_must_get(StringMap<T> *h, StringHashKey const &key) {
  189. return string_map_must_get(h, key.hash, key.string);
  190. }
  191. template <typename T>
  192. gb_internal gb_inline T &string_map_must_get(StringMap<T> *h, String const &key) {
  193. return string_map_must_get(h, string_hash(key), key);
  194. }
  195. template <typename T>
  196. gb_internal gb_inline T &string_map_must_get(StringMap<T> *h, char const *key) {
  197. String k = make_string_c(key);
  198. return string_map_must_get(h, string_hash(k), k);
  199. }
  200. template <typename T>
  201. gb_internal void string_map_set(StringMap<T> *h, u32 hash, String const &key, T const &value) {
  202. MapIndex index;
  203. MapFindResult fr;
  204. if (h->hashes_count == 0) {
  205. string_map_grow(h);
  206. }
  207. fr = string_map__find(h, hash, key);
  208. if (fr.entry_index != MAP_SENTINEL) {
  209. index = fr.entry_index;
  210. } else {
  211. index = string_map__add_entry(h, hash, key);
  212. if (fr.entry_prev != MAP_SENTINEL) {
  213. h->entries[fr.entry_prev].next = index;
  214. } else {
  215. h->hashes[fr.hash_index] = index;
  216. }
  217. }
  218. h->entries[index].value = value;
  219. if (string_map__full(h)) {
  220. string_map_grow(h);
  221. }
  222. }
  223. template <typename T>
  224. gb_internal gb_inline void string_map_set(StringMap<T> *h, String const &key, T const &value) {
  225. string_map_set(h, string_hash_string(key), value);
  226. }
  227. template <typename T>
  228. gb_internal gb_inline void string_map_set(StringMap<T> *h, char const *key, T const &value) {
  229. string_map_set(h, string_hash_string(make_string_c(key)), value);
  230. }
  231. template <typename T>
  232. gb_internal gb_inline void string_map_set(StringMap<T> *h, StringHashKey const &key, T const &value) {
  233. string_map_set(h, key.hash, key.string, value);
  234. }
  235. // template <typename T>
  236. // gb_internal void string_map__erase(StringMap<T> *h, MapFindResult const &fr) {
  237. // MapFindResult last;
  238. // if (fr.entry_prev == MAP_SENTINEL) {
  239. // h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
  240. // } else {
  241. // h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next;
  242. // }
  243. // if (fr.entry_index == h->count-1) {
  244. // array_pop(&h->entries);
  245. // return;
  246. // }
  247. // h->entries[fr.entry_index] = h->entries[h->count-1];
  248. // last = string_map__find(h, h->entries[fr.entry_index].key);
  249. // if (last.entry_prev != MAP_SENTINEL) {
  250. // h->entries[last.entry_prev].next = fr.entry_index;
  251. // } else {
  252. // h->hashes[last.hash_index] = fr.entry_index;
  253. // }
  254. // }
  255. // template <typename T>
  256. // gb_internal void string_map_remove(StringMap<T> *h, StringHashKey const &key) {
  257. // MapFindResult fr = string_map__find(h, key);
  258. // if (fr.entry_index != MAP_SENTINEL) {
  259. // string_map__erase(h, fr);
  260. // }
  261. // }
  262. template <typename T>
  263. gb_internal gb_inline void string_map_clear(StringMap<T> *h) {
  264. h->count = 0;
  265. for (u32 i = 0; i < h->hashes_count; i++) {
  266. h->hashes[i] = MAP_SENTINEL;
  267. }
  268. }
  269. template <typename T>
  270. gb_internal StringMapEntry<T> *begin(StringMap<T> &m) noexcept {
  271. return m.entries;
  272. }
  273. template <typename T>
  274. gb_internal StringMapEntry<T> const *begin(StringMap<T> const &m) noexcept {
  275. return m.entries;
  276. }
  277. template <typename T>
  278. gb_internal StringMapEntry<T> *end(StringMap<T> &m) {
  279. return m.entries + m.count;
  280. }
  281. template <typename T>
  282. gb_internal StringMapEntry<T> const *end(StringMap<T> const &m) noexcept {
  283. return m.entries + m.count;
  284. }