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.
 
 
 
 

177 satır
5.7 KiB

  1. #pragma once
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include "types.hpp"
  6. #define for_str_hash_map(hm) \
  7. if (char* key = nullptr); else \
  8. if (void* value = nullptr); else \
  9. for(int i = 0; i < hm->current_capacity; ++i) \
  10. if (!((key = hm->data[i].original_string) && \
  11. (value = hm->data[i].object))); else
  12. struct StringHashMapCell {
  13. char* original_string;
  14. void* object;
  15. u64 hash;
  16. bool deleted;
  17. };
  18. struct StringHashMap {
  19. int current_capacity;
  20. int cell_count;
  21. StringHashMapCell* data;
  22. };
  23. inline void print_hm(StringHashMap* hm) {
  24. for_str_hash_map(hm) {
  25. printf("index: %d key: %s value: %llu\n", i, key, (unsigned long long)value);
  26. }
  27. }
  28. inline bool strings_match(char* a, char* b) {
  29. return strcmp(a, b) == 0;
  30. }
  31. u32 hash(char* str) {
  32. u32 value = str[0] << 7;
  33. int i = 0;
  34. while (str[i]) {
  35. value = (10000003 * value) ^ str[i++];
  36. }
  37. return value ^ i;
  38. }
  39. StringHashMap* create_hashmap(int initial_capacity = 8) {
  40. StringHashMap* hm = new StringHashMap;
  41. hm->current_capacity = initial_capacity;
  42. hm->cell_count = 0;
  43. // set all data to nullptr
  44. hm->data = (StringHashMapCell *)calloc(initial_capacity, sizeof(StringHashMapCell));
  45. // printf("check: %s\n", hm->data[6].original_string);
  46. return hm;
  47. }
  48. int hm_get_index_of_living_cell_if_it_exists(StringHashMap* hm, char* key, u64 hash_val) {
  49. int index = hash_val % hm->current_capacity;
  50. StringHashMapCell cell = hm->data[index];
  51. // test if cell exists at that index
  52. if (cell.original_string) {
  53. // check if strings match
  54. if (strings_match(key, cell.original_string)) {
  55. // we found it, now check it it is deleted:
  56. if (cell.deleted) {
  57. // we found it but it was deleted, we dont have to
  58. // check for collisions then
  59. return -1;
  60. } else {
  61. // we found it and it is not deleted
  62. return index;
  63. }
  64. } else {
  65. // strings dont match, this means we have a collision.
  66. // We just search front to back, lol
  67. for (int i = 0; i < hm->current_capacity; ++i) {
  68. cell = hm->data[i];
  69. if (!cell.original_string)
  70. continue;
  71. if (!strings_match(key, cell.original_string))
  72. continue;
  73. if (cell.deleted)
  74. continue;
  75. return i;
  76. }
  77. // not or only deleted cells found
  78. return -1;
  79. }
  80. } else {
  81. // no cell exists at this index so the item was never in the
  82. // hashmap. Either it would be there or be ther and 'deleted'
  83. // or another item would be there and therefore a collistion
  84. // would exist
  85. return -1;
  86. }
  87. }
  88. inline bool hm_key_exists(StringHashMap* hm, char* key) {
  89. return hm_get_index_of_living_cell_if_it_exists(hm, key, hash(key)) != -1;
  90. }
  91. inline void* hm_get_object(StringHashMap* hm, char* key) {
  92. int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hash(key));
  93. if (index != -1) {
  94. return hm->data[index].object;
  95. }
  96. return nullptr;
  97. }
  98. inline void hm_delete_object(StringHashMap* hm, char* key) {
  99. int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hash(key));
  100. if (index != -1) {
  101. hm->data[index].deleted = true;
  102. }
  103. }
  104. void hm_set(StringHashMap* hm, char* key, void* obj) {
  105. u64 hash_val = hash(key);
  106. int index = hash_val % hm->current_capacity;
  107. // if we the desired cell is just empty, write to it and done :)
  108. if (!hm->data[index].original_string) {
  109. // insert new cell into desired slot
  110. ++hm->cell_count;
  111. } else {
  112. if (strings_match(key, hm->data[index].original_string)) {
  113. // overwrite object with same key, dont increment cell
  114. // count
  115. } else {
  116. // collision, check resize
  117. ++hm->cell_count;
  118. if ((hm->cell_count*1.0f / hm->current_capacity) > 0.666f) {
  119. StringHashMapCell* old_data = hm->data;
  120. hm->data = (StringHashMapCell*)calloc(hm->current_capacity*4, sizeof(StringHashMapCell));
  121. hm->cell_count = 0;
  122. hm->current_capacity *= 4;
  123. // insert all old items again
  124. for (int i = 0; i < hm->current_capacity/4; ++i) {
  125. StringHashMapCell cell = old_data[i];
  126. if (cell.original_string) {
  127. hm_set(hm, cell.original_string, cell.object);
  128. }
  129. }
  130. free(old_data);
  131. index = hash_val % hm->current_capacity;
  132. }
  133. // search for empty slot for new cell starting at desired index;
  134. // preventing gotos using lambdas!
  135. [&](){
  136. for (int i = index; i < hm->current_capacity; ++i) {
  137. if (!hm->data[i].original_string ||
  138. strings_match(hm->data[i].original_string, key))
  139. {
  140. index = i;
  141. return;
  142. }
  143. }
  144. for (int i = 0; i < index; ++i) {
  145. if (!hm->data[i].original_string ||
  146. strings_match(hm->data[i].original_string, key))
  147. {
  148. index = i;
  149. return;
  150. }
  151. }
  152. }();
  153. }
  154. }
  155. hm->data[index].deleted = false;
  156. hm->data[index].original_string = key;
  157. hm->data[index].hash = hash_val;
  158. hm->data[index].object = obj;
  159. }