string_map.cpp 9.3 KB

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