HashMap.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #include "core/HashMap.h"
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include "core/Utility.h"
  5. static bool isInvalidKey(const CoreHashMap* m, const void* key) {
  6. const char* c = key;
  7. for(size_t i = m->keySize; i > 0; i--) {
  8. if(*(c++) != 0) {
  9. return false;
  10. }
  11. }
  12. return true;
  13. }
  14. static void* getKey(const CoreHashMap* m, size_t index) {
  15. return (char*)m->keys + m->keySize * index;
  16. }
  17. static void* getValue(const CoreHashMap* m, size_t index) {
  18. return (char*)m->values + m->valueSize * index;
  19. }
  20. static size_t searchSlot(CoreHashMap* m, const void* key) {
  21. size_t rehashFactor = 2;
  22. while(true) {
  23. coreRehashHashMap(m, m->entries * rehashFactor + 1);
  24. if(isInvalidKey(m, key)) {
  25. return m->capacity - 1;
  26. }
  27. size_t baseHash = m->hasher(key, m->keySize) * 514685581u;
  28. size_t end = m->capacity - 2;
  29. // rehash on bad clustering
  30. for(size_t i = 0; i <= 5; i++) {
  31. size_t hash = (baseHash + i) & end;
  32. void* keyEntry = getKey(m, hash);
  33. if(isInvalidKey(m, keyEntry) ||
  34. m->equal(keyEntry, key, m->keySize)) {
  35. return hash;
  36. }
  37. }
  38. rehashFactor *= 2;
  39. }
  40. }
  41. #define SEARCH_VALUE(type, Type) \
  42. static void* searchValue##Type(const CoreHashMap* m, const void* rawKey) { \
  43. type key = *(const type*)rawKey; \
  44. if(m->capacity != 0) { \
  45. if(key == 0) { \
  46. size_t i = m->capacity - 1; \
  47. return ((type*)m->keys)[i] == 0 ? getValue(m, i) : nullptr; \
  48. } \
  49. size_t baseHash = ((size_t)key) * 514685581u; \
  50. size_t end = m->capacity - 2; \
  51. for(size_t i = 0; i <= end; i++) { \
  52. size_t hash = (baseHash + i) & end; \
  53. type keyEntry = *(type*)getKey(m, hash); \
  54. if(keyEntry == key) { \
  55. return getValue(m, hash); \
  56. } else if(keyEntry == 0) { \
  57. return nullptr; \
  58. } \
  59. } \
  60. } \
  61. return nullptr; \
  62. }
  63. SEARCH_VALUE(u32, U32)
  64. SEARCH_VALUE(u64, U64)
  65. static void* searchValue(const CoreHashMap* m, const void* key) {
  66. if(m->capacity != 0) {
  67. if(isInvalidKey(m, key)) {
  68. size_t i = m->capacity - 1;
  69. return isInvalidKey(m, getKey(m, i)) ? getValue(m, i) : nullptr;
  70. }
  71. size_t baseHash = m->hasher(key, m->keySize) * 514685581u;
  72. size_t end = m->capacity - 2;
  73. for(size_t i = 0; i <= end; i++) {
  74. size_t hash = (baseHash + i) & end;
  75. void* keyEntry = getKey(m, hash);
  76. if(m->equal(keyEntry, key, m->keySize)) {
  77. return getValue(m, hash);
  78. } else if(isInvalidKey(m, keyEntry)) {
  79. return nullptr;
  80. }
  81. }
  82. }
  83. return nullptr;
  84. }
  85. static size_t roundUp2(size_t n) {
  86. size_t w = 1;
  87. while(w < n) {
  88. w *= 2;
  89. }
  90. return w;
  91. }
  92. CoreHashMap coreInitHashMap(size_t keySize, size_t valueSize, CoreHasher hasher,
  93. CoreEqual equal) {
  94. CoreSearchValue search = searchValue;
  95. if(hasher == coreHash && equal == coreEqual) {
  96. switch(keySize) {
  97. case sizeof(u32): search = searchValueU32; break;
  98. case sizeof(u64): search = searchValueU64; break;
  99. }
  100. }
  101. return (CoreHashMap){nullptr, nullptr, keySize, valueSize, 0,
  102. 0, hasher, equal, search};
  103. }
  104. void coreDestroyHashMap(CoreHashMap* m) {
  105. coreFree(m->keys);
  106. coreFree(m->values);
  107. *m = (CoreHashMap){0};
  108. }
  109. void coreRehashHashMap(CoreHashMap* m, size_t minCapacity) {
  110. if(minCapacity <= m->capacity) {
  111. return;
  112. }
  113. size_t l = roundUp2(coreMaxSize(minCapacity, 8lu)) + 1;
  114. CoreHashMap map =
  115. CORE_HASH_MAP(m->keySize, m->valueSize, m->hasher, m->equal);
  116. size_t keyBytes = l * m->keySize;
  117. map.keys = coreAllocate(keyBytes);
  118. memset(map.keys, 0, keyBytes);
  119. memset(getKey(&map, l - 1), 1, m->keySize);
  120. map.values = coreAllocate(l * m->valueSize);
  121. map.capacity = l;
  122. size_t length = m->capacity;
  123. if(length > 0) {
  124. length--;
  125. for(size_t i = 0; i < length; i++) {
  126. void* keyEntry = getKey(m, i);
  127. if(!isInvalidKey(m, keyEntry)) {
  128. coreHashMapPutPointer(&map, keyEntry, getValue(m, i));
  129. }
  130. }
  131. void* keyEntry = getKey(m, length);
  132. if(isInvalidKey(m, keyEntry)) {
  133. coreHashMapPutPointer(&map, keyEntry, getValue(m, length));
  134. }
  135. }
  136. coreSwapHashMap(&map, m);
  137. coreDestroyHashMap(&map);
  138. }
  139. void* coreHashMapPutPointer(CoreHashMap* m, const void* key,
  140. const void* value) {
  141. size_t index = searchSlot(m, key);
  142. void* keyEntry = getKey(m, index);
  143. if(m->equal(keyEntry, key, m->keySize)) {
  144. void* v = getValue(m, index);
  145. memcpy(v, value, m->valueSize);
  146. return v;
  147. }
  148. void* v = getValue(m, index);
  149. memcpy(v, value, m->valueSize);
  150. m->entries++;
  151. memcpy(keyEntry, key, m->keySize);
  152. return v;
  153. }
  154. void* coreHashMapSearchPointer(CoreHashMap* m, const void* key) {
  155. return m->search(m, key);
  156. }
  157. const void* coreHashMapSearchPointerC(const CoreHashMap* m, const void* key) {
  158. return m->search(m, key);
  159. }
  160. bool coreHashMapContainsPointer(const CoreHashMap* m, const void* key) {
  161. return coreHashMapSearchPointerC(m, key) != nullptr;
  162. }
  163. void coreClearHashMap(CoreHashMap* m) {
  164. if(m->keys == nullptr) {
  165. return;
  166. }
  167. m->entries = 0;
  168. memset(m->keys, 0, m->capacity * m->keySize);
  169. memset(getKey(m, m->capacity - 1), 1, m->keySize);
  170. }
  171. bool coreHashMapRemovePointer(CoreHashMap* m, const void* key) {
  172. // ToDo: This is a very slow remove
  173. CoreHashMap n =
  174. CORE_HASH_MAP(m->keySize, m->valueSize, m->hasher, m->equal);
  175. CoreHashMapIterator i = CORE_HASH_MAP_ITERATOR(m);
  176. bool r = false;
  177. while(true) {
  178. CoreHashMapNode* node = coreHashMapNext(&i);
  179. if(node == nullptr) {
  180. break;
  181. }
  182. if(!m->equal(key, node->key, n.keySize)) {
  183. coreHashMapPutPointer(&n, node->key, node->value);
  184. } else {
  185. r = true;
  186. }
  187. }
  188. coreSwapHashMap(&n, m);
  189. coreDestroyHashMap(&n);
  190. return r;
  191. }
  192. size_t coreToStringHashMap(const CoreHashMap* m, char* buffer, size_t n,
  193. CoreToString keyString, CoreToString valueString) {
  194. size_t w = 0;
  195. coreStringAddI(&w, &buffer, &n, snprintf(buffer, n, "["));
  196. char* end = getKey(m, m->capacity);
  197. char* key = m->keys;
  198. char* value = m->values;
  199. bool notFirst = false;
  200. while(key != end) {
  201. if(isInvalidKey(m, key) == (key + m->keySize == end)) {
  202. if(notFirst) {
  203. coreStringAddI(&w, &buffer, &n, snprintf(buffer, n, ", "));
  204. }
  205. notFirst = true;
  206. coreStringAdd(&w, &buffer, &n, keyString(key, buffer, n));
  207. coreStringAddI(&w, &buffer, &n, snprintf(buffer, n, " = "));
  208. coreStringAdd(&w, &buffer, &n, valueString(value, buffer, n));
  209. }
  210. key += m->keySize;
  211. value += m->valueSize;
  212. }
  213. coreStringAddI(&w, &buffer, &n, snprintf(buffer, n, "]"));
  214. return w;
  215. }
  216. void coreSwapHashMap(CoreHashMap* a, CoreHashMap* b) {
  217. CoreHashMap tmp = *a;
  218. *a = *b;
  219. *b = tmp;
  220. }
  221. size_t coreHashString(const void* key, size_t n) {
  222. if(n != sizeof(char*)) {
  223. return 0;
  224. }
  225. const char* s = *(const char* const*)key;
  226. size_t h = 0;
  227. while(*s != '\0') {
  228. h = 2120251889lu * h + (size_t)(*(s++));
  229. }
  230. return h;
  231. }
  232. size_t coreHash(const void* key, size_t n) {
  233. size_t h = 0;
  234. if(n <= sizeof(size_t)) {
  235. memcpy(&h, key, n);
  236. return h;
  237. }
  238. const char* cKey = key;
  239. while(n > 0) {
  240. size_t m = 0;
  241. if(n >= sizeof(size_t)) {
  242. memcpy(&m, cKey, sizeof(size_t));
  243. cKey += sizeof(size_t);
  244. n -= sizeof(size_t);
  245. } else {
  246. memcpy(&m, cKey, n);
  247. cKey += n;
  248. n = 0;
  249. }
  250. h ^= m;
  251. }
  252. return h;
  253. }
  254. bool coreEqual(const void* keyA, const void* keyB, size_t n) {
  255. return memcmp(keyA, keyB, n) == 0;
  256. }
  257. CoreHashMapNode* coreHashMapNext(CoreHashMapIterator* mi) {
  258. const CoreHashMap* m = mi->map;
  259. mi->index++;
  260. size_t end = m->capacity - 1;
  261. while(mi->index < m->capacity) {
  262. void* key = getKey(m, mi->index);
  263. if(isInvalidKey(m, key) == (mi->index == end)) {
  264. mi->node.key = key;
  265. mi->node.value = getValue(m, mi->index);
  266. return &mi->node;
  267. }
  268. mi->index++;
  269. }
  270. return nullptr;
  271. }