made hashmaps extensibe by packing them in a horrible macro

This commit is contained in:
FelixBrendel
2019-10-03 16:52:01 +02:00
parent 854593273f
commit 2f6954b520
+157 -167
View File
@@ -4,173 +4,163 @@
#include <stdlib.h> #include <stdlib.h>
#include "types.hpp" #include "types.hpp"
#define for_str_hash_map(hm) \
if (char* key = nullptr); else \ // 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, hm) \
if (key_type key = nullptr); else \
if (void* value = nullptr); else \ if (void* value = nullptr); else \
for(int i = 0; i < hm->current_capacity; ++i) \ for(int index = 0; index < hm->current_capacity; ++index) \
if (!((key = hm->data[i].original_string) && \ if (!((key = hm->data[index].original) && \
(value = hm->data[i].object))); else (value = hm->data[index].object))); else
#define define_hash_map(type, name) \
struct StringHashMapCell { \
char* original_string; struct name##_Hash_Map_Cell { \
void* object; type original; \
u64 hash; u64 hash; \
bool deleted; bool deleted; \
}; void* object; \
}; \
struct StringHashMap { \
int current_capacity; struct name##_Hash_Map { \
int cell_count; int current_capacity; \
StringHashMapCell* data; int cell_count; \
}; name##_Hash_Map_Cell* data; \
}; \
inline void print_hm(StringHashMap* hm) { \
for_str_hash_map(hm) { name##_Hash_Map* create_##name##_hashmap(int initial_capacity=8) { \
printf("index: %d key: %s value: %llu\n", i, key, (unsigned long long)value); name##_Hash_Map* hm = new name##_Hash_Map; \
} hm->current_capacity = initial_capacity; \
} hm->cell_count = 0; \
/* set all data to nullptr */ \
inline bool strings_match(char* a, char* b) { hm->data = (name##_Hash_Map_Cell*)calloc(initial_capacity, sizeof(name##_Hash_Map_Cell)); \
return strcmp(a, b) == 0; /* printf("check: %s\n", hm->data[6].original_string); */ \
} return hm; \
} \
u32 hash(char* str) { \
u32 value = str[0] << 7; int hm_get_index_of_living_cell_if_it_exists(name##_Hash_Map* hm, type key, u64 hash_val) { \
int i = 0; int index = hash_val % hm->current_capacity; \
while (str[i]) { name##_Hash_Map_Cell cell = hm->data[index]; \
value = (10000003 * value) ^ str[i++]; /* test if cell exists at that index */ \
} if (cell.original) { \
return value ^ i; /* check if strings match */ \
} if (hm_objects_match(key, cell.original)) { \
/* we found it, now check it it is deleted: */ \
StringHashMap* create_hashmap(int initial_capacity = 8) { if (cell.deleted) { \
StringHashMap* hm = new StringHashMap; /* we found it but it was deleted, we */ \
hm->current_capacity = initial_capacity; /* dont have to check for collisions then */ \
hm->cell_count = 0; return -1; \
// set all data to nullptr } else { \
hm->data = (StringHashMapCell *)calloc(initial_capacity, sizeof(StringHashMapCell)); /* we found it and it is not deleted */ \
// printf("check: %s\n", hm->data[6].original_string); return index; \
return hm; } \
} } else { \
/* strings dont match, this means we have */ \
int hm_get_index_of_living_cell_if_it_exists(StringHashMap* hm, char* key, u64 hash_val) { /* a collision. We just search forward */ \
int index = hash_val % hm->current_capacity; for (int i = 0; i < hm->current_capacity; ++i) { \
StringHashMapCell cell = hm->data[index]; int new_idx = (i + index) % hm->current_capacity; \
// test if cell exists at that index cell = hm->data[new_idx]; \
if (cell.original_string) { if (!cell.original) \
// check if strings match return -1; \
if (strings_match(key, cell.original_string)) { if (!hm_objects_match(key, cell.original)) \
// we found it, now check it it is deleted: continue; \
if (cell.deleted) { if (cell.deleted) \
// we found it but it was deleted, we dont have to continue; \
// check for collisions then return new_idx; \
return -1; } \
} else { /* not or only deleted cells found */ \
// we found it and it is not deleted return -1; \
return index; } \
} } else { \
} else { /* no cell exists at this index so the item was never in the */ \
// strings dont match, this means we have a collision. /* hashmap. Either it would be there or be ther and 'deleted' */ \
// We just search front to back, lol /* or another item would be there and therefore a collistion */ \
for (int i = 0; i < hm->current_capacity; ++i) { /* would exist */ \
cell = hm->data[i]; return -1; \
if (!cell.original_string) } \
continue; } \
if (!strings_match(key, cell.original_string)) \
continue; inline bool hm_key_exists(name##_Hash_Map* hm, type key) { \
if (cell.deleted) return hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)) != -1; \
continue; } \
return i; \
} inline void* hm_get_object(name##_Hash_Map* hm, type key) { \
// not or only deleted cells found int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)); \
return -1; if (index != -1) { \
} return hm->data[index].object; \
} else { } \
// no cell exists at this index so the item was never in the return nullptr; \
// hashmap. Either it would be there or be ther and 'deleted' } \
// or another item would be there and therefore a collistion \
// would exist inline void hm_delete_object(name##_Hash_Map* hm, char* key) { \
return -1; int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)); \
} if (index != -1) { \
} hm->data[index].deleted = true; \
} \
inline bool hm_key_exists(StringHashMap* hm, char* key) { } \
return hm_get_index_of_living_cell_if_it_exists(hm, key, hash(key)) != -1; \
} void hm_set(name##_Hash_Map* hm, type key, void* obj) { \
u64 hash_val = hm_hash(key); \
inline void* hm_get_object(StringHashMap* hm, char* key) { int index = hash_val % hm->current_capacity; \
int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hash(key)); \
if (index != -1) { /* if we the desired cell is just empty, write to it and done :) */ \
return hm->data[index].object; if (!hm->data[index].original) { \
} /* insert new cell into desired slot */ \
return nullptr; ++hm->cell_count; \
} } else { \
if (hm_objects_match(key, hm->data[index].original)) { \
inline void hm_delete_object(StringHashMap* hm, char* key) { /* overwrite object with same key, dont increment cell */ \
int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hash(key)); /* count */ \
if (index != -1) { } else { \
hm->data[index].deleted = true; /* collision, check resize */ \
} ++hm->cell_count; \
} if ((hm->cell_count*1.0f / hm->current_capacity) > 0.666f) { \
auto old_data = hm->data; \
void hm_set(StringHashMap* hm, char* key, void* obj) { hm->data = (name##_Hash_Map_Cell*)calloc(hm->current_capacity*4, sizeof(name##_Hash_Map_Cell)); \
u64 hash_val = hash(key); hm->cell_count = 0; \
int index = hash_val % hm->current_capacity; hm->current_capacity *= 4; \
\
// if we the desired cell is just empty, write to it and done :) /* insert all old items again */ \
if (!hm->data[index].original_string) { for (int i = 0; i < hm->current_capacity/4; ++i) { \
// insert new cell into desired slot auto cell = old_data[i]; \
++hm->cell_count; if (cell.original) { \
} else { hm_set(hm, cell.original, cell.object); \
if (strings_match(key, hm->data[index].original_string)) { } \
// overwrite object with same key, dont increment cell } \
// count free(old_data); \
} else { index = hash_val % hm->current_capacity; \
// collision, check resize } \
++hm->cell_count; /* search for empty slot for new cell starting at desired index; */ \
if ((hm->cell_count*1.0f / hm->current_capacity) > 0.666f) { /* preventing gotos using lambdas! */ \
StringHashMapCell* old_data = hm->data; [&](){ \
hm->data = (StringHashMapCell*)calloc(hm->current_capacity*4, sizeof(StringHashMapCell)); for (int i = index; i < hm->current_capacity; ++i) { \
hm->cell_count = 0; if (!hm->data[i].original || \
hm->current_capacity *= 4; hm_objects_match(hm->data[i].original, key)) \
{ \
// insert all old items again index = i; \
for (int i = 0; i < hm->current_capacity/4; ++i) { return; \
StringHashMapCell cell = old_data[i]; } \
if (cell.original_string) { } \
hm_set(hm, cell.original_string, cell.object); for (int i = 0; i < index; ++i) { \
} if (!hm->data[i].original || \
} hm_objects_match(hm->data[i].original, key)) \
free(old_data); { \
index = hash_val % hm->current_capacity; index = i; \
} return; \
// 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 || } \
strings_match(hm->data[i].original_string, key)) \
{ hm->data[index].deleted = false; \
index = i; hm->data[index].original = key; \
return; hm->data[index].hash = hash_val; \
} hm->data[index].object = obj; \
} } \
for (int i = 0; i < index; ++i) {
if (!hm->data[i].original_string ||
strings_match(hm->data[i].original_string, key))
{
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;
}