myxce/src/lib/htab.c

188 lines
4 KiB
C

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#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_lock(&(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_lock(&(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;
}