Mercurial > repo
view src/ploki/hash.c @ 8065:591b1467ccdf
<int-e> le/rn paste/"Paste" is a short story by Henry James. Its contents has been cut into pieces and distributed over numerous tin boxes on the World Wide Web, little pearls of wisdom buried among ordinary pastes.
author | HackBot |
---|---|
date | Sun, 15 May 2016 13:14:57 +0000 |
parents | ac0403686959 |
children |
line wrap: on
line source
#include "config.h" #include "hash.h" #include "main.h" #include "main_opt.h" #include "random.h" #include "xmalloc.h" #include <errno.h> #include <stddef.h> #include <stdio.h> #include <assert.h> struct h_entry { size_t hash; void *key; void *value; }; struct h_node { struct h_entry entry; struct h_node *next; }; enum {MAGIC = 112}; void h_init( Hash *h, size_t (*hash)(const void *, size_t), int (*cmp)(const void *, const void *), void (*delk)(void *), void (*delv)(void *) ) { size_t i; h->entries = 0; h->brk = -1; h->iter = -1; h->iterptr = NULL; h->seed = randval() * (size_t)-1; h->delk = delk; h->delv = delv; assert(hash != NULL); h->hash = hash; assert(cmp != NULL); h->cmp = cmp; h->table = xmalloc(h->newsize = h->size = MAGIC, sizeof *h->table); for (i = 0; i < h->size; ++i) { h->table[i] = NULL; } } #define DELKV(p) \ do { \ if (h->delk) { \ h->delk((p)->entry.key); \ } \ if (h->delv) { \ h->delv((p)->entry.value); \ } \ } while (0) void h_end(Hash *h) { size_t size, b; if (!h->table) return; for (b = 0, size = h->newsize; h->newsize; h->newsize--) { struct h_node *p; if ((p = h->table[h->newsize - 1])) { ++b; for (; p; p = h->table[h->newsize - 1]) { h->table[h->newsize - 1] = p->next; DELKV(p); xfree(p); } } } xfree(h->table); h->table = NULL; if (Opt.debug & DBG_HASH) { fprintf(stderr, "%s: hash[%lu/%lu/%lu]\n", Prog, (unsigned long)h->entries, (unsigned long)b, (unsigned long)size); } } ATTR_PURE static size_t xclip(const Hash *h, const size_t hash_unc) { size_t hash; hash = hash_unc % h->size; if (hash > h->brk) { hash = hash_unc % h->newsize; } return hash; } #if 0 ATTR_PURE static size_t xhash(const Hash *h, const void *key) { return xclip(h, h->hash(key, h->seed)); } #endif #define XRESIZN(h) ((h)->brk + 1u) #define XSTEP(h) do { if (XRESIZN(h)) xstep(h); } while (0) static void xstep(Hash *h) { struct h_node *rev = NULL; struct h_node *p; struct h_node *tmp; assert(h->table != NULL); for (p = h->table[h->brk]; p; p = tmp) { tmp = p->next; p->next = rev; rev = p; } h->table[h->brk--] = NULL; if (!XRESIZN(h)) { h->size = h->newsize; } for (p = rev; p; p = tmp) { const size_t i = xclip(h, p->entry.hash); tmp = p->next; p->next = h->table[i]; h->table[i] = p; } } static void xincentries(Hash *h) { h->entries++; if (!(XRESIZN(h)) && h->entries / h->size > 3u) { size_t i; h->table = xrealloc(h->table, h->newsize = h->size * 2u + 1u); for (i = h->size; i < h->newsize; ++i) { h->table[i] = NULL; } h->brk = h->size - 1u; xstep(h); } } int h_get(Hash *h, const void *key, void **res) { XSTEP(h); { const size_t hash_unc = h->hash(key, h->seed); const size_t hash = xclip(h, hash_unc); struct h_node *p; for (p = h->table[hash]; p; p = p->next) { if (hash_unc == p->entry.hash && h->cmp(p->entry.key, key) == 0) { if (res) { *res = p->entry.value; } return H_OK; } } } return H_NOENT; } int h_del(Hash *h, const void *key) { XSTEP(h); { const size_t hash_unc = h->hash(key, h->seed); const size_t hash = xclip(h, hash_unc); struct h_node **p; for (p = &h->table[hash]; *p; p = &(*p)->next) { if (hash_unc == (*p)->entry.hash && h->cmp((*p)->entry.key, key) == 0) { struct h_node *tmp = *p; *p = (*p)->next; DELKV(tmp); xfree(tmp); h->entries--; return H_OK; } } } return H_NOENT; } #if 0 void h_push(Hash *h, void *key, void *val) { XSTEP(h); { const size_t hash_unc = h->hash(key, h->seed); const size_t hash = xclip(h, hash_unc); struct h_node *p; p = xmalloc(1, sizeof *p); p->entry.hash = hash_unc; p->entry.key = key; p->entry.value = val; p->next = h->table[hash]; h->table[hash] = p; xincentries(h); } } #endif int h_put(Hash *h, void *key, void *val, int replace) { XSTEP(h); { const size_t hash_unc = h->hash(key, h->seed); const size_t hash = xclip(h, hash_unc); struct h_node **p; for (p = &h->table[hash]; *p; p = &(*p)->next) { if (hash_unc == (*p)->entry.hash && h->cmp((*p)->entry.key, key) == 0) { if (replace) { DELKV(*p); (*p)->entry.key = key; (*p)->entry.value = val; return H_OK; } else { return H_EXIST; } } } *p = xmalloc(1, sizeof **p); (*p)->entry.hash = hash_unc; (*p)->entry.key = key; (*p)->entry.value = val; (*p)->next = NULL; xincentries(h); } return H_OK; } void h_reset(Hash *h) { h->iter = -1; h->iterptr = NULL; } int h_nextkv(Hash *h, void **k, void **v) { if (h->iterptr) { *k = h->iterptr->entry.key; *v = h->iterptr->entry.value; h->iterptr = h->iterptr->next; return H_OK; } for (h->iter++; h->iter < h->newsize; h->iter++) { if ((h->iterptr = h->table[h->iter])) { *k = h->iterptr->entry.key; *v = h->iterptr->entry.value; h->iterptr = h->iterptr->next; return H_OK; } } h->iter = -1; return H_NOENT; } #if 0 size_t (h_entries)(const Hash *h) { return h_entries(h); } #endif