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" #include "sls/string.h"
typedef struct Bucket { typedef struct Bucket {
uint32_t key_hash_b; uint32_t hash_a;
uint32_t hash_b;
void *item; void *item;
struct Bucket *next; struct Bucket *next;
} Bucket; } Bucket;

View File

@ -16,39 +16,34 @@ static size_t next_power_of_two(size_t n) {
n |= n >> 4; n |= n >> 4;
n |= n >> 8; n |= n >> 8;
n |= n >> 16; n |= n >> 16;
#if SIZE_MAX > UINT32_MAX #if SIZE_MAX > UINT32_MAX
n |= n >> 32; n |= n >> 32;
#endif #endif
n++; n++;
return n; return n;
} }
HashTable *init_hash_table(size_t min_buckets_count) { 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; if (!ht) return NULL;
ht->buckets_count = buckets_count;
ht->buckets_count = next_power_of_two(min_buckets_count); for (size_t i = 0; i < buckets_count; i++)
ht->buckets[i] = NULL;
ht->buckets = (Bucket **)calloc(ht->buckets_count, sizeof(Bucket *));
if (!ht->buckets) {
free(ht);
return NULL;
}
return ht; return ht;
} }
void del_hash_table(HashTable *ht) { void del_hash_table(HashTable *ht) {
for (size_t i = 0; i < ht->buckets_count; i++) { for (size_t i = 0; i < ht->buckets_count; i++) {
Bucket *next, *head; Bucket *head = ht->buckets[i];
head = (ht->buckets)+i;
while (head) { while (head) {
next = head->next; Bucket *next = head->next;
// TODO: Does item need to be freed?
free(head); free(head);
head = next; head = next;
} }
} }
free(ht->buckets);
free(ht); free(ht);
} }
@ -84,12 +79,13 @@ static inline uint32_t sls_hash_b(SlsStr key) {
key.len -= 4; key.len -= 4;
} }
switch (key.len) { if (key.len >= 3)
case 3: hash ^= key.str[2] << 16; hash ^= key.str[2] << 16;
case 2: hash ^= key.str[1] << 8; if (key.len >= 2)
case 1: hash ^= key.str[0]; hash ^= key.str[1] << 8;
hash *= m; if (key.len >= 1)
} hash ^= key.str[0];
hash *= m;
hash ^= hash >> 13; hash ^= hash >> 13;
hash *= m; hash *= m;
@ -98,12 +94,62 @@ static inline uint32_t sls_hash_b(SlsStr key) {
return hash; return hash;
} }
static inline size_t bucket_index(const HashTable *ht, SlsStr key) { Boolean hash_table_put(HashTable *ht, SlsStr key, void *item) {
return sls_hash_a(key) & (ht->buckets_count - 1); 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;
}