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.
 
 
 
 

185 line
6.5 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. #define for_hash_map(hm) \
  8. if (decltype((hm).data[0].original) key = 0); else \
  9. if (decltype((hm).data[0].object) value = 0); else \
  10. for(u32 index = 0; index < (hm).current_capacity; ++index) \
  11. if (!((!(hm).data[index].deleted) && \
  12. (key = (hm).data[index].original) && \
  13. (value = (hm).data[index].object))); else
  14. template <typename key_type, typename value_type>
  15. struct Hash_Map {
  16. u32 current_capacity;
  17. u32 cell_count;
  18. struct HM_Cell {
  19. key_type original;
  20. u64 hash;
  21. bool deleted;
  22. value_type object;
  23. }* data;
  24. void alloc(u32 initial_capacity = 8) {
  25. current_capacity = initial_capacity;
  26. cell_count = 0;
  27. data = (HM_Cell*)calloc(initial_capacity, sizeof(HM_Cell));
  28. }
  29. void dealloc() {
  30. free(data);
  31. data = nullptr;
  32. }
  33. s32 get_index_of_living_cell_if_it_exists(key_type key, u64 hash_val) {
  34. // s32 index = hash_val & (current_capacity - 1);
  35. s32 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 (u32 i = 0; i < current_capacity; ++i) {
  54. u32 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_type)key)) != -1;
  77. }
  78. key_type search_key_to_object(value_type v) {
  79. for (u32 i = 0; i < current_capacity; ++i) {
  80. if (data[i].object == v && !data[i].deleted)
  81. return data[i].original;
  82. }
  83. return nullptr;
  84. }
  85. Array_List<key_type> get_all_keys() {
  86. Array_List<key_type> ret;
  87. ret.alloc();
  88. // QUESTION(Felix): Does it make sense to
  89. // ret.reserve(this->cell_count)?
  90. for (u32 i = 0; i < current_capacity; ++i) {
  91. if (data[i].original && !data[i].deleted)
  92. ret.append(data[i].original);
  93. }
  94. return ret;
  95. }
  96. value_type get_object(key_type key) {
  97. s32 index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key));
  98. if (index != -1) {
  99. return data[index].object;
  100. }
  101. return 0;
  102. }
  103. void delete_object(key_type key) {
  104. s32 index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key));
  105. if (index != -1) {
  106. data[index].deleted = true;
  107. }
  108. }
  109. void set_object(key_type key, value_type obj, u64 hash_val) {
  110. u32 index = hash_val % current_capacity;
  111. /* if we the desired cell is just empty, write to it and done :) */
  112. if (!data[index].original) {
  113. /* insert new cell into desired slot */
  114. ++cell_count;
  115. } else {
  116. if (hm_objects_match(key, data[index].original)) {
  117. /* overwrite object with same key, dont increment cell */
  118. /* count */
  119. } else {
  120. /* collision, check resize */
  121. ++cell_count;
  122. if ((cell_count*1.0f / current_capacity) > 0.666f) {
  123. auto old_data = data;
  124. data = (HM_Cell*)calloc(current_capacity*4, sizeof(HM_Cell));
  125. cell_count = 0;
  126. current_capacity *= 4;
  127. /* insert all old items again */
  128. for (u32 i = 0; i < current_capacity/4; ++i) {
  129. auto cell = old_data[i];
  130. if (cell.original) {
  131. set_object(cell.original, cell.object, cell.hash);
  132. }
  133. }
  134. free(old_data);
  135. index = hash_val % current_capacity;
  136. }
  137. /* search for empty slot for new cell starting at desired index; */
  138. /* preventing gotos using lambdas! */
  139. [&]{
  140. for (u32 i = index; i < current_capacity; ++i) {
  141. if (!data[i].original ||
  142. hm_objects_match(data[i].original, key))
  143. {
  144. index = i;
  145. return;
  146. }
  147. }
  148. for (u32 i = 0; i < index; ++i) {
  149. if (!data[i].original ||
  150. hm_objects_match(data[i].original, key))
  151. {
  152. index = i;
  153. return;
  154. }
  155. }
  156. }();
  157. }
  158. }
  159. data[index].deleted = false;
  160. data[index].original = key;
  161. data[index].hash = hash_val;
  162. data[index].object = obj;
  163. }
  164. void set_object(key_type key, value_type obj) {
  165. u64 hash_val = hm_hash((key_type)key);
  166. set_object(key, obj, hash_val);
  167. }
  168. };