HashMap.h 17 KB

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