hashmaps
This commit is contained in:
+187
@@ -0,0 +1,187 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user