Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

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