diff options
Diffstat (limited to 'src/common/hash_table.c')
-rw-r--r-- | src/common/hash_table.c | 140 |
1 files changed, 138 insertions, 2 deletions
diff --git a/src/common/hash_table.c b/src/common/hash_table.c index 2f66d45..6b4c014 100644 --- a/src/common/hash_table.c +++ b/src/common/hash_table.c @@ -1,12 +1,148 @@ #include "../include/hash_table.h" #include "../include/helpers.h" - +#include "../include/list.h" #include <stdlib.h> +#include <string.h> + +pair_t *init_pair(char *key, void *v) { + pair_t *pair = safe_calloc(1, sizeof(pair_t)); + pair->key = key; + pair->v = v; + return pair; +} + +void *bucket_pop(list_t *b, char *key) { + node_t *cur = b->head; + node_t *prev; + pair_t *cur_pair; + node_t *tmp; + + if (b->size == 0) + return NULL; + + while (cur) { + cur_pair = cur->item; + if (strcmp(cur_pair->key, key) == 0) { + prev = cur->prev; + if (prev) { + tmp = cur->next; + prev->next = tmp; + + if (tmp) + tmp->prev = prev; + else { + b->tail = prev; + } + + b->size--; + + if (b->size <= 1) + b->head = b->tail; + + return cur; + } else { + tmp = cur->next; + if (tmp) + tmp->prev = NULL; + + b->head = tmp; + b->size--; + + if (b->size <= 1) + b->tail = b->head; + + return cur; + } + } + } + return NULL; +} + +void *bucket_get(list_t *b, char *key) { + node_t *cur = b->head; + pair_t *cur_pair; + + while (cur) { + cur_pair = cur->item; + if (strcmp(key, cur_pair->key) == 0) { + return cur_pair->v; + } + } + return NULL; +} + +void bucket_free(void *x, void (*freefunc)(void *)) { + list_t *b = x; + node_t *cur = b->head; + node_t *tmp; + pair_t *cur_pair; + + if (!x) + return; + + while (cur) { + cur_pair = cur->item; + + freefunc(cur_pair->v); + free(cur_pair->key); + free(cur_pair); + + tmp = cur->next; + free(cur); + cur = tmp; + } + free(b); +} ht_t *init_ht(size_t size) { ht_t *ht = safe_calloc(1, sizeof(size)); size_t realsize = size == 0 ? DEFAULT_HT_SIZE : size; - ht->buckets = safe_calloc(realsize, sizeof(sll_t *)); + ht->buckets = safe_calloc(realsize, sizeof(list_t *)); ht->size = realsize; return ht; } + +void ht_insert(ht_t *ht, char *key, void *value) { + unsigned long bn = hash(key) % ht->size; + list_t *bucket = ht->buckets[bn]; + if (!bucket) + ht->buckets[bn] = init_list(); + + list_push_back(bucket, init_pair(key, value)); +} + +void *ht_pop(ht_t *ht, char *key) { + unsigned long bn = hash(key) % ht->size; + list_t *bucket = ht->buckets[bn]; + if (!bucket) + return NULL; + return bucket_pop(bucket, key); +} + +void *ht_get(ht_t *ht, char *key) { + unsigned long bn = hash(key) % ht->size; + list_t *bucket = ht->buckets[bn]; + if (!bucket) + return NULL; + return bucket_get(bucket, key); +} + +void ht_free(void *x, void (*freefunc)(void *)) { + ht_t *ht = x; + for (int i = 0; i < ht->size; i++) + bucket_free(ht->buckets[i], freefunc); + + free(ht->buckets); + free(ht); +} + +/* DJB2 hash function */ +unsigned long hash(char *str) { + unsigned long hash = 5381; + int c; + + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + return hash; +} |