Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

188 lignes
5.6 KiB

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