#pragma once #include #include #include #include "types.hpp" struct StringHashMapCell { char* original_string; void* object; u64 hash; bool deleted; }; struct StringHashMap { int current_capacity; int cell_count; StringHashMapCell* data; }; inline bool strings_match(char* a, char* b) { return strcmp(a, b) == 0; } u32 hash(char* str) { u32 value = str[0] << 7; int i = 0; while (str[i]) { value = (10000003 * value) ^ str[i++]; } return value ^ i; // unsigned long hash = 5381; // int c; // while (c = *str++) // hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ // return hash; // int result = 0x55555555; // while (*str) { // result ^= *str++; // // result = (result << 5) | (result >> (32 - 5)) & ~((-1 >> 5) << 5); // // result = rol(result, 5); // } // return result; // uint32_t hash, i; // for(hash = i = 0; str[i]; ++i) // { // hash += str[i]; // hash += (hash << 10); // hash ^= (hash >> 6); // } // hash += (hash << 3); // hash ^= (hash >> 11); // hash += (hash << 15); // return hash; } StringHashMap* create_hashmap(int initial_capacity = 8) { StringHashMap* hm = new StringHashMap; hm->current_capacity = initial_capacity; hm->cell_count = 0; // set all data to nullptr hm->data = (StringHashMapCell *)calloc(initial_capacity, sizeof(StringHashMapCell*)); return hm; } int hm_get_index_of_living_cell_if_it_exists(StringHashMap* hm, char* key, u64 hash_val) { int index = hash_val % hm->current_capacity; StringHashMapCell cell = hm->data[index]; // test if cell exists at that index if (cell.original_string) { // check if strings match if (strings_match(key, cell.original_string)) { // 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 front to back, lol for (int i = 0; i < hm->current_capacity; ++i) { cell = hm->data[i]; if (!cell.original_string) continue; if (!strings_match(key, cell.original_string)) continue; if (cell.deleted) continue; return i; } // 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(StringHashMap* hm, char* key) { return hm_get_index_of_living_cell_if_it_exists(hm, key, hash(key)) != -1; } inline void* hm_get_object(StringHashMap* hm, char* key) { int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hash(key)); if (index != -1) { return hm->data[index].object; } return nullptr; } inline void hm_delete_object(StringHashMap* hm, char* key) { int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hash(key)); if (index != -1) { hm->data[index].deleted = true; } } void hm_set(StringHashMap* hm, char* key, void* obj) { u64 hash_val = hash(key); int index = index = hash_val % hm->current_capacity; // if we the desired cell is just empty, write to it and done :) printf("index: %d\n"); if (!hm->data[index].original_string) { // insert new cell into desired slot ++hm->cell_count; } else { if (strings_match(key, hm->data[index].original_string)) { // 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) { printf("raellocation\n"); StringHashMapCell* old_data = hm->data; hm->data = (StringHashMapCell*)calloc(hm->current_capacity*4, sizeof(StringHashMapCell*)); hm->cell_count = 0; hm->current_capacity *= 4; // insert all old items again for (int i = 0; i < hm->current_capacity/4; ++i) { StringHashMapCell cell = old_data[i]; if (cell.original_string) { hm_set(hm, cell.original_string, cell.object); } } free(old_data); } // 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_string) { index = i; return; } } for (int i = 0; i < index; ++i) { if (!hm->data[i].original_string) { index = i; return; } } }(); } } hm->data[index].deleted = false; hm->data[index].original_string = key; hm->data[index].hash = hash_val; hm->data[index].object = obj; }