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.
 
 
 
 

167 regels
5.9 KiB

  1. #pragma once
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include "types.hpp"
  6. #define for_hash_map(hm) \
  7. if (decltype((hm).data[0].original) key = 0); else \
  8. if (decltype((hm).data[0].object) value = 0); else \
  9. for(int index = 0; index < (hm).current_capacity; ++index) \
  10. if (!((!(hm).data[index].deleted) && \
  11. (key = (hm).data[index].original) && \
  12. (value = (hm).data[index].object))); else
  13. template <typename key_type, typename value_type>
  14. struct Hash_Map {
  15. int current_capacity;
  16. int cell_count;
  17. struct HM_Cell {
  18. key_type original;
  19. u64 hash;
  20. bool deleted;
  21. value_type object;
  22. }* data;
  23. Hash_Map(int initial_capacity = 8) {
  24. current_capacity = initial_capacity;
  25. cell_count = 0;
  26. data = (HM_Cell*)calloc(initial_capacity, sizeof(HM_Cell));
  27. }
  28. ~Hash_Map() {
  29. if (data) {
  30. free(data);
  31. data = nullptr;
  32. }
  33. }
  34. int get_index_of_living_cell_if_it_exists(key_type key, u64 hash_val) {
  35. // int index = hash_val & (current_capacity - 1);
  36. int index = hash_val % current_capacity;
  37. HM_Cell cell = data[index];
  38. /* test if cell exists at that index */
  39. if (cell.original) {
  40. /* check if strings match */
  41. if (hm_objects_match(key, cell.original)) {
  42. /* we found it, now check it it is deleted: */
  43. if (cell.deleted) {
  44. /* we found it but it was deleted, we */
  45. /* dont have to check for collisions then */
  46. return -1;
  47. } else {
  48. /* we found it and it is not deleted */
  49. return index;
  50. }
  51. } else {
  52. /* strings dont match, this means we have */
  53. /* a collision. We just search forward */
  54. for (int i = 0; i < current_capacity; ++i) {
  55. int new_idx = (i + index) % current_capacity;
  56. cell = data[new_idx];
  57. if (!cell.original)
  58. return -1;
  59. if (!hm_objects_match(key, cell.original))
  60. continue;
  61. if (cell.deleted)
  62. continue;
  63. return new_idx;
  64. }
  65. /* not or only deleted cells found */
  66. return -1;
  67. }
  68. } else {
  69. /* no cell exists at this index so the item was never in the */
  70. /* hashmap. Either it would be there or be ther and 'deleted' */
  71. /* or another item would be there and therefore a collistion */
  72. /* would exist */
  73. return -1;
  74. }
  75. }
  76. bool key_exists(key_type key) {
  77. return get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key)) != -1;
  78. }
  79. value_type get_object(key_type key) {
  80. int index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key));
  81. if (index != -1) {
  82. return data[index].object;
  83. }
  84. return 0;
  85. }
  86. void delete_object(key_type key) {
  87. int index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key));
  88. if (index != -1) {
  89. data[index].deleted = true;
  90. }
  91. }
  92. void set_object(key_type key, value_type obj, u64 hash_val) {
  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, cell.hash);
  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. void set_object(key_type key, value_type obj) {
  148. u64 hash_val = hm_hash((key_type)key);
  149. set_object(key, obj, hash_val);
  150. }
  151. };