HashMap.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #ifndef CORE_HASHMAP_H
  2. #define CORE_HASHMAP_H
  3. #include "core/ToString.h"
  4. #include "core/Types.h"
  5. #include "core/Utility.h"
  6. size_t hashString(const char* key);
  7. size_t roundUp2(size_t n);
  8. #define isInvalidKeyInt(key) ((key) == 0)
  9. #define equalInt(a, b) ((a) == (b))
  10. #define hashInt(key) ((size_t)key)
  11. #define isInvalidKeySize(key) ((key) == 0)
  12. #define equalSize(a, b) ((a) == (b))
  13. #define hashSize(key) (key)
  14. #define HASHMAP(K, V, N) \
  15. typedef struct { \
  16. K* keys; \
  17. V* values; \
  18. size_t capacity; \
  19. size_t entries; \
  20. } HashMap##N; \
  21. \
  22. void initHashMap##N(HashMap##N* m); \
  23. void destroyHashMap##N(HashMap##N* m); \
  24. void rehashHashMap##N(HashMap##N* m, size_t minCapacity); \
  25. V* putHashMapKey##N(HashMap##N* m, K key); \
  26. V* searchHashMapKey##N(const HashMap##N* m, K key); \
  27. void clearHashMap##N(HashMap##N* m); \
  28. bool removeHashMapKey##N(HashMap##N* m, K key); \
  29. \
  30. typedef struct { \
  31. const K* key; \
  32. V* value; \
  33. } HashMapNode##N; \
  34. \
  35. typedef struct { \
  36. K* key; \
  37. K* endKey; \
  38. V* value; \
  39. V* endValue; \
  40. const HashMap##N* map; \
  41. HashMapNode##N node; \
  42. } HashMapIterator##N; \
  43. \
  44. void initHashMapIterator##N(HashMapIterator##N* mi, const HashMap##N* m); \
  45. bool hasNextHashMapNode##N(HashMapIterator##N* mi); \
  46. HashMapNode##N* nextHashMapNode##N(HashMapIterator##N* mi); \
  47. typedef size_t (*ToStringKey##N)(K const* const data, char* buffer, \
  48. size_t n); \
  49. typedef size_t (*ToStringValue##N)(V const* const data, char* buffer, \
  50. size_t n); \
  51. size_t toStringHashMap##N(const HashMap##N* m, char* buffer, size_t n, \
  52. ToStringKey##N keyString, \
  53. ToStringValue##N valueString);
  54. #define HASHMAP_SOURCE(K, V, N) \
  55. static size_t searchSlot##N(HashMap##N* m, K key) { \
  56. size_t rehashFactor = 2; \
  57. while(true) { \
  58. rehashHashMap##N(m, m->entries* rehashFactor + 1); \
  59. if(isInvalidKey##N(key)) { \
  60. return m->capacity - 1; \
  61. } \
  62. size_t baseHash = hash##N(key) * 514685581u; \
  63. size_t end = m->capacity - 2; \
  64. /* rehash on bad clustering */ \
  65. for(size_t i = 0; i <= 5; i++) { \
  66. size_t hash = (baseHash + i) & end; \
  67. K keyEntry = m->keys[hash]; \
  68. if(isInvalidKey##N(keyEntry) || equal##N(keyEntry, key)) { \
  69. return hash; \
  70. } \
  71. } \
  72. rehashFactor *= 2; \
  73. } \
  74. } \
  75. \
  76. void initHashMap##N(HashMap##N* m) { \
  77. m->keys = nullptr; \
  78. m->values = nullptr; \
  79. m->capacity = 0; \
  80. m->entries = 0; \
  81. } \
  82. \
  83. void destroyHashMap##N(HashMap##N* m) { \
  84. coreFree(m->keys); \
  85. coreFree(m->values); \
  86. *m = (HashMap##N){0}; \
  87. } \
  88. \
  89. void rehashHashMap##N(HashMap##N* m, size_t minCapacity) { \
  90. if(minCapacity <= m->capacity) { \
  91. return; \
  92. } \
  93. size_t l = roundUp2(maxSize(minCapacity, 8lu)) + 1; \
  94. HashMap##N map; \
  95. initHashMap##N(&map); \
  96. size_t keyBytes = l * sizeof(K); \
  97. map.keys = coreAllocate(keyBytes); \
  98. memset(map.keys, 0, keyBytes); \
  99. memset(map.keys + (l - 1), 1, sizeof(K)); \
  100. map.values = coreAllocate(l * sizeof(V)); \
  101. map.capacity = l; \
  102. \
  103. size_t length = m->capacity; \
  104. if(length > 0) { \
  105. length--; \
  106. for(size_t i = 0; i < length; i++) { \
  107. K keyEntry = m->keys[i]; \
  108. if(!isInvalidKey##N(keyEntry)) { \
  109. *putHashMapKey##N(&map, keyEntry) = m->values[i]; \
  110. } \
  111. } \
  112. K keyEntry = m->keys[length]; \
  113. if(isInvalidKey##N(keyEntry)) { \
  114. *putHashMapKey##N(&map, keyEntry) = m->values[length]; \
  115. } \
  116. } \
  117. swap(&map, m); \
  118. destroyHashMap##N(&map); \
  119. } \
  120. \
  121. V* putHashMapKey##N(HashMap##N* m, K key) { \
  122. size_t index = searchSlot##N(m, key); \
  123. K* keyEntry = m->keys + index; \
  124. if(equal##N(*keyEntry, key)) { \
  125. return m->values + index; \
  126. } \
  127. m->entries++; \
  128. *keyEntry = key; \
  129. return m->values + index; \
  130. } \
  131. \
  132. V* searchHashMapKey##N(const HashMap##N* m, K key) { \
  133. if(m->capacity != 0) { \
  134. if(isInvalidKey##N(key)) { \
  135. size_t i = m->capacity - 1; \
  136. return isInvalidKey##N(m->keys[i]) ? m->values + i : nullptr; \
  137. } \
  138. size_t baseHash = hash##N(key) * 514685581u; \
  139. size_t end = m->capacity - 2; \
  140. for(size_t i = 0; i <= end; i++) { \
  141. size_t hash = (baseHash + i) & end; \
  142. K keyEntry = m->keys[hash]; \
  143. if(equal##N(keyEntry, key)) { \
  144. return m->values + hash; \
  145. } else if(isInvalidKey##N(keyEntry)) { \
  146. return nullptr; \
  147. } \
  148. } \
  149. } \
  150. return nullptr; \
  151. } \
  152. \
  153. void clearHashMap##N(HashMap##N* m) { \
  154. if(m->keys == nullptr) { \
  155. return; \
  156. } \
  157. m->entries = 0; \
  158. memset(m->keys, 0, m->capacity * sizeof(K)); \
  159. memset(m->keys + (m->capacity - 1), 1, sizeof(K)); \
  160. } \
  161. \
  162. bool removeHashMapKey##N(HashMap##N* m, K key) { \
  163. /* ToDo: This is a very slow remove */ \
  164. HashMap##N n; \
  165. initHashMap##N(&n); \
  166. HashMapIterator##N i; \
  167. initHashMapIterator##N(&i, m); \
  168. bool r = false; \
  169. while(hasNextHashMapNode##N(&i)) { \
  170. HashMapNode##N* node = nextHashMapNode##N(&i); \
  171. if(!equal##N(key, *node->key)) { \
  172. *putHashMapKey##N(&n, *node->key) = *node->value; \
  173. } else { \
  174. r = true; \
  175. } \
  176. } \
  177. swap(&n, m); \
  178. destroyHashMap##N(&n); \
  179. return r; \
  180. } \
  181. \
  182. void initHashMapIterator##N(HashMapIterator##N* mi, const HashMap##N* m) { \
  183. mi->key = m->keys; \
  184. mi->endKey = mi->key + m->capacity; \
  185. mi->value = m->values; \
  186. mi->endValue = mi->value + m->capacity; \
  187. mi->map = m; \
  188. } \
  189. \
  190. bool hasNextHashMapNode##N(HashMapIterator##N* mi) { \
  191. while(mi->key != mi->endKey) { \
  192. K* nextKey = mi->key + 1; \
  193. if(isInvalidKey##N(*mi->key) == (nextKey == mi->endKey)) { \
  194. break; \
  195. } \
  196. mi->key = nextKey; \
  197. mi->value++; \
  198. } \
  199. return mi->key != mi->endKey; \
  200. } \
  201. \
  202. HashMapNode##N* nextHashMapNode##N(HashMapIterator##N* mi) { \
  203. mi->node.key = mi->key; \
  204. mi->node.value = mi->value; \
  205. mi->key++; \
  206. mi->value++; \
  207. return &mi->node; \
  208. } \
  209. \
  210. size_t toStringHashMap##N(const HashMap##N* m, char* buffer, size_t n, \
  211. ToStringKey##N keyString, \
  212. ToStringValue##N valueString) { \
  213. size_t w = 0; \
  214. stringAdd(&w, &buffer, &n, toString(buffer, n, "[")); \
  215. bool notFirst = false; \
  216. HashMapIterator##N i; \
  217. initHashMapIterator##N(&i, m); \
  218. while(hasNextHashMapNode##N(&i)) { \
  219. HashMapNode##N* node = nextHashMapNode##N(&i); \
  220. if(notFirst) { \
  221. stringAdd(&w, &buffer, &n, toString(buffer, n, ", ")); \
  222. } \
  223. notFirst = true; \
  224. stringAdd(&w, &buffer, &n, keyString(node->key, buffer, n)); \
  225. stringAdd(&w, &buffer, &n, toString(buffer, n, " = ")); \
  226. stringAdd(&w, &buffer, &n, valueString(node->value, buffer, n)); \
  227. } \
  228. stringAdd(&w, &buffer, &n, toString(buffer, n, "]")); \
  229. return w; \
  230. }
  231. #endif