Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

252 řádky
8.4 KiB

  1. #pragma once
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include "types.hpp"
  6. #include "arraylist.hpp"
  7. u32 hm_hash(const char* str) {
  8. u32 value = str[0] << 7;
  9. s32 i = 0;
  10. while (str[i]) {
  11. value = (10000003 * value) ^ str[i++];
  12. }
  13. return value ^ i;
  14. }
  15. u32 hm_hash(char* str) {
  16. u32 value = str[0] << 7;
  17. s32 i = 0;
  18. while (str[i]) {
  19. value = (10000003 * value) ^ str[i++];
  20. }
  21. return value ^ i;
  22. }
  23. u32 hm_hash(void* ptr) {
  24. return ((u64)ptr * 2654435761) % 4294967296;
  25. }
  26. inline bool hm_objects_match(const char* a, const char* b) {
  27. return strcmp(a, b) == 0;
  28. }
  29. inline bool hm_objects_match(char* a, char* b) {
  30. return strcmp(a, b) == 0;
  31. }
  32. inline bool hm_objects_match(void* a, void* b) {
  33. return a == b;
  34. }
  35. #define for_hash_map(hm) \
  36. if (decltype((hm).data[0].original) key = 0); else \
  37. if (decltype((hm).data[0].object) value = 0); else \
  38. for(u32 index = 0; index < (hm).current_capacity; ++index) \
  39. if (!((!(hm).data[index].deleted) && \
  40. (key = (hm).data[index].original) && \
  41. (value = (hm).data[index].object))); else
  42. template <typename key_type, typename value_type>
  43. struct Hash_Map {
  44. u32 current_capacity;
  45. u32 cell_count;
  46. struct HM_Cell {
  47. key_type original;
  48. u64 hash;
  49. enum struct Occupancy : u8 {
  50. Avaliable = 0,
  51. Occupied,
  52. Deleted
  53. } occupancy;
  54. value_type object;
  55. }* data;
  56. void alloc(u32 initial_capacity = 8) {
  57. current_capacity = initial_capacity;
  58. cell_count = 0;
  59. data = (HM_Cell*)calloc(initial_capacity, sizeof(HM_Cell));
  60. }
  61. void dealloc() {
  62. free(data);
  63. data = nullptr;
  64. }
  65. s32 get_index_of_living_cell_if_it_exists(key_type key, u64 hash_val) {
  66. // s32 index = hash_val & (current_capacity - 1);
  67. s32 index = hash_val % current_capacity;
  68. HM_Cell cell = data[index];
  69. /* test if there is or was something there */
  70. if (cell.occupancy != HM_Cell::Occupancy::Avaliable) {
  71. /* check if objects match */
  72. if (hm_objects_match(key, cell.original)) {
  73. /* we found it, now check it it is deleted: */
  74. if (cell.occupancy == HM_Cell::Occupancy::Deleted) {
  75. /* we found it but it was deleted, we */
  76. /* dont have to check for collisions then */
  77. return -1;
  78. } else {
  79. /* we found it and it is not deleted */
  80. return index;
  81. }
  82. } else {
  83. /* objects dont match, this means we have */
  84. /* a collision. We just search forward */
  85. for (u32 i = 0; i < current_capacity; ++i) {
  86. u32 new_idx = (i + index) % current_capacity;
  87. cell = data[new_idx];
  88. /* If we find a avaliable cell while looking */
  89. /* forward, the object is not in the hm */
  90. if (cell.occupancy == HM_Cell::Occupancy::Avaliable)
  91. return -1;
  92. /* If the objects don't match, keep looking */
  93. if (!hm_objects_match(key, cell.original))
  94. continue;
  95. /* TODO(Felix): If the objects do match, */
  96. /* and it is deleted, we should return -1? */
  97. if (cell.occupancy == HM_Cell::Occupancy::Deleted)
  98. continue;
  99. return new_idx;
  100. }
  101. /* not or only deleted cells found */
  102. return -1;
  103. }
  104. } else {
  105. /* no cell exists at this index so the item was never in the */
  106. /* hashmap. Either it would be there or be ther and 'deleted' */
  107. /* or another item would be there and therefore a collistion */
  108. /* would exist */
  109. return -1;
  110. }
  111. }
  112. bool key_exists(key_type key) {
  113. return get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key)) != -1;
  114. }
  115. key_type search_key_to_object(value_type v) {
  116. for (u32 i = 0; i < current_capacity; ++i) {
  117. if (data[i].object == v &&
  118. data[i].occupancy == HM_Cell::Occupancy::Occupied)
  119. {
  120. return data[i].original;
  121. }
  122. }
  123. return nullptr;
  124. }
  125. Array_List<key_type> get_all_keys() {
  126. Array_List<key_type> ret;
  127. ret.alloc();
  128. // QUESTION(Felix): Does it make sense to
  129. // ret.reserve(this->cell_count)?
  130. for (u32 i = 0; i < current_capacity; ++i) {
  131. if (data[i].occupancy == HM_Cell::Occupancy::Occupied)
  132. ret.append(data[i].original);
  133. }
  134. return ret;
  135. }
  136. value_type get_object(key_type key, u64 hash_val) {
  137. s32 index = get_index_of_living_cell_if_it_exists(key, hash_val);
  138. if (index != -1) {
  139. return data[index].object;
  140. }
  141. return 0;
  142. }
  143. value_type get_object(key_type key) {
  144. return get_object(key, hm_hash((key_type)key));
  145. }
  146. value_type* get_object_ptr(key_type key, u64 hash_val) {
  147. s32 index = get_index_of_living_cell_if_it_exists(key, hash_val);
  148. if (index != -1) {
  149. return &(data[index].object);
  150. }
  151. return 0;
  152. }
  153. value_type* get_object_ptr(key_type key) {
  154. return get_object_ptr(key, hm_hash((key_type)key));
  155. }
  156. void delete_object(key_type key) {
  157. s32 index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key));
  158. if (index != -1) {
  159. data[index].occupancy = HM_Cell::Occupancy::Deleted;
  160. }
  161. }
  162. void set_object(key_type key, value_type obj, u64 hash_val) {
  163. u32 index = hash_val % current_capacity;
  164. /* if we the desired cell is avaliable, write to it and done :) */
  165. if (data[index].occupancy == HM_Cell::Occupancy::Avaliable) {
  166. /* insert new cell into desired slot */
  167. ++cell_count;
  168. } else {
  169. if (hm_objects_match(key, data[index].original)) {
  170. /* overwrite object with same key, dont increment cell */
  171. /* count */
  172. } else {
  173. /* collision, check resize */
  174. if ((cell_count*1.0f / current_capacity) > 0.666f) {
  175. auto old_data = data;
  176. data = (HM_Cell*)calloc(current_capacity*4, sizeof(HM_Cell));
  177. cell_count = 0;
  178. current_capacity *= 4;
  179. /* insert all old items again */
  180. for (u32 i = 0; i < current_capacity/4; ++i) {
  181. auto cell = old_data[i];
  182. if (cell.occupancy == HM_Cell::Occupancy::Occupied) {
  183. set_object(cell.original, cell.object, cell.hash);
  184. }
  185. }
  186. free(old_data);
  187. index = hash_val % current_capacity;
  188. }
  189. ++cell_count;
  190. /* search for empty slot for new cell starting at desired index; */
  191. /* preventing gotos using lambdas! */
  192. [&]{
  193. for (u32 i = index; i < current_capacity; ++i) {
  194. if (data[i].occupancy == HM_Cell::Occupancy::Avaliable ||
  195. hm_objects_match(data[i].original, key))
  196. {
  197. index = i;
  198. return;
  199. }
  200. }
  201. for (u32 i = 0; i < index; ++i) {
  202. if (data[i].occupancy == HM_Cell::Occupancy::Avaliable ||
  203. hm_objects_match(data[i].original, key))
  204. {
  205. index = i;
  206. return;
  207. }
  208. }
  209. }();
  210. }
  211. }
  212. data[index].occupancy = HM_Cell::Occupancy::Occupied;
  213. data[index].original = key;
  214. data[index].hash = hash_val;
  215. data[index].object = obj;
  216. }
  217. void set_object(key_type key, value_type obj) {
  218. u64 hash_val = hm_hash((key_type)key);
  219. set_object(key, obj, hash_val);
  220. }
  221. };