From 259bae805cef9354b2579d16e192d8268cb68949 Mon Sep 17 00:00:00 2001 From: Sara Date: Sat, 4 Nov 2023 19:18:28 +0100 Subject: [PATCH] added hashmap --- src/map.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/map.h | 28 +++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 src/map.c create mode 100644 src/map.h diff --git a/src/map.c b/src/map.c new file mode 100644 index 0000000..870a553 --- /dev/null +++ b/src/map.c @@ -0,0 +1,81 @@ +#include "map.h" +#include "memory.h" +#include "math.h" +#include "debug.h" + +HashMap hash_map_from_sizes(size_t ksize, size_t vsize, HashFn hasher) { + return (HashMap) { + .data = list_init(ksize + vsize + sizeof(uintptr_t)), + .hasher = hasher, + .key_size = ksize, + .value_size = vsize, + }; +} + +void hash_map_empty(HashMap* self) { + list_empty(&self->data); +} + +static inline +uintptr_t _internal_get_hash(HashMap* self, size_t at) { + return *list_at_as(uintptr_t, &self->data, at); +} + +static inline +void* _internal_get_key(HashMap* self, size_t at) { + return (void*)(list_at_as(uint8_t, &self->data, at) + sizeof(uintptr_t) + self->value_size); +} + +static inline +void* _internal_get_value(HashMap* self, size_t at) { + return (void*)(list_at_as(uint8_t, &self->data, at) + sizeof(uintptr_t)); +} + +static inline +size_t _internal_search(HashMap* self, uintptr_t hash) { + int left = 0; + int right = self->data.len - 1; + int m; + + while(left <= right) { + m = floor((float)(left + right) / 2.0); + if(*list_at_as(uintptr_t, &self->data, m) < hash) { + left = m + 1; + } else if(*list_at_as(uintptr_t, &self->data, m) > hash) { + right = m - 1; + } else { + return m; + } + } + + return self->data.len; +} + +void hash_map_insert(HashMap* self, void* key, void* value) { + const uintptr_t hash = self->hasher(key); + const size_t target_index = _internal_search(self, hash); + + list_reserve(&self->data, self->data.len + 1); + self->data.len += 1; + + uint8_t* target_address = list_at(&self->data, target_index); + + uintptr_t* target_hash = (uintptr_t*)target_address; + uint8_t* target_value = target_address + sizeof(uintptr_t); + uint8_t* target_key = target_value + self->value_size; + + *target_hash = hash; + memcpy(target_value, value, self->value_size); + memcpy(target_key, key, self->key_size); +} + +void hash_map_erase(HashMap* self, void* key) { + const size_t target_index = _internal_search(self, self->hasher(key)); + ASSERT_RETURN(target_index < self->data.len,, "Attempted to erase a hashmap by a key that is not in the hashmap"); + list_erase(&self->data, target_index); +} + +void* hash_map_at(HashMap* self, void* key) { + const size_t target_index = _internal_search(self, self->hasher(key)); + return list_at(&self->data, target_index); +} diff --git a/src/map.h b/src/map.h new file mode 100644 index 0000000..0652342 --- /dev/null +++ b/src/map.h @@ -0,0 +1,28 @@ +#ifndef _fencer_hashmap_h +#define _fencer_hashmap_h + +#include "stdint.h" +#include "list.h" + +typedef uintptr_t (*HashFn)(void*); + +typedef struct HashMap { + HashFn hasher; + List data; + size_t key_size; + size_t value_size; +} HashMap; + +extern HashMap hash_map_from_sizes(size_t key_size, size_t value_size, HashFn hasher); +extern void hash_map_empty(HashMap* self); +extern void hash_map_insert(HashMap* self, void* key, void* value); +extern void hash_map_erase(HashMap* self, void* key); +extern void* hash_map_at(HashMap* self, void* key); + +#define hash_map_at_as(__Type, __Map, __Key)\ + ((__Type*)hash_map_at(__Map, __Key)) + +#define hash_map_from_types(__KType, __VType, __Hasher)\ + (hash_map_from_sizes(sizeof(__KType), sizeof(_VType), __Hasher)) + +#endif // !_fencer_hashmap_h