Finished hash table
This commit is contained in:
parent
20434b20ab
commit
63541aac85
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue