#pragma once #include #include #include #include "types.hpp" // inline void print_hm(StringHashMap* hm) { // for_str_hash_map(hm) { // printf("index: %d desired-index: %llu key: %s hash: %llu value: %llu\n", i, (hm->data[i].hash % hm->current_capacity), (char*)key, hm->data[i].hash, (unsigned long long)value); // } // } #define __for_hm_generator(key_type, value_type, hm) \ if (key_type key = 0); else \ if (value_type value = 0); else \ for(int index = 0; index < hm.current_capacity; ++index) \ if (!((!hm.data[index].deleted) && \ (key = hm.data[index].original) && \ (value = hm.data[index].object))); else template struct Hash_Map { int current_capacity; int cell_count; struct HM_Cell { key_type original; u64 hash; bool deleted; value_type object; }* data; Hash_Map(int initial_capacity = 8) { current_capacity = initial_capacity; cell_count = 0; data = (HM_Cell*)calloc(initial_capacity, sizeof(HM_Cell)); } int get_index_of_living_cell_if_it_exists(key_type key, u64 hash_val) { // int index = hash_val & (current_capacity - 1); int index = hash_val % current_capacity; HM_Cell cell = data[index]; /* test if cell exists at that index */ if (cell.original) { /* check if strings match */ if (hm_objects_match(key, cell.original)) { /* we found it, now check it it is deleted: */ if (cell.deleted) { /* we found it but it was deleted, we */ /* dont have to check for collisions then */ return -1; } else { /* we found it and it is not deleted */ return index; } } else { /* strings dont match, this means we have */ /* a collision. We just search forward */ for (int i = 0; i < current_capacity; ++i) { int new_idx = (i + index) % current_capacity; cell = data[new_idx]; if (!cell.original) return -1; if (!hm_objects_match(key, cell.original)) continue; if (cell.deleted) continue; return new_idx; } /* not or only deleted cells found */ return -1; } } else { /* no cell exists at this index so the item was never in the */ /* hashmap. Either it would be there or be ther and 'deleted' */ /* or another item would be there and therefore a collistion */ /* would exist */ return -1; } } bool key_exists(key_type key) { return get_index_of_living_cell_if_it_exists(key, hm_hash(key)) != -1; } value_type get_object(key_type key) { int index = get_index_of_living_cell_if_it_exists(key, hm_hash(key)); if (index != -1) { return data[index].object; } int a = *((int*)(nullptr)); return 0; } void delete_object(key_type key) { int index = get_index_of_living_cell_if_it_exists(key, hm_hash(key)); if (index != -1) { data[index].deleted = true; } } void set_object(key_type key, value_type obj) { u64 hash_val = hm_hash(key); int index = hash_val % current_capacity; /* if we the desired cell is just empty, write to it and done :) */ if (!data[index].original) { /* insert new cell into desired slot */ ++cell_count; } else { if (hm_objects_match(key, data[index].original)) { /* overwrite object with same key, dont increment cell */ /* count */ } else { /* collision, check resize */ ++cell_count; if ((cell_count*1.0f / current_capacity) > 0.666f) { auto old_data = data; data = (HM_Cell*)calloc(current_capacity*4, sizeof(HM_Cell)); cell_count = 0; current_capacity *= 4; /* insert all old items again */ for (int i = 0; i < current_capacity/4; ++i) { auto cell = old_data[i]; if (cell.original) { set_object(cell.original, cell.object); } } free(old_data); index = hash_val % current_capacity; } /* search for empty slot for new cell starting at desired index; */ /* preventing gotos using lambdas! */ [&](){ for (int i = index; i < current_capacity; ++i) { if (!data[i].original || hm_objects_match(data[i].original, key)) { index = i; return; } } for (int i = 0; i < index; ++i) { if (!data[i].original || hm_objects_match(data[i].original, key)) { index = i; return; } } }(); } } data[index].deleted = false; data[index].original = key; data[index].hash = hash_val; data[index].object = obj; } }; // #define define_hash_map(type, name) \ // bool hm_objects_match(type,type); \ // u32 hm_hash(type); \ // \ // struct name##_Hash_Map_Cell { \ // type original; \ // u64 hash; \ // bool deleted; \ // void* object; \ // }; \ // \ // struct name##_Hash_Map { \ // int current_capacity; \ // int cell_count; \ // name##_Hash_Map_Cell* data; \ // }; \ // \ // name##_Hash_Map* create_##name##_hashmap(int initial_capacity=8) { \ // name##_Hash_Map* hm = new name##_Hash_Map; \ // hm->current_capacity = initial_capacity; \ // hm->cell_count = 0; \ // /* set all data to nullptr */ \ // hm->data = (name##_Hash_Map_Cell*)calloc(initial_capacity, sizeof(name##_Hash_Map_Cell)); \ // /* printf("check: %s\n", hm->data[6].original_string); */ \ // return hm; \ // } \ // \ // int hm_get_index_of_living_cell_if_it_exists(name##_Hash_Map* hm, type key, u64 hash_val) { \ // int index = hash_val % hm->current_capacity; \ // name##_Hash_Map_Cell cell = hm->data[index]; \ // /* test if cell exists at that index */ \ // if (cell.original) { \ // /* check if strings match */ \ // if (hm_objects_match(key, cell.original)) { \ // /* we found it, now check it it is deleted: */ \ // if (cell.deleted) { \ // /* we found it but it was deleted, we */ \ // /* dont have to check for collisions then */ \ // return -1; \ // } else { \ // /* we found it and it is not deleted */ \ // return index; \ // } \ // } else { \ // /* strings dont match, this means we have */ \ // /* a collision. We just search forward */ \ // for (int i = 0; i < hm->current_capacity; ++i) { \ // int new_idx = (i + index) % hm->current_capacity; \ // cell = hm->data[new_idx]; \ // if (!cell.original) \ // return -1; \ // if (!hm_objects_match(key, cell.original)) \ // continue; \ // if (cell.deleted) \ // continue; \ // return new_idx; \ // } \ // /* not or only deleted cells found */ \ // return -1; \ // } \ // } else { \ // /* no cell exists at this index so the item was never in the */ \ // /* hashmap. Either it would be there or be ther and 'deleted' */ \ // /* or another item would be there and therefore a collistion */ \ // /* would exist */ \ // return -1; \ // } \ // } \ // \ // inline bool hm_key_exists(name##_Hash_Map* hm, type key) { \ // return hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)) != -1; \ // } \ // \ // inline void* hm_get_object(name##_Hash_Map* hm, type key) { \ // int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)); \ // if (index != -1) { \ // return hm->data[index].object; \ // } \ // return nullptr; \ // } \ // \ // inline void hm_delete_object(name##_Hash_Map* hm, type key) { \ // int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)); \ // if (index != -1) { \ // hm->data[index].deleted = true; \ // } \ // } \ // \ // void hm_set(name##_Hash_Map* hm, type key, void* obj) { \ // u64 hash_val = hm_hash(key); \ // int index = hash_val % hm->current_capacity; \ // \ // /* if we the desired cell is just empty, write to it and done :) */ \ // if (!hm->data[index].original) { \ // /* insert new cell into desired slot */ \ // ++hm->cell_count; \ // } else { \ // if (hm_objects_match(key, hm->data[index].original)) { \ // /* overwrite object with same key, dont increment cell */ \ // /* count */ \ // } else { \ // /* collision, check resize */ \ // ++hm->cell_count; \ // if ((hm->cell_count*1.0f / hm->current_capacity) > 0.666f) { \ // auto old_data = hm->data; \ // hm->data = (name##_Hash_Map_Cell*)calloc(hm->current_capacity*4, sizeof(name##_Hash_Map_Cell)); \ // hm->cell_count = 0; \ // hm->current_capacity *= 4; \ // \ // /* insert all old items again */ \ // for (int i = 0; i < hm->current_capacity/4; ++i) { \ // auto cell = old_data[i]; \ // if (cell.original) { \ // hm_set(hm, cell.original, cell.object); \ // } \ // } \ // free(old_data); \ // index = hash_val % hm->current_capacity; \ // } \ // /* search for empty slot for new cell starting at desired index; */ \ // /* preventing gotos using lambdas! */ \ // [&](){ \ // for (int i = index; i < hm->current_capacity; ++i) { \ // if (!hm->data[i].original || \ // hm_objects_match(hm->data[i].original, key)) \ // { \ // index = i; \ // return; \ // } \ // } \ // for (int i = 0; i < index; ++i) { \ // if (!hm->data[i].original || \ // hm_objects_match(hm->data[i].original, key)) \ // { \ // index = i; \ // return; \ // } \ // } \ // }(); \ // } \ // } \ // \ // hm->data[index].deleted = false; \ // hm->data[index].original = key; \ // hm->data[index].hash = hash_val; \ // hm->data[index].object = obj; \ // } \