You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

311 regels
17 KiB

  1. #pragma once
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include "types.hpp"
  6. // inline void print_hm(StringHashMap* hm) {
  7. // for_str_hash_map(hm) {
  8. // printf("index: %d desired-index: %llu key: %s hash: %llu value: %llu\n", i, (hm->data[i].hash % hm->current_capacity), (char*)key, hm->data[i].hash, (unsigned long long)value);
  9. // }
  10. // }
  11. #define __for_hm_generator(key_type, value_type, hm) \
  12. if (key_type key = 0); else \
  13. if (value_type value = 0); else \
  14. for(int index = 0; index < hm.current_capacity; ++index) \
  15. if (!((!hm.data[index].deleted) && \
  16. (key = hm.data[index].original) && \
  17. (value = hm.data[index].object))); else
  18. template <typename key_type, typename value_type>
  19. struct Hash_Map {
  20. int current_capacity;
  21. int cell_count;
  22. struct HM_Cell {
  23. key_type original;
  24. u64 hash;
  25. bool deleted;
  26. value_type object;
  27. }* data;
  28. Hash_Map(int initial_capacity = 8) {
  29. current_capacity = initial_capacity;
  30. cell_count = 0;
  31. data = (HM_Cell*)calloc(initial_capacity, sizeof(HM_Cell));
  32. }
  33. int get_index_of_living_cell_if_it_exists(key_type key, u64 hash_val) {
  34. // int index = hash_val & (current_capacity - 1);
  35. int index = hash_val % current_capacity;
  36. HM_Cell cell = data[index];
  37. /* test if cell exists at that index */
  38. if (cell.original) {
  39. /* check if strings match */
  40. if (hm_objects_match(key, cell.original)) {
  41. /* we found it, now check it it is deleted: */
  42. if (cell.deleted) {
  43. /* we found it but it was deleted, we */
  44. /* dont have to check for collisions then */
  45. return -1;
  46. } else {
  47. /* we found it and it is not deleted */
  48. return index;
  49. }
  50. } else {
  51. /* strings dont match, this means we have */
  52. /* a collision. We just search forward */
  53. for (int i = 0; i < current_capacity; ++i) {
  54. int new_idx = (i + index) % current_capacity;
  55. cell = data[new_idx];
  56. if (!cell.original)
  57. return -1;
  58. if (!hm_objects_match(key, cell.original))
  59. continue;
  60. if (cell.deleted)
  61. continue;
  62. return new_idx;
  63. }
  64. /* not or only deleted cells found */
  65. return -1;
  66. }
  67. } else {
  68. /* no cell exists at this index so the item was never in the */
  69. /* hashmap. Either it would be there or be ther and 'deleted' */
  70. /* or another item would be there and therefore a collistion */
  71. /* would exist */
  72. return -1;
  73. }
  74. }
  75. bool key_exists(key_type key) {
  76. return get_index_of_living_cell_if_it_exists(key, hm_hash(key)) != -1;
  77. }
  78. value_type get_object(key_type key) {
  79. int index = get_index_of_living_cell_if_it_exists(key, hm_hash(key));
  80. if (index != -1) {
  81. return data[index].object;
  82. }
  83. return 0;
  84. }
  85. void delete_object(key_type key) {
  86. int index = get_index_of_living_cell_if_it_exists(key, hm_hash(key));
  87. if (index != -1) {
  88. data[index].deleted = true;
  89. }
  90. }
  91. void set_object(key_type key, value_type obj) {
  92. u64 hash_val = hm_hash(key);
  93. int index = hash_val % current_capacity;
  94. /* if we the desired cell is just empty, write to it and done :) */
  95. if (!data[index].original) {
  96. /* insert new cell into desired slot */
  97. ++cell_count;
  98. } else {
  99. if (hm_objects_match(key, data[index].original)) {
  100. /* overwrite object with same key, dont increment cell */
  101. /* count */
  102. } else {
  103. /* collision, check resize */
  104. ++cell_count;
  105. if ((cell_count*1.0f / current_capacity) > 0.666f) {
  106. auto old_data = data;
  107. data = (HM_Cell*)calloc(current_capacity*4, sizeof(HM_Cell));
  108. cell_count = 0;
  109. current_capacity *= 4;
  110. /* insert all old items again */
  111. for (int i = 0; i < current_capacity/4; ++i) {
  112. auto cell = old_data[i];
  113. if (cell.original) {
  114. set_object(cell.original, cell.object);
  115. }
  116. }
  117. free(old_data);
  118. index = hash_val % current_capacity;
  119. }
  120. /* search for empty slot for new cell starting at desired index; */
  121. /* preventing gotos using lambdas! */
  122. [&](){
  123. for (int i = index; i < current_capacity; ++i) {
  124. if (!data[i].original ||
  125. hm_objects_match(data[i].original, key))
  126. {
  127. index = i;
  128. return;
  129. }
  130. }
  131. for (int i = 0; i < index; ++i) {
  132. if (!data[i].original ||
  133. hm_objects_match(data[i].original, key))
  134. {
  135. index = i;
  136. return;
  137. }
  138. }
  139. }();
  140. }
  141. }
  142. data[index].deleted = false;
  143. data[index].original = key;
  144. data[index].hash = hash_val;
  145. data[index].object = obj;
  146. }
  147. };
  148. // #define define_hash_map(type, name) \
  149. // bool hm_objects_match(type,type); \
  150. // u32 hm_hash(type); \
  151. // \
  152. // struct name##_Hash_Map_Cell { \
  153. // type original; \
  154. // u64 hash; \
  155. // bool deleted; \
  156. // void* object; \
  157. // }; \
  158. // \
  159. // struct name##_Hash_Map { \
  160. // int current_capacity; \
  161. // int cell_count; \
  162. // name##_Hash_Map_Cell* data; \
  163. // }; \
  164. // \
  165. // name##_Hash_Map* create_##name##_hashmap(int initial_capacity=8) { \
  166. // name##_Hash_Map* hm = new name##_Hash_Map; \
  167. // hm->current_capacity = initial_capacity; \
  168. // hm->cell_count = 0; \
  169. // /* set all data to nullptr */ \
  170. // hm->data = (name##_Hash_Map_Cell*)calloc(initial_capacity, sizeof(name##_Hash_Map_Cell)); \
  171. // /* printf("check: %s\n", hm->data[6].original_string); */ \
  172. // return hm; \
  173. // } \
  174. // \
  175. // int hm_get_index_of_living_cell_if_it_exists(name##_Hash_Map* hm, type key, u64 hash_val) { \
  176. // int index = hash_val % hm->current_capacity; \
  177. // name##_Hash_Map_Cell cell = hm->data[index]; \
  178. // /* test if cell exists at that index */ \
  179. // if (cell.original) { \
  180. // /* check if strings match */ \
  181. // if (hm_objects_match(key, cell.original)) { \
  182. // /* we found it, now check it it is deleted: */ \
  183. // if (cell.deleted) { \
  184. // /* we found it but it was deleted, we */ \
  185. // /* dont have to check for collisions then */ \
  186. // return -1; \
  187. // } else { \
  188. // /* we found it and it is not deleted */ \
  189. // return index; \
  190. // } \
  191. // } else { \
  192. // /* strings dont match, this means we have */ \
  193. // /* a collision. We just search forward */ \
  194. // for (int i = 0; i < hm->current_capacity; ++i) { \
  195. // int new_idx = (i + index) % hm->current_capacity; \
  196. // cell = hm->data[new_idx]; \
  197. // if (!cell.original) \
  198. // return -1; \
  199. // if (!hm_objects_match(key, cell.original)) \
  200. // continue; \
  201. // if (cell.deleted) \
  202. // continue; \
  203. // return new_idx; \
  204. // } \
  205. // /* not or only deleted cells found */ \
  206. // return -1; \
  207. // } \
  208. // } else { \
  209. // /* no cell exists at this index so the item was never in the */ \
  210. // /* hashmap. Either it would be there or be ther and 'deleted' */ \
  211. // /* or another item would be there and therefore a collistion */ \
  212. // /* would exist */ \
  213. // return -1; \
  214. // } \
  215. // } \
  216. // \
  217. // inline bool hm_key_exists(name##_Hash_Map* hm, type key) { \
  218. // return hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)) != -1; \
  219. // } \
  220. // \
  221. // inline void* hm_get_object(name##_Hash_Map* hm, type key) { \
  222. // int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)); \
  223. // if (index != -1) { \
  224. // return hm->data[index].object; \
  225. // } \
  226. // return nullptr; \
  227. // } \
  228. // \
  229. // inline void hm_delete_object(name##_Hash_Map* hm, type key) { \
  230. // int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)); \
  231. // if (index != -1) { \
  232. // hm->data[index].deleted = true; \
  233. // } \
  234. // } \
  235. // \
  236. // void hm_set(name##_Hash_Map* hm, type key, void* obj) { \
  237. // u64 hash_val = hm_hash(key); \
  238. // int index = hash_val % hm->current_capacity; \
  239. // \
  240. // /* if we the desired cell is just empty, write to it and done :) */ \
  241. // if (!hm->data[index].original) { \
  242. // /* insert new cell into desired slot */ \
  243. // ++hm->cell_count; \
  244. // } else { \
  245. // if (hm_objects_match(key, hm->data[index].original)) { \
  246. // /* overwrite object with same key, dont increment cell */ \
  247. // /* count */ \
  248. // } else { \
  249. // /* collision, check resize */ \
  250. // ++hm->cell_count; \
  251. // if ((hm->cell_count*1.0f / hm->current_capacity) > 0.666f) { \
  252. // auto old_data = hm->data; \
  253. // hm->data = (name##_Hash_Map_Cell*)calloc(hm->current_capacity*4, sizeof(name##_Hash_Map_Cell)); \
  254. // hm->cell_count = 0; \
  255. // hm->current_capacity *= 4; \
  256. // \
  257. // /* insert all old items again */ \
  258. // for (int i = 0; i < hm->current_capacity/4; ++i) { \
  259. // auto cell = old_data[i]; \
  260. // if (cell.original) { \
  261. // hm_set(hm, cell.original, cell.object); \
  262. // } \
  263. // } \
  264. // free(old_data); \
  265. // index = hash_val % hm->current_capacity; \
  266. // } \
  267. // /* search for empty slot for new cell starting at desired index; */ \
  268. // /* preventing gotos using lambdas! */ \
  269. // [&](){ \
  270. // for (int i = index; i < hm->current_capacity; ++i) { \
  271. // if (!hm->data[i].original || \
  272. // hm_objects_match(hm->data[i].original, key)) \
  273. // { \
  274. // index = i; \
  275. // return; \
  276. // } \
  277. // } \
  278. // for (int i = 0; i < index; ++i) { \
  279. // if (!hm->data[i].original || \
  280. // hm_objects_match(hm->data[i].original, key)) \
  281. // { \
  282. // index = i; \
  283. // return; \
  284. // } \
  285. // } \
  286. // }(); \
  287. // } \
  288. // } \
  289. // \
  290. // hm->data[index].deleted = false; \
  291. // hm->data[index].original = key; \
  292. // hm->data[index].hash = hash_val; \
  293. // hm->data[index].object = obj; \
  294. // } \