#include #include #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; }