188 lines
4 KiB
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;
|
|
}
|