Finished hash table

This commit is contained in:
Kyler Olsen 2025-11-28 20:02:27 -07:00
parent 20434b20ab
commit 63541aac85
2 changed files with 76 additions and 29 deletions

View File

@ -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;

View File

@ -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
#if SIZE_MAX > UINT32_MAX
n |= n >> 32;
#endif
#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];
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;
}