created HashMap iterator
This commit is contained in:
parent
2de044711f
commit
6a1067a612
@ -6,13 +6,13 @@
|
||||
|
||||
typedef void (*FreeFunction)(void*);
|
||||
|
||||
typedef struct KeyHash {
|
||||
typedef struct HashMapKeyHash {
|
||||
str key;
|
||||
u32 hash;
|
||||
} KeyHash;
|
||||
} HashMapKeyHash;
|
||||
|
||||
typedef struct HashMapBucket {
|
||||
List(KeyHash) key_hash_list;
|
||||
List(HashMapKeyHash) key_hash_list;
|
||||
List(T) value_list;
|
||||
} HashMapBucket;
|
||||
|
||||
@ -34,3 +34,23 @@ bool HashMap_tryPush(HashMap_* self, const str key, void* value_ptr);
|
||||
void HashMap_pushOrUpdate(HashMap_* self, const str key, void* value_ptr);
|
||||
NULLABLE(void*) HashMap_tryGetPtr(const HashMap_* self, const str key);
|
||||
bool HashMap_tryDelete(HashMap_* self, const str key);
|
||||
|
||||
|
||||
typedef struct {
|
||||
const HashMap_* map;
|
||||
i32 bucket_n;
|
||||
i32 elem_n;
|
||||
} HashMapIter;
|
||||
|
||||
typedef struct HashMapKeyValue {
|
||||
str key;
|
||||
void* value;
|
||||
} HashMapKeyValue;
|
||||
|
||||
static inline HashMapIter HashMapIter_create(const HashMap_* table){
|
||||
return (HashMapIter){ .map = table, .bucket_n = -1, .elem_n = -1 };
|
||||
}
|
||||
|
||||
bool HashMapIter_moveNext(HashMapIter* self);
|
||||
/// don't forget to call HashMapIter_moveNext() first
|
||||
bool HashMapIter_getCurrent(HashMapIter* self, HashMapKeyValue* kv);
|
||||
|
||||
@ -27,11 +27,11 @@ void HashMap_destroy(HashMap_* self){
|
||||
|
||||
for(u32 i = 0; i < self->height; i++){
|
||||
HashMapBucket* bu = &self->table[i];
|
||||
u32 len = List_len(bu->key_hash_list, KeyHash);
|
||||
u32 len = List_len(bu->key_hash_list, HashMapKeyHash);
|
||||
|
||||
// free key strings
|
||||
for(u32 j = 0; j < len; j++){
|
||||
KeyHash* kh = (KeyHash*)bu->key_hash_list.data + j;
|
||||
HashMapKeyHash* kh = (HashMapKeyHash*)bu->key_hash_list.data + j;
|
||||
free(kh->key.data);
|
||||
}
|
||||
|
||||
@ -68,8 +68,8 @@ static BucketAndIndex __HashMap_search(const HashMap_* self, const str key, u32
|
||||
|
||||
BucketAndIndex r;
|
||||
r.bu = &self->table[hash % self->height];
|
||||
for(r.i = 0; r.i < (i32)List_len(r.bu->key_hash_list, KeyHash); r.i++){
|
||||
KeyHash* kh = (KeyHash*)r.bu->key_hash_list.data + r.i;
|
||||
for(r.i = 0; r.i < (i32)List_len(r.bu->key_hash_list, HashMapKeyHash); r.i++){
|
||||
HashMapKeyHash* kh = (HashMapKeyHash*)r.bu->key_hash_list.data + r.i;
|
||||
if(kh->hash == hash && str_equals(kh->key, key)){
|
||||
return r;
|
||||
}
|
||||
@ -85,7 +85,7 @@ void* HashMap_tryGetPtr(const HashMap_* self, const str key){
|
||||
// key not found
|
||||
if(r.i == -1)
|
||||
return NULL;
|
||||
return ((u8*)r.bu->value_list.data) + r.i * self->value_t_size;
|
||||
return (u8*)r.bu->value_list.data + r.i * self->value_t_size;
|
||||
}
|
||||
|
||||
|
||||
@ -102,12 +102,12 @@ static void __HashMap_expand(HashMap_* self){
|
||||
// copy values from old buckets to new
|
||||
for(u32 i = 0; i < self->height; i++){
|
||||
HashMapBucket* old_bucket = &self->table[i];
|
||||
u32 len = List_len(old_bucket->key_hash_list, KeyHash);
|
||||
u32 len = List_len(old_bucket->key_hash_list, HashMapKeyHash);
|
||||
|
||||
for(u32 j = 0; j < len; j++){
|
||||
KeyHash kh = ((KeyHash*)old_bucket->key_hash_list.data)[j];
|
||||
HashMapKeyHash kh = ((HashMapKeyHash*)old_bucket->key_hash_list.data)[j];
|
||||
HashMapBucket* new_bucket = &table_expanded[kh.hash % height_expanded];
|
||||
List_push(&new_bucket->key_hash_list, KeyHash, kh);
|
||||
List_push(&new_bucket->key_hash_list, HashMapKeyHash, kh);
|
||||
void* old_value_ptr = (u8*)old_bucket->value_list.data + j * self->value_t_size;
|
||||
List_push_size(&new_bucket->value_list, old_value_ptr, self->value_t_size);
|
||||
}
|
||||
@ -129,13 +129,13 @@ bool HashMap_tryPush(HashMap_* self, const str key, void* value_ptr){
|
||||
return false;
|
||||
|
||||
HashMapBucket* bu = r.bu;
|
||||
if(bu == NULL || List_len(bu->key_hash_list, KeyHash) >= __HashMapBucket_MAX_LEN){
|
||||
if(bu == NULL || List_len(bu->key_hash_list, HashMapKeyHash) >= __HashMapBucket_MAX_LEN){
|
||||
__HashMap_expand(self);
|
||||
bu = &self->table[hash % self->height];
|
||||
}
|
||||
|
||||
KeyHash kh = { .key = str_copy(key), .hash = hash };
|
||||
List_push(&bu->key_hash_list, KeyHash, kh);
|
||||
HashMapKeyHash kh = { .key = str_copy(key), .hash = hash };
|
||||
List_push(&bu->key_hash_list, HashMapKeyHash, kh);
|
||||
List_push_size(&bu->value_list, value_ptr, self->value_t_size);
|
||||
return true;
|
||||
}
|
||||
@ -145,18 +145,19 @@ void HashMap_pushOrUpdate(HashMap_* self, const str key, void* value_ptr){
|
||||
BucketAndIndex r = __HashMap_search(self, key, hash);
|
||||
// found existing item with the same key
|
||||
if(r.i != -1){
|
||||
void* existing_item = ((u8*)r.bu->value_list.data) + r.i * self->value_t_size;
|
||||
void* existing_item = (u8*)r.bu->value_list.data + r.i * self->value_t_size;
|
||||
memcpy(existing_item, value_ptr, self->value_t_size);
|
||||
return;
|
||||
}
|
||||
|
||||
HashMapBucket* bu = r.bu;
|
||||
if(bu == NULL || List_len(bu->key_hash_list, KeyHash) >= __HashMapBucket_MAX_LEN){
|
||||
if(bu == NULL || List_len(bu->key_hash_list, HashMapKeyHash) >= __HashMapBucket_MAX_LEN){
|
||||
__HashMap_expand(self);
|
||||
bu = &self->table[hash % self->height];
|
||||
}
|
||||
|
||||
KeyHash kh = { .key = str_copy(key), .hash = hash };
|
||||
List_push(&bu->key_hash_list, KeyHash, kh);
|
||||
HashMapKeyHash kh = { .key = str_copy(key), .hash = hash };
|
||||
List_push(&bu->key_hash_list, HashMapKeyHash, kh);
|
||||
List_push_size(&bu->value_list, value_ptr, self->value_t_size);
|
||||
}
|
||||
|
||||
@ -167,7 +168,48 @@ bool HashMap_tryDelete(HashMap_* self, const str key){
|
||||
if(r.i == -1)
|
||||
return false;
|
||||
|
||||
List_removeAt(&r.bu->key_hash_list, KeyHash, r.i, 1);
|
||||
List_removeAt(&r.bu->key_hash_list, HashMapKeyHash, r.i, 1);
|
||||
List_removeAt_size(&r.bu->value_list, r.i, self->value_t_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HashMapIter_moveNext(HashMapIter* self){
|
||||
if(self->map == NULL)
|
||||
return false;
|
||||
|
||||
if(self->bucket_n == -1){
|
||||
self->bucket_n = 0;
|
||||
}
|
||||
// move to next element in current bucket
|
||||
const HashMapBucket* bu = &self->map->table[self->bucket_n];
|
||||
i32 bu_elem_len = List_len(bu->key_hash_list, HashMapKeyHash);
|
||||
if(self->elem_n + 1 < bu_elem_len){
|
||||
self->elem_n++;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// move to next non-empty bucket
|
||||
while(self->bucket_n + 1 < (i32)self->map->height){
|
||||
self->bucket_n++;
|
||||
self->elem_n = 0;
|
||||
bu = &self->map->table[self->bucket_n];
|
||||
if(bu->key_hash_list.size != 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HashMapIter_getCurrent(HashMapIter* self, HashMapKeyValue* kv){
|
||||
if(self->map == NULL || self->bucket_n == -1 || self->elem_n == -1)
|
||||
return false;
|
||||
|
||||
const HashMapBucket* bu = &self->map->table[self->bucket_n];
|
||||
// table is empty
|
||||
if(bu->key_hash_list.size == 0)
|
||||
return false;
|
||||
|
||||
kv->key = List_index(bu->key_hash_list, HashMapKeyHash, self->elem_n).key;
|
||||
kv->value = (u8*)bu->value_list.data + self->map->value_t_size * self->elem_n;
|
||||
return true;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user