made hashmaps extensibe by packing them in a horrible macro
This commit is contained in:
+158
-168
@@ -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) {
|
||||||
if (void* value = nullptr); else \
|
// for_str_hash_map(hm) {
|
||||||
for(int i = 0; i < hm->current_capacity; ++i) \
|
// 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);
|
||||||
if (!((key = hm->data[i].original_string) && \
|
// }
|
||||||
(value = hm->data[i].object))); else
|
// }
|
||||||
|
|
||||||
|
#define __for_hm_generator(key_type, hm) \
|
||||||
|
if (key_type key = nullptr); else \
|
||||||
|
if (void* value = nullptr); else \
|
||||||
|
for(int index = 0; index < hm->current_capacity; ++index) \
|
||||||
|
if (!((key = hm->data[index].original) && \
|
||||||
|
(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;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user