HashMap.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. static void* searchValue(const CoreHashMap* m, const void* key) {
  42. if(m->capacity != 0) {
  43. if(isInvalidKey(m, key)) {
  44. size_t i = m->capacity - 1;
  45. return isInvalidKey(m, getKey(m, i)) ? getValue(m, i) : nullptr;
  46. }
  47. size_t baseHash = m->hasher(key, m->keySize) * 514685581u;
  48. size_t end = m->capacity - 2;
  49. for(size_t i = 0; i <= end; i++) {
  50. size_t hash = (baseHash + i) & end;
  51. void* keyEntry = getKey(m, hash);
  52. if(m->equal(keyEntry, key, m->keySize)) {
  53. return getValue(m, hash);
  54. } else if(isInvalidKey(m, keyEntry)) {
  55. return nullptr;
  56. }
  57. }
  58. }
  59. return nullptr;
  60. }
  61. static size_t roundUp2(size_t n) {
  62. size_t w = 1;
  63. while(w < n) {
  64. w *= 2;
  65. }
  66. return w;
  67. }
  68. void coreDestroyHashMap(CoreHashMap* m) {
  69. coreFree(m->keys);
  70. coreFree(m->values);
  71. *m = (CoreHashMap){0};
  72. }
  73. void coreRehashHashMap(CoreHashMap* m, size_t minCapacity) {
  74. if(minCapacity <= m->capacity) {
  75. return;
  76. }
  77. size_t l = roundUp2(coreMaxSize(minCapacity, 8lu)) + 1;
  78. CoreHashMap map =
  79. CORE_HASH_MAP(m->keySize, m->valueSize, m->hasher, m->equal);
  80. size_t keyBytes = l * m->keySize;
  81. map.keys = coreAllocate(l * m->keySize);
  82. memset(map.keys, 0, keyBytes);
  83. memset(getKey(&map, l - 1), 1, m->keySize);
  84. map.values = coreAllocate(l * m->valueSize);
  85. map.capacity = l;
  86. size_t length = m->capacity;
  87. if(length > 0) {
  88. length--;
  89. for(size_t i = 0; i < length; i++) {
  90. void* keyEntry = getKey(m, i);
  91. if(!isInvalidKey(m, keyEntry)) {
  92. coreHashMapPutPointer(&map, keyEntry, getValue(m, i));
  93. }
  94. }
  95. void* keyEntry = getKey(m, length);
  96. if(isInvalidKey(m, keyEntry)) {
  97. coreHashMapPutPointer(&map, keyEntry, getValue(m, length));
  98. }
  99. }
  100. coreSwapHashMap(&map, m);
  101. coreDestroyHashMap(&map);
  102. }
  103. void* coreHashMapPutPointer(CoreHashMap* m, const void* key,
  104. const void* value) {
  105. size_t index = searchSlot(m, key);
  106. void* keyEntry = getKey(m, index);
  107. if(m->equal(keyEntry, key, m->keySize)) {
  108. void* v = getValue(m, index);
  109. memcpy(v, value, m->valueSize);
  110. return v;
  111. }
  112. void* v = getValue(m, index);
  113. memcpy(v, value, m->valueSize);
  114. m->entries++;
  115. memcpy(keyEntry, key, m->keySize);
  116. return v;
  117. }
  118. void* coreHashMapSearchPointer(CoreHashMap* m, const void* key) {
  119. return searchValue(m, key);
  120. }
  121. const void* coreHashMapSearchPointerC(const CoreHashMap* m, const void* key) {
  122. return searchValue(m, key);
  123. }
  124. bool coreHashMapContainsPointer(const CoreHashMap* m, const void* key) {
  125. return coreHashMapSearchPointerC(m, key) != nullptr;
  126. }
  127. void coreClearHashMap(CoreHashMap* m) {
  128. if(m->keys == nullptr) {
  129. return;
  130. }
  131. m->entries = 0;
  132. memset(m->keys, 0, m->capacity * m->keySize);
  133. memset(getKey(m, m->capacity - 1), 1, m->keySize);
  134. }
  135. size_t coreToStringHashMap(const CoreHashMap* m, char* buffer, size_t n,
  136. CoreToString keyString, CoreToString valueString) {
  137. size_t w = 0;
  138. coreStringAddI(&w, &buffer, &n, snprintf(buffer, n, "["));
  139. char* end = getKey(m, m->capacity);
  140. char* key = m->keys;
  141. char* value = m->values;
  142. bool notFirst = false;
  143. while(key != end) {
  144. if(isInvalidKey(m, key) == (key + m->keySize == end)) {
  145. if(notFirst) {
  146. coreStringAddI(&w, &buffer, &n, snprintf(buffer, n, ", "));
  147. }
  148. notFirst = true;
  149. coreStringAdd(&w, &buffer, &n, keyString(key, buffer, n));
  150. coreStringAddI(&w, &buffer, &n, snprintf(buffer, n, " = "));
  151. coreStringAdd(&w, &buffer, &n, valueString(value, buffer, n));
  152. }
  153. key += m->keySize;
  154. value += m->valueSize;
  155. }
  156. coreStringAddI(&w, &buffer, &n, snprintf(buffer, n, "]"));
  157. return w;
  158. }
  159. void coreSwapHashMap(CoreHashMap* a, CoreHashMap* b) {
  160. CoreHashMap tmp = *a;
  161. *a = *b;
  162. *b = tmp;
  163. }
  164. size_t coreHashString(const void* key, size_t n) {
  165. if(n != sizeof(char*)) {
  166. return 0;
  167. }
  168. const char* s = *(const char* const*)key;
  169. size_t h = 0;
  170. while(*s != '\0') {
  171. h = 2120251889lu * h + (size_t)(*(s++));
  172. }
  173. return h;
  174. }
  175. size_t coreHash(const void* key, size_t n) {
  176. size_t h = 0;
  177. if(n <= sizeof(size_t)) {
  178. memcpy(&h, key, n);
  179. return h;
  180. }
  181. const char* cKey = key;
  182. while(n > 0) {
  183. size_t m = 0;
  184. if(n >= sizeof(size_t)) {
  185. memcpy(&m, cKey, sizeof(size_t));
  186. cKey += sizeof(size_t);
  187. n -= sizeof(size_t);
  188. } else {
  189. memcpy(&m, cKey, n);
  190. cKey += n;
  191. n = 0;
  192. }
  193. h ^= m;
  194. }
  195. return h;
  196. }
  197. bool coreEqual(const void* keyA, const void* keyB, size_t n) {
  198. return memcmp(keyA, keyB, n) == 0;
  199. }
  200. CoreHashMapNode* coreHashMapNext(CoreHashMapIterator* mi) {
  201. const CoreHashMap* m = mi->map;
  202. mi->index++;
  203. size_t end = m->capacity - 1;
  204. while(mi->index < m->capacity) {
  205. void* key = getKey(m, mi->index);
  206. if(isInvalidKey(m, key) == (mi->index == end)) {
  207. mi->node.key = key;
  208. mi->node.value = getValue(m, mi->index);
  209. return &mi->node;
  210. }
  211. mi->index++;
  212. }
  213. return nullptr;
  214. }