#include <string.h>
#include <stdlib.h>
#include "bin.h"
#include "ht.h"
#include "mem.h"
int ht_init(ht *x, unsigned tab, unsigned long (*hash)(const void *,unsigned))
{
unsigned tmps;
x->b = (htbucket **)mem_alloc(tmps = tab * sizeof(htbucket *));
if (!x->b) return -1;
memzero(x->b, tmps);
x->ondel = 0;
x->onwrite = 0;
x->onfail = 0;
x->s = tab;
x->hash = hash;
return 1;
}
static int ht_die_fn(ht *x, void *key, unsigned klen, void *data)
{
if (ht_delete(x, key, klen) != 1)
return HT_WILLFAIL;
return HT_RESTART;
}
int ht_die(ht *x)
{
if (ht_walk(x, ht_die_fn) == -1)
return 1;
return 0;
}
int ht_ondelete(ht *x, int (*fn)(void *data))
{
x->ondel = fn;
return 1;
}
int ht_onwrite(ht *x, void (*fn)(const void *,unsigned,const void *))
{
x->onwrite = fn;
return 1;
}
int ht_onfail(ht *x, int (*fn)(const void *, unsigned))
{
x->onfail = fn;
return 1;
}
int ht_walk(ht *x, int (*fn)(ht *x, void *key, unsigned klen, void *data))
{
unsigned i;
union { void *A; const void *B; } qu;
htbucket *n;
int ret = -1;
restart_l:
for (i = 0; i < x->s; i++) {
n = x->b[i];
if (n == 0)
continue;
while (n) {
qu.B = n->key;
switch (fn(x, qu.A, n->klen, n->data)) {
case HT_RESTART: goto restart_l;
case HT_FAILNOW: return 0;
case HT_SUCCESSNOW: return 1;
case HT_TRIPSUCCESS: ret = 1; break;
case HT_TRIPFAIL: ret = 0; break;
case HT_WILLSUCCESS: if (ret != 0) ret = 1; break;
case HT_WILLFAIL: if (ret != 1) ret = 0; break;
case HT_NEXT: break;
case HT_AGAIN: continue;
};
n = (htbucket *)n->next;
}
}
return ret;
}
static int ht_store_flag(ht *x, const void *key, unsigned klen,
void *data, int flag, int i)
{
htbucket *n;
unsigned long hash;
unsigned pos;
bin_t kx;
hash = x->hash(key, klen);
n = x->b[pos = hash % x->s];
while (n) {
if (n->hash == hash && n->klen == klen &&
memcmp(key, n->key, klen) == 0) {
return 0; /* collision */
}
n = (htbucket *)n->next;
}
n = (htbucket *)mem_alloc(sizeof(htbucket));
if (!n) return -1;
bin_init(kx);
bin_copy(kx, key, klen);
n->key = caddr(kx);
n->klen = klen;
n->hash = x->hash(key, klen);;
n->data = data;
n->next = (void *)x->b[pos];
n->free_data = flag;
n->idata = i;
x->b[pos] = (htbucket *)n;
/* write to log (as necessary) */
if (x->onwrite)
x->onwrite(n->key, n->klen, n->data);
return 1;
}
int ht_store(ht *x, const void *key, unsigned klen, void *data)
{
return ht_store_flag(x, key, klen, data, 0, -1);
}
int ht_storeint(ht *x, const void *key, unsigned klen, int i)
{
return ht_store_flag(x, key, klen, 0, 0, i);
}
int ht_storecopy(ht *x, const void *key, unsigned klen, void *data, unsigned dlen)
{
int ret;
void *copy;
copy = (void *)mem_alloc(dlen);
if (!copy) return -1;
memcpy(copy, data, dlen);
ret = ht_store_flag(x, key, klen, copy, 1, -1);
if (ret != 1)
mem_free(copy);
return ret;
}
int ht_fetchint(ht *x, const void *key, unsigned klen)
{
htbucket *n, *sn;
unsigned long hash;
int retry = 0;
hash = x->hash(key, klen);
sn = n = x->b[hash % x->s];
retry_fetchint_l:
while (n) {
if (n->hash == hash && n->klen == klen &&
memcmp(key, n->key, klen) == 0) {
return n->idata;
}
n = (htbucket *)n->next;
}
if (x->onfail && !retry) {
if (x->onfail(key, klen) == HT_RESTART) {
n = sn;
retry = 1;
goto retry_fetchint_l;
}
}
return -1;
}
void *ht_fetch(ht *x, const void *key, unsigned klen)
{
htbucket *n, *sn;
unsigned long hash;
int retry = 0;
hash = x->hash(key, klen);
sn = n = x->b[hash % x->s];
retry_fetch_l:
while (n) {
if (n->hash == hash && n->klen == klen &&
memcmp(key, n->key, klen) == 0) {
return n->data;
}
n = (htbucket *)n->next;
}
if (x->onfail && !retry) {
if (x->onfail(key, klen) == HT_RESTART) {
n = sn;
retry = 1;
goto retry_fetch_l;
}
}
return (void *)0;
}
int ht_delete(ht *x, const void *key, unsigned klen)
{
htbucket *n, *ln;
unsigned long hash;
unsigned pos;
hash = x->hash(key, klen);
n = x->b[pos = hash % x->s];
ln = 0;
while (n) {
if (n->hash == hash && n->klen == klen &&
memcmp(key, n->key, klen) == 0) {
if (ln)
ln->next = n->next;
else
x->b[pos] = n->next;
mem_free(n->key);
if (n->free_data)
mem_free(n->data);
mem_free(n);
return 1;
}
ln = n;
n = (htbucket *)n->next;
}
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1