generic containers

This commit is contained in:
FelixBrendel
2019-10-17 12:33:45 +02:00
parent b65f439d8e
commit e782aa70b7
2 changed files with 299 additions and 157 deletions
+3 -3
View File
@@ -35,7 +35,7 @@ struct Array_List {
return data[index]; return data[index];
} }
proc _merge(int start, int mid, int end) -> void { void _merge(int start, int mid, int end) {
int start2 = mid + 1; int start2 = mid + 1;
/* If the direct merge is already sorted */ /* If the direct merge is already sorted */
@@ -67,7 +67,7 @@ struct Array_List {
} }
} }
proc sort(int left=-1, int right=-1) -> void { void sort(int left=-1, int right=-1) {
if (left == -1) { if (left == -1) {
sort(0, next_index - 1); sort(0, next_index - 1);
return; return;
@@ -83,7 +83,7 @@ struct Array_List {
_merge(left, middle, right); _merge(left, middle, right);
} }
proc sorted_find(type elem, int left=-1, int right=-1) -> int { int sorted_find(type elem, int left=-1, int right=-1) {
if (left == -1) { if (left == -1) {
return sorted_find(elem, 0, next_index - 1); return sorted_find(elem, 0, next_index - 1);
} else if (left == right) { } else if (left == right) {
+296 -154
View File
@@ -11,159 +11,301 @@
// } // }
// } // }
#define __for_hm_generator(key_type, hm) \ #define __for_hm_generator(key_type, value_type, hm) \
if (key_type key = nullptr); else \ if (key_type key = 0); else \
if (void* value = nullptr); else \ if (value_type value = 0); else \
for(int index = 0; index < hm->current_capacity; ++index) \ for(int index = 0; index < hm.current_capacity; ++index) \
if (!((!hm->data[index].deleted) && \ if (!((!hm.data[index].deleted) && \
(key = hm->data[index].original) && \ (key = hm.data[index].original) && \
(value = hm->data[index].object))); else (value = hm.data[index].object))); else
#define define_hash_map(type, name) \ template <typename key_type, typename value_type>
bool hm_objects_match(type,type); \ struct Hash_Map {
u32 hm_hash(type); \ int current_capacity;
\ int cell_count;
struct name##_Hash_Map_Cell { \ struct HM_Cell {
type original; \ key_type original;
u64 hash; \ u64 hash;
bool deleted; \ bool deleted;
void* object; \ value_type object;
}; \ }* data;
\
struct name##_Hash_Map { \ Hash_Map(int initial_capacity = 8) {
int current_capacity; \ current_capacity = initial_capacity;
int cell_count; \ cell_count = 0;
name##_Hash_Map_Cell* data; \ data = (HM_Cell*)calloc(initial_capacity, sizeof(HM_Cell));
}; \ }
\
name##_Hash_Map* create_##name##_hashmap(int initial_capacity=8) { \ int get_index_of_living_cell_if_it_exists(key_type key, u64 hash_val) {
name##_Hash_Map* hm = new name##_Hash_Map; \ // int index = hash_val & (current_capacity - 1);
hm->current_capacity = initial_capacity; \ int index = hash_val % current_capacity;
hm->cell_count = 0; \ HM_Cell cell = data[index];
/* set all data to nullptr */ \ /* test if cell exists at that index */
hm->data = (name##_Hash_Map_Cell*)calloc(initial_capacity, sizeof(name##_Hash_Map_Cell)); \ if (cell.original) {
/* printf("check: %s\n", hm->data[6].original_string); */ \ /* check if strings match */
return hm; \ if (hm_objects_match(key, cell.original)) {
} \ /* we found it, now check it it is deleted: */
\ if (cell.deleted) {
int hm_get_index_of_living_cell_if_it_exists(name##_Hash_Map* hm, type key, u64 hash_val) { \ /* we found it but it was deleted, we */
int index = hash_val % hm->current_capacity; \ /* dont have to check for collisions then */
name##_Hash_Map_Cell cell = hm->data[index]; \ return -1;
/* test if cell exists at that index */ \ } else {
if (cell.original) { \ /* we found it and it is not deleted */
/* check if strings match */ \ return index;
if (hm_objects_match(key, cell.original)) { \ }
/* we found it, now check it it is deleted: */ \ } else {
if (cell.deleted) { \ /* strings dont match, this means we have */
/* we found it but it was deleted, we */ \ /* a collision. We just search forward */
/* dont have to check for collisions then */ \ for (int i = 0; i < current_capacity; ++i) {
return -1; \ int new_idx = (i + index) % current_capacity;
} else { \ cell = data[new_idx];
/* we found it and it is not deleted */ \ if (!cell.original)
return index; \ return -1;
} \ if (!hm_objects_match(key, cell.original))
} else { \ continue;
/* strings dont match, this means we have */ \ if (cell.deleted)
/* a collision. We just search forward */ \ continue;
for (int i = 0; i < hm->current_capacity; ++i) { \ return new_idx;
int new_idx = (i + index) % hm->current_capacity; \ }
cell = hm->data[new_idx]; \ /* not or only deleted cells found */
if (!cell.original) \ return -1;
return -1; \ }
if (!hm_objects_match(key, cell.original)) \ } else {
continue; \ /* no cell exists at this index so the item was never in the */
if (cell.deleted) \ /* hashmap. Either it would be there or be ther and 'deleted' */
continue; \ /* or another item would be there and therefore a collistion */
return new_idx; \ /* would exist */
} \ return -1;
/* not or only deleted cells found */ \ }
return -1; \ }
} \
} else { \ bool key_exists(key_type key) {
/* no cell exists at this index so the item was never in the */ \ return get_index_of_living_cell_if_it_exists(key, hm_hash(key)) != -1;
/* hashmap. Either it would be there or be ther and 'deleted' */ \ }
/* or another item would be there and therefore a collistion */ \
/* would exist */ \ value_type get_object(key_type key) {
return -1; \ int index = get_index_of_living_cell_if_it_exists(key, hm_hash(key));
} \ if (index != -1) {
} \ return data[index].object;
\ }
inline bool hm_key_exists(name##_Hash_Map* hm, type key) { \ int a = *((int*)(nullptr));
return hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)) != -1; \ return 0;
} \ }
\
inline void* hm_get_object(name##_Hash_Map* hm, type key) { \ void delete_object(key_type key) {
int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)); \ int index = get_index_of_living_cell_if_it_exists(key, hm_hash(key));
if (index != -1) { \ if (index != -1) {
return hm->data[index].object; \ data[index].deleted = true;
} \ }
return nullptr; \ }
} \
\ void set_object(key_type key, value_type obj) {
inline void hm_delete_object(name##_Hash_Map* hm, type key) { \ u64 hash_val = hm_hash(key);
int index = hm_get_index_of_living_cell_if_it_exists(hm, key, hm_hash(key)); \ int index = hash_val % current_capacity;
if (index != -1) { \
hm->data[index].deleted = true; \ /* 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;
void hm_set(name##_Hash_Map* hm, type key, void* obj) { \ } else {
u64 hash_val = hm_hash(key); \ if (hm_objects_match(key, data[index].original)) {
int index = hash_val % hm->current_capacity; \ /* overwrite object with same key, dont increment cell */
\ /* count */
/* if we the desired cell is just empty, write to it and done :) */ \ } else {
if (!hm->data[index].original) { \ /* collision, check resize */
/* insert new cell into desired slot */ \ ++cell_count;
++hm->cell_count; \ if ((cell_count*1.0f / current_capacity) > 0.666f) {
} else { \ auto old_data = data;
if (hm_objects_match(key, hm->data[index].original)) { \ data = (HM_Cell*)calloc(current_capacity*4, sizeof(HM_Cell));
/* overwrite object with same key, dont increment cell */ \ cell_count = 0;
/* count */ \ current_capacity *= 4;
} else { \
/* collision, check resize */ \ /* insert all old items again */
++hm->cell_count; \ for (int i = 0; i < current_capacity/4; ++i) {
if ((hm->cell_count*1.0f / hm->current_capacity) > 0.666f) { \ auto cell = old_data[i];
auto old_data = hm->data; \ if (cell.original) {
hm->data = (name##_Hash_Map_Cell*)calloc(hm->current_capacity*4, sizeof(name##_Hash_Map_Cell)); \ set_object(cell.original, cell.object);
hm->cell_count = 0; \ }
hm->current_capacity *= 4; \ }
\ free(old_data);
/* insert all old items again */ \ index = hash_val % current_capacity;
for (int i = 0; i < hm->current_capacity/4; ++i) { \ }
auto cell = old_data[i]; \ /* search for empty slot for new cell starting at desired index; */
if (cell.original) { \ /* preventing gotos using lambdas! */
hm_set(hm, cell.original, cell.object); \ [&](){
} \ for (int i = index; i < current_capacity; ++i) {
} \ if (!data[i].original ||
free(old_data); \ hm_objects_match(data[i].original, key))
index = hash_val % hm->current_capacity; \ {
} \ index = i;
/* search for empty slot for new cell starting at desired index; */ \ return;
/* preventing gotos using lambdas! */ \ }
[&](){ \ }
for (int i = index; i < hm->current_capacity; ++i) { \ for (int i = 0; i < index; ++i) {
if (!hm->data[i].original || \ if (!data[i].original ||
hm_objects_match(hm->data[i].original, key)) \ hm_objects_match(data[i].original, key))
{ \ {
index = i; \ index = i;
return; \ return;
} \ }
} \ }
for (int i = 0; i < index; ++i) { \ }();
if (!hm->data[i].original || \ }
hm_objects_match(hm->data[i].original, key)) \ }
{ \
index = i; \ data[index].deleted = false;
return; \ data[index].original = key;
} \ data[index].hash = hash_val;
} \ data[index].object = obj;
}(); \ }
} \
} \ };
\
hm->data[index].deleted = false; \ // #define define_hash_map(type, name) \
hm->data[index].original = key; \ // bool hm_objects_match(type,type); \
hm->data[index].hash = hash_val; \ // u32 hm_hash(type); \
hm->data[index].object = obj; \ // \
} \ // 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; \
// } \