From 63541aac854bbdb493f73ce8d5a35e5905b189df Mon Sep 17 00:00:00 2001 From: Kyler Date: Fri, 28 Nov 2025 20:02:27 -0700 Subject: [PATCH] Finished hash table --- SLS_C/include/sls/hash_table.h | 3 +- SLS_C/src/hash_table.c | 102 ++++++++++++++++++++++++--------- 2 files changed, 76 insertions(+), 29 deletions(-) diff --git a/SLS_C/include/sls/hash_table.h b/SLS_C/include/sls/hash_table.h index 61be87d..3118055 100644 --- a/SLS_C/include/sls/hash_table.h +++ b/SLS_C/include/sls/hash_table.h @@ -11,7 +11,8 @@ #include "sls/string.h" typedef struct Bucket { - uint32_t key_hash_b; + uint32_t hash_a; + uint32_t hash_b; void *item; struct Bucket *next; } Bucket; diff --git a/SLS_C/src/hash_table.c b/SLS_C/src/hash_table.c index 93961bf..ab306c5 100644 --- a/SLS_C/src/hash_table.c +++ b/SLS_C/src/hash_table.c @@ -16,39 +16,34 @@ static size_t next_power_of_two(size_t n) { n |= n >> 4; n |= n >> 8; n |= n >> 16; -#if SIZE_MAX > UINT32_MAX - n |= n >> 32; -#endif + #if SIZE_MAX > UINT32_MAX + n |= n >> 32; + #endif n++; return n; } HashTable *init_hash_table(size_t min_buckets_count) { - HashTable *ht = (HashTable *)malloc(sizeof(HashTable)); + size_t buckets_count = next_power_of_two(min_buckets_count); + size_t size = sizeof(HashTable) + buckets_count * sizeof(Bucket); + HashTable *ht = (HashTable *)malloc(size); if (!ht) return NULL; - - ht->buckets_count = next_power_of_two(min_buckets_count); - - ht->buckets = (Bucket **)calloc(ht->buckets_count, sizeof(Bucket *)); - if (!ht->buckets) { - free(ht); - return NULL; - } - + ht->buckets_count = buckets_count; + for (size_t i = 0; i < buckets_count; i++) + ht->buckets[i] = NULL; return ht; } void del_hash_table(HashTable *ht) { for (size_t i = 0; i < ht->buckets_count; i++) { - Bucket *next, *head; - head = (ht->buckets)+i; + Bucket *head = ht->buckets[i]; while (head) { - next = head->next; + Bucket *next = head->next; + // TODO: Does item need to be freed? free(head); head = next; } } - free(ht->buckets); free(ht); } @@ -84,12 +79,13 @@ static inline uint32_t sls_hash_b(SlsStr key) { key.len -= 4; } - switch (key.len) { - case 3: hash ^= key.str[2] << 16; - case 2: hash ^= key.str[1] << 8; - case 1: hash ^= key.str[0]; - hash *= m; - } + if (key.len >= 3) + hash ^= key.str[2] << 16; + if (key.len >= 2) + hash ^= key.str[1] << 8; + if (key.len >= 1) + hash ^= key.str[0]; + hash *= m; hash ^= hash >> 13; hash *= m; @@ -98,12 +94,62 @@ static inline uint32_t sls_hash_b(SlsStr key) { return hash; } -static inline size_t bucket_index(const HashTable *ht, SlsStr key) { - return sls_hash_a(key) & (ht->buckets_count - 1); +Boolean hash_table_put(HashTable *ht, SlsStr key, void *item) { + uint32_t hash_a = sls_hash_a(key); + uint32_t hash_b = sls_hash_b(key); + size_t bucket_index = hash_a & (ht->buckets_count - 1); + + for (Bucket *node = ht->buckets[bucket_index]; node; node = node->next) { + if (node->hash_a == hash_a && node->hash_b == hash_b) { + // TODO: Does item need to be freed before being replaced? + node->item = item; + return TRUE; + } + } + + Bucket *bucket = (Bucket *)malloc(sizeof(Bucket)); + if (!bucket) + return FALSE; + bucket->hash_a = hash_a; + bucket->hash_b = hash_b; + bucket->item = item; + bucket->next = ht->buckets[bucket_index]; + ht->buckets[bucket_index] = bucket; + + return TRUE; } -Boolean hash_table_put(HashTable *ht, SlsStr key, void *item); +void *hash_table_get(const HashTable *ht, SlsStr key, void *default_item) { + uint32_t hash_a = sls_hash_a(key); + uint32_t hash_b = sls_hash_b(key); + size_t bucket_index = hash_a & (ht->buckets_count - 1); -void *hash_table_get(const HashTable *ht, SlsStr key, void *default_item); + for (Bucket *node = ht->buckets[bucket_index]; node; node = node->next) + if (node->hash_a == hash_a && node->hash_b == hash_b) + return node->item; -Boolean hash_table_del(HashTable *ht, SlsStr key); + return default_item; +} + +Boolean hash_table_del(HashTable *ht, SlsStr key) { + uint32_t hash_a = sls_hash_a(key); + uint32_t hash_b = sls_hash_b(key); + size_t bucket_index = hash_a & (ht->buckets_count - 1); + + Bucket *prev = NULL; + + for (Bucket *node = ht->buckets[bucket_index]; node; node = node->next) { + if (node->hash_a == hash_a && node->hash_b == hash_b) { + if (prev == NULL) + ht->buckets[bucket_index] = node->next; + else + prev->next = node->next; + // TODO: Does item need to be freed? + free(node); + return TRUE; + } + prev = node; + } + + return FALSE; +}