#include #include #include #include "htab.h" #include "utils.h" #define HASH_KEY_HASH(t, key) \ (((t)->fn.hash != NULL) ? ((t)->fn.hash)(key) : hash64((uint64_t)key)) #define HASH_KEY_CMP(t, k1, k2) \ (((t)->fn.cmp != NULL) ? ((t)->fn.cmp)((k1), (k2)) : ((k1) != (k2))) #define HASH_KEY_COPY(t, key) \ (((t)->fn.copy != NULL) ? ((t)->fn.copy)(key) : (key)) #define HASH_KEY_FREE(t, key) \ do { \ if (((t)->fn.free != NULL) && ((key) != NULL)) { \ (t)->fn.free(key); \ } \ } while (0) static unsigned int string_hash(void* data) { return hash_string((const char*)data); } static int string_cmp(void* d1, void* d2) { return (int)strcmp((char*)d1, (char*)d2); } static void* string_dup(void* data) { return (void*)strdup((char*)data); } static void string_free(void* data) { if (data != NULL) { free(data); } } hash_key_fn_t string_hash_key = { .hash = (hash_key_hash_fn_t)string_hash, .cmp = (hash_key_cmp_fn_t)string_cmp, .copy = (hash_key_copy_fn_t)string_dup, .free = (hash_key_free_fn_t)string_free }; hash_key_fn_t int_hash_key = { .hash = NULL, .cmp = NULL, .copy = NULL, .free = NULL }; int ht_init(htab_t* t, int nslots, hash_key_fn_t fn) { if ((t == NULL) || (nslots <= 1)) { return -EINVAL; } mylock_init(&(t->lock)); t->slots = (hent_t**)calloc(nslots, sizeof(hent_t*)); if (t->slots == NULL) { return -ENOMEM; } t->nslots = nslots; t->fn = fn; return 0; } void ht_fini(htab_t* t) { int i; hent_t* e; if (t == NULL) { return; } for (i = 0; i < t->nslots; i++) { while ((e = t->slots[i]) != NULL) { t->slots[i] = e->next; e->next = NULL; HASH_KEY_FREE(t, e->key); free(e); } } free(t->slots); return; } hent_t* ht_get(htab_t* t, void* key) { unsigned int hc; hent_t* e; if (t == NULL) { SET_ERROR(EINVAL); return NULL; } hc = HASH_KEY_HASH(t, key) % (t->nslots); mylock_lock(&(t->lock)); e = t->slots[hc]; while (e != NULL) { if (HASH_KEY_CMP(t, e->key, key) == 0) { break; } e = e->next; } mylock_unlock(&(t->lock)); return e; } hent_t* ht_add(htab_t* t, void* key) { unsigned int hc; hent_t* e; if ((t == NULL) || (key == NULL)) { return NULL; } e = ht_get(t, key); if (e != NULL) { return e; } e = (hent_t*)calloc(1, sizeof(*e)); if (e == NULL) { return NULL; } e->key = HASH_KEY_COPY(t, key); if (e->key == NULL) { free(e); return NULL; } e->data = -1; hc = HASH_KEY_HASH(t, key) % (t->nslots); mylock_init(&(t->lock)); e->next = t->slots[hc]; t->slots[hc] = e; mylock_unlock(&(t->lock)); return e; } int ht_del(htab_t* t, void* key) { unsigned int hc; hent_t** e; int deleted = 0; if ((t == NULL) || (key == NULL)) { return -EINVAL; } hc = HASH_KEY_HASH(t, key) % (t->nslots); mylock_init(&(t->lock)); e = &(t->slots[hc]); while ((*e) != NULL) { if (HASH_KEY_CMP(t, (*e)->key, key) == 0) { hent_t* e1 = *e; *e = e1->next; HASH_KEY_FREE(t, e1->key); free(e1); deleted = 1; break; } e = &((*e)->next); } mylock_unlock(&(t->lock)); if (deleted) { return 1; } return -ENOENT; }