HashMap.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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. size_t toStringHashMap##N(const HashMap##N* m, char* buffer, size_t n, \
  48. CoreToString keyString, \
  49. CoreToString valueString);
  50. #define HASHMAP_SOURCE(K, V, N) \
  51. static size_t searchSlot##N(HashMap##N* m, K key) { \
  52. size_t rehashFactor = 2; \
  53. while(true) { \
  54. rehashHashMap##N(m, m->entries* rehashFactor + 1); \
  55. if(isInvalidKey##N(key)) { \
  56. return m->capacity - 1; \
  57. } \
  58. size_t baseHash = hash##N(key) * 514685581u; \
  59. size_t end = m->capacity - 2; \
  60. /* rehash on bad clustering */ \
  61. for(size_t i = 0; i <= 5; i++) { \
  62. size_t hash = (baseHash + i) & end; \
  63. K keyEntry = m->keys[hash]; \
  64. if(isInvalidKey##N(keyEntry) || equal##N(keyEntry, key)) { \
  65. return hash; \
  66. } \
  67. } \
  68. rehashFactor *= 2; \
  69. } \
  70. } \
  71. \
  72. void initHashMap##N(HashMap##N* m) { \
  73. m->keys = nullptr; \
  74. m->values = nullptr; \
  75. m->capacity = 0; \
  76. m->entries = 0; \
  77. } \
  78. \
  79. void destroyHashMap##N(HashMap##N* m) { \
  80. coreFree(m->keys); \
  81. coreFree(m->values); \
  82. *m = (HashMap##N){0}; \
  83. } \
  84. \
  85. void rehashHashMap##N(HashMap##N* m, size_t minCapacity) { \
  86. if(minCapacity <= m->capacity) { \
  87. return; \
  88. } \
  89. size_t l = roundUp2(coreMaxSize(minCapacity, 8lu)) + 1; \
  90. HashMap##N map; \
  91. initHashMap##N(&map); \
  92. size_t keyBytes = l * sizeof(K); \
  93. map.keys = coreAllocate(keyBytes); \
  94. memset(map.keys, 0, keyBytes); \
  95. memset(map.keys + (l - 1), 1, sizeof(K)); \
  96. map.values = coreAllocate(l * sizeof(V)); \
  97. map.capacity = l; \
  98. \
  99. size_t length = m->capacity; \
  100. if(length > 0) { \
  101. length--; \
  102. for(size_t i = 0; i < length; i++) { \
  103. K keyEntry = m->keys[i]; \
  104. if(!isInvalidKey##N(keyEntry)) { \
  105. *putHashMapKey##N(&map, keyEntry) = m->values[i]; \
  106. } \
  107. } \
  108. K keyEntry = m->keys[length]; \
  109. if(isInvalidKey##N(keyEntry)) { \
  110. *putHashMapKey##N(&map, keyEntry) = m->values[length]; \
  111. } \
  112. } \
  113. coreSwap(&map, m); \
  114. destroyHashMap##N(&map); \
  115. } \
  116. \
  117. V* putHashMapKey##N(HashMap##N* m, K key) { \
  118. size_t index = searchSlot##N(m, key); \
  119. K* keyEntry = m->keys + index; \
  120. if(equal##N(*keyEntry, key)) { \
  121. return m->values + index; \
  122. } \
  123. m->entries++; \
  124. *keyEntry = key; \
  125. return m->values + index; \
  126. } \
  127. \
  128. V* searchHashMapKey##N(const HashMap##N* m, K key) { \
  129. if(m->capacity != 0) { \
  130. if(isInvalidKey##N(key)) { \
  131. size_t i = m->capacity - 1; \
  132. return isInvalidKey##N(m->keys[i]) ? m->values + i : nullptr; \
  133. } \
  134. size_t baseHash = hash##N(key) * 514685581u; \
  135. size_t end = m->capacity - 2; \
  136. for(size_t i = 0; i <= end; i++) { \
  137. size_t hash = (baseHash + i) & end; \
  138. K keyEntry = m->keys[hash]; \
  139. if(equal##N(keyEntry, key)) { \
  140. return m->values + hash; \
  141. } else if(isInvalidKey##N(keyEntry)) { \
  142. return nullptr; \
  143. } \
  144. } \
  145. } \
  146. return nullptr; \
  147. } \
  148. \
  149. void clearHashMap##N(HashMap##N* m) { \
  150. if(m->keys == nullptr) { \
  151. return; \
  152. } \
  153. m->entries = 0; \
  154. memset(m->keys, 0, m->capacity * sizeof(K)); \
  155. memset(m->keys + (m->capacity - 1), 1, sizeof(K)); \
  156. } \
  157. \
  158. bool removeHashMapKey##N(HashMap##N* m, K key) { \
  159. /* ToDo: This is a very slow remove */ \
  160. HashMap##N n; \
  161. initHashMap##N(&n); \
  162. HashMapIterator##N i; \
  163. initHashMapIterator##N(&i, m); \
  164. bool r = false; \
  165. while(hasNextHashMapNode##N(&i)) { \
  166. HashMapNode##N* node = nextHashMapNode##N(&i); \
  167. if(!equal##N(key, *node->key)) { \
  168. *putHashMapKey##N(&n, *node->key) = *node->value; \
  169. } else { \
  170. r = true; \
  171. } \
  172. } \
  173. coreSwap(&n, m); \
  174. destroyHashMap##N(&n); \
  175. return r; \
  176. } \
  177. \
  178. void initHashMapIterator##N(HashMapIterator##N* mi, const HashMap##N* m) { \
  179. mi->key = m->keys; \
  180. mi->endKey = mi->key + m->capacity; \
  181. mi->value = m->values; \
  182. mi->endValue = mi->value + m->capacity; \
  183. mi->map = m; \
  184. } \
  185. \
  186. bool hasNextHashMapNode##N(HashMapIterator##N* mi) { \
  187. while(mi->key != mi->endKey) { \
  188. K* nextKey = mi->key + 1; \
  189. if(isInvalidKey##N(*mi->key) == (nextKey == mi->endKey)) { \
  190. break; \
  191. } \
  192. mi->key = nextKey; \
  193. mi->value++; \
  194. } \
  195. return mi->key != mi->endKey; \
  196. } \
  197. \
  198. HashMapNode##N* nextHashMapNode##N(HashMapIterator##N* mi) { \
  199. mi->node.key = mi->key; \
  200. mi->node.value = mi->value; \
  201. mi->key++; \
  202. mi->value++; \
  203. return &mi->node; \
  204. } \
  205. \
  206. size_t toStringHashMap##N(const HashMap##N* m, char* buffer, size_t n, \
  207. CoreToString keyString, \
  208. CoreToString valueString) { \
  209. size_t w = 0; \
  210. coreStringAdd(&w, &buffer, &n, coreToString(buffer, n, "[")); \
  211. bool notFirst = false; \
  212. HashMapIterator##N i; \
  213. initHashMapIterator##N(&i, m); \
  214. while(hasNextHashMapNode##N(&i)) { \
  215. HashMapNode##N* node = nextHashMapNode##N(&i); \
  216. if(notFirst) { \
  217. coreStringAdd(&w, &buffer, &n, coreToString(buffer, n, ", ")); \
  218. } \
  219. notFirst = true; \
  220. coreStringAdd(&w, &buffer, &n, keyString(node->key, buffer, n)); \
  221. coreStringAdd(&w, &buffer, &n, coreToString(buffer, n, " = ")); \
  222. coreStringAdd(&w, &buffer, &n, \
  223. valueString(node->value, buffer, n)); \
  224. } \
  225. stringAdd(&w, &buffer, &n, coreToString(buffer, n, "]")); \
  226. return w; \
  227. }
  228. #endif