25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

183 satır
6.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. #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(int 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. int current_capacity;
  17. int 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(int 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. 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_type)key)) != -1;
  77. }
  78. key_type search_key_to_object(value_type v) {
  79. for (int 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. for (int i = 0; i < current_capacity; ++i) {
  89. if (data[i].original && !data[i].deleted)
  90. ret.append(data[i].original);
  91. }
  92. return ret;
  93. }
  94. value_type get_object(key_type key) {
  95. int index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key));
  96. if (index != -1) {
  97. return data[index].object;
  98. }
  99. return 0;
  100. }
  101. void delete_object(key_type key) {
  102. int index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key));
  103. if (index != -1) {
  104. data[index].deleted = true;
  105. }
  106. }
  107. void set_object(key_type key, value_type obj, u64 hash_val) {
  108. int index = hash_val % current_capacity;
  109. /* if we the desired cell is just empty, write to it and done :) */
  110. if (!data[index].original) {
  111. /* insert new cell into desired slot */
  112. ++cell_count;
  113. } else {
  114. if (hm_objects_match(key, data[index].original)) {
  115. /* overwrite object with same key, dont increment cell */
  116. /* count */
  117. } else {
  118. /* collision, check resize */
  119. ++cell_count;
  120. if ((cell_count*1.0f / current_capacity) > 0.666f) {
  121. auto old_data = data;
  122. data = (HM_Cell*)calloc(current_capacity*4, sizeof(HM_Cell));
  123. cell_count = 0;
  124. current_capacity *= 4;
  125. /* insert all old items again */
  126. for (int i = 0; i < current_capacity/4; ++i) {
  127. auto cell = old_data[i];
  128. if (cell.original) {
  129. set_object(cell.original, cell.object, cell.hash);
  130. }
  131. }
  132. free(old_data);
  133. index = hash_val % current_capacity;
  134. }
  135. /* search for empty slot for new cell starting at desired index; */
  136. /* preventing gotos using lambdas! */
  137. [&]{
  138. for (int i = index; i < current_capacity; ++i) {
  139. if (!data[i].original ||
  140. hm_objects_match(data[i].original, key))
  141. {
  142. index = i;
  143. return;
  144. }
  145. }
  146. for (int i = 0; i < index; ++i) {
  147. if (!data[i].original ||
  148. hm_objects_match(data[i].original, key))
  149. {
  150. index = i;
  151. return;
  152. }
  153. }
  154. }();
  155. }
  156. }
  157. data[index].deleted = false;
  158. data[index].original = key;
  159. data[index].hash = hash_val;
  160. data[index].object = obj;
  161. }
  162. void set_object(key_type key, value_type obj) {
  163. u64 hash_val = hm_hash((key_type)key);
  164. set_object(key, obj, hash_val);
  165. }
  166. };