|
|
@@ -11,159 +11,301 @@ |
|
|
// } |
|
|
// } |
|
|
// } |
|
|
// } |
|
|
|
|
|
|
|
|
#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 (!((!hm->data[index].deleted) && \ |
|
|
|
|
|
(key = hm->data[index].original) && \ |
|
|
|
|
|
(value = hm->data[index].object))); else |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define define_hash_map(type, name) \ |
|
|
|
|
|
bool hm_objects_match(type,type); \ |
|
|
|
|
|
u32 hm_hash(type); \ |
|
|
|
|
|
\ |
|
|
|
|
|
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; \ |
|
|
|
|
|
} \ |
|
|
|
|
|
|
|
|
#define __for_hm_generator(key_type, value_type, hm) \ |
|
|
|
|
|
if (key_type key = 0); else \ |
|
|
|
|
|
if (value_type value = 0); else \ |
|
|
|
|
|
for(int index = 0; index < hm.current_capacity; ++index) \ |
|
|
|
|
|
if (!((!hm.data[index].deleted) && \ |
|
|
|
|
|
(key = hm.data[index].original) && \ |
|
|
|
|
|
(value = hm.data[index].object))); else |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename key_type, typename value_type> |
|
|
|
|
|
struct Hash_Map { |
|
|
|
|
|
int current_capacity; |
|
|
|
|
|
int cell_count; |
|
|
|
|
|
struct HM_Cell { |
|
|
|
|
|
key_type original; |
|
|
|
|
|
u64 hash; |
|
|
|
|
|
bool deleted; |
|
|
|
|
|
value_type object; |
|
|
|
|
|
}* data; |
|
|
|
|
|
|
|
|
|
|
|
Hash_Map(int initial_capacity = 8) { |
|
|
|
|
|
current_capacity = initial_capacity; |
|
|
|
|
|
cell_count = 0; |
|
|
|
|
|
data = (HM_Cell*)calloc(initial_capacity, sizeof(HM_Cell)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int get_index_of_living_cell_if_it_exists(key_type key, u64 hash_val) { |
|
|
|
|
|
// int index = hash_val & (current_capacity - 1); |
|
|
|
|
|
int index = hash_val % current_capacity; |
|
|
|
|
|
HM_Cell cell = 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 < current_capacity; ++i) { |
|
|
|
|
|
int new_idx = (i + index) % current_capacity; |
|
|
|
|
|
cell = 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; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool key_exists(key_type key) { |
|
|
|
|
|
return get_index_of_living_cell_if_it_exists(key, hm_hash(key)) != -1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
value_type get_object(key_type key) { |
|
|
|
|
|
int index = get_index_of_living_cell_if_it_exists(key, hm_hash(key)); |
|
|
|
|
|
if (index != -1) { |
|
|
|
|
|
return data[index].object; |
|
|
|
|
|
} |
|
|
|
|
|
int a = *((int*)(nullptr)); |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void delete_object(key_type key) { |
|
|
|
|
|
int index = get_index_of_living_cell_if_it_exists(key, hm_hash(key)); |
|
|
|
|
|
if (index != -1) { |
|
|
|
|
|
data[index].deleted = true; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void set_object(key_type key, value_type obj) { |
|
|
|
|
|
u64 hash_val = hm_hash(key); |
|
|
|
|
|
int index = hash_val % current_capacity; |
|
|
|
|
|
|
|
|
|
|
|
/* 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; |
|
|
|
|
|
} else { |
|
|
|
|
|
if (hm_objects_match(key, data[index].original)) { |
|
|
|
|
|
/* overwrite object with same key, dont increment cell */ |
|
|
|
|
|
/* count */ |
|
|
|
|
|
} else { |
|
|
|
|
|
/* collision, check resize */ |
|
|
|
|
|
++cell_count; |
|
|
|
|
|
if ((cell_count*1.0f / current_capacity) > 0.666f) { |
|
|
|
|
|
auto old_data = data; |
|
|
|
|
|
data = (HM_Cell*)calloc(current_capacity*4, sizeof(HM_Cell)); |
|
|
|
|
|
cell_count = 0; |
|
|
|
|
|
current_capacity *= 4; |
|
|
|
|
|
|
|
|
|
|
|
/* insert all old items again */ |
|
|
|
|
|
for (int i = 0; i < current_capacity/4; ++i) { |
|
|
|
|
|
auto cell = old_data[i]; |
|
|
|
|
|
if (cell.original) { |
|
|
|
|
|
set_object(cell.original, cell.object); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
free(old_data); |
|
|
|
|
|
index = hash_val % current_capacity; |
|
|
|
|
|
} |
|
|
|
|
|
/* search for empty slot for new cell starting at desired index; */ |
|
|
|
|
|
/* preventing gotos using lambdas! */ |
|
|
|
|
|
[&](){ |
|
|
|
|
|
for (int i = index; i < current_capacity; ++i) { |
|
|
|
|
|
if (!data[i].original || |
|
|
|
|
|
hm_objects_match(data[i].original, key)) |
|
|
|
|
|
{ |
|
|
|
|
|
index = i; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
for (int i = 0; i < index; ++i) { |
|
|
|
|
|
if (!data[i].original || |
|
|
|
|
|
hm_objects_match(data[i].original, key)) |
|
|
|
|
|
{ |
|
|
|
|
|
index = i; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
data[index].deleted = false; |
|
|
|
|
|
data[index].original = key; |
|
|
|
|
|
data[index].hash = hash_val; |
|
|
|
|
|
data[index].object = obj; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// #define define_hash_map(type, name) \ |
|
|
|
|
|
// bool hm_objects_match(type,type); \ |
|
|
|
|
|
// u32 hm_hash(type); \ |
|
|
|
|
|
// \ |
|
|
|
|
|
// 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; \ |
|
|
|
|
|
// } \ |