diff --git a/hash_map.c b/hash_map.c new file mode 100644 index 0000000..b1b2190 --- /dev/null +++ b/hash_map.c @@ -0,0 +1,58 @@ +#include "hash_map.h" +#include "string.h" + +HashMap hash_map_from_sizes(size_t key, size_t value, HashFunc hasher) { + HashMap self = { + .hasher = hasher, + .key_size = key, + .value_size = value + }; + for(size_t i = 0; i < CUTES_HASH_MAP_BUCKETS; ++i) + self.buckets[i] = list_init(sizeof(uintptr_t) + key + value); + return self; +} + +void hash_map_empty(HashMap *self) { + for(size_t i = 0; i < CUTES_HASH_MAP_BUCKETS; ++i) { + list_empty(self->buckets + i); + } +} + +void *hash_map_get_raw(HashMap *self, void *key) { + uintptr_t hash = self->hasher(key); // hash the key first + List bucket = self->buckets[hash % CUTES_HASH_MAP_BUCKETS]; // get the bucket to search + // linear search through the bucket to find the element + for(size_t i = 0; i < bucket.len; ++i) { + uintptr_t *key_at = list_at(&bucket, i); + if(hash == *key_at) + return ++key_at; + } + return NULL; +} + +void hash_map_insert(HashMap *self, void *key, void *value) { + uintptr_t hash = self->hasher(key); + // stage key-value-pair data + char data[sizeof(uintptr_t) + self->key_size + self->value_size]; + memcpy(data, &hash, sizeof(uintptr_t)); // copy key hash into start of data + memcpy(data + sizeof(uintptr_t), key, self->key_size); + memcpy(data + sizeof(uintptr_t) + self->key_size, value, self->value_size); // copy value into end of data + // insert staged data into list + list_add(self->buckets + (hash % CUTES_HASH_MAP_BUCKETS), data); +} + +List hash_map_keys(HashMap *self) { + List keys = list_init(self->key_size); + for(size_t bucket_index = 0; bucket_index < CUTES_HASH_MAP_BUCKETS; ++bucket_index) + for(size_t key_index = 0; key_index < self->buckets[bucket_index].len; ++key_index) + list_add(&keys, list_at(self->buckets + bucket_index, key_index)); + return keys; +} + +List hash_map_values(HashMap *self) { + List values = list_init(self->value_size); + for(size_t bucket_index = 0; bucket_index < CUTES_HASH_MAP_BUCKETS; ++bucket_index) + for(size_t value_index = 0; value_index < self->buckets[bucket_index].len; ++value_index) + list_add(&values, ((char*)list_at(self->buckets + bucket_index, value_index)) + (sizeof(uintptr_t) + self->key_size)); + return values; +} diff --git a/hash_map.h b/hash_map.h new file mode 100644 index 0000000..d40258d --- /dev/null +++ b/hash_map.h @@ -0,0 +1,29 @@ +#ifndef CUTES_HASH_MAP_H +#define CUTES_HASH_MAP_H + +#include "list.h" +#include "stdint.h" +#include "typeclass_helpers.h" + +#define CUTES_HASH_MAP_BUCKETS 24 + +typedef uintptr_t (*HashFunc)(void *data); + +typedef struct HashMap { + List buckets[CUTES_HASH_MAP_BUCKETS]; + HashFunc hasher; + size_t key_size; + size_t value_size; +} HashMap; + +HashMap hash_map_from_sizes(size_t key_size, size_t value_size, HashFunc hasher); +void hash_map_empty(HashMap *self); +void *hash_map_get_raw(HashMap *self, void *key); +void hash_map_insert(HashMap *self, void *key, void *value); +List hash_map_keys(HashMap *self); +List hash_map_values(HashMap *self); + +#define hash_map_from_types(TKey, TValue, KeyHasher) (hash_map_from_sizes(sizeof(TKey), sizeof(TValue), (HashFunc)KeyHasher)); TC_FN_TYPECHECK(uintptr_t, KeyHasher, TKey*) +#define hash_map_get_as(TValue, Self, Key) ((TValue*)hash_map_get_raw(Self, Key)) + +#endif // !CUTES_HASH_MAP_H