ref: 1edcce3e14962a3642ff07d95770128cee95c5b5
dir: /hash.c/
#include <u.h>
#include <libc.h>
#include "hash.h"
enum{
Tagsize = sizeof(Hnode),
};
Hmap*
allochmap(uvlong (*hash)(void*), int (*cmp)(void*,void*), int nbuckets, int size)
{
void *store;
Hmap *h;
int nsz;
nsz = Tagsize + size;
store = mallocz(sizeof(*h) + (nbuckets * nsz), 1);
if(store == nil)
return nil;
h = store;
h->nbs = nbuckets;
h->nsz = nsz;
h->hash = hash;
h->cmp = cmp;
h->len = h->cap = nbuckets;
h->nodes = store;
h->nodes += sizeof(*h);
return store;
}
void
hmapset(Hmap **store, void *new)
{
Hnode *n;
uchar *v;
Hmap *h;
int next;
h = *store;
v = h->nodes + (h->hash(new)%h->nbs) * h->nsz;
for(;;){
n = (Hnode*)v;
next = n->next;
if(n->filled == 0)
goto replace;
if(h->cmp(v + Tagsize, new) == 0)
goto replace;
if(next == 0)
break;
v = h->nodes + next*h->nsz;
}
if(h->cap == h->len){
h->cap *= 2;
*store = realloc(*store, sizeof(*h) + h->cap*h->nsz);
h = *store;
h->nodes = (uchar*)*store + sizeof(*h);
memset(h->nodes + h->len*h->nsz, 0, h->nsz);
}
n->next = h->len;
h->len++;
assert(h->len <= h->cap);
v = h->nodes + n->next*h->nsz;
n = (Hnode*)v;
replace:
memmove(v + Tagsize, new, h->nsz - Tagsize);
n->filled++;
n->next = next;
}
void*
hmapget(Hmap *h, void *q)
{
Hnode *n;
uchar *v;
v = h->nodes + (h->hash(q)%h->nbs)*h->nsz;
for(;;){
n = (Hnode*)v;
if(n->filled != 0 && h->cmp(v + Tagsize, q) == 0)
return v + Tagsize;
if(n->next == 0)
break;
v = h->nodes + n->next*h->nsz;
}
return nil;
}
void*
hmapdel(Hmap *h, Hnode *q)
{
uchar *v;
Hnode *n;
v = hmapget(h, q);
if(n == nil)
return nil;
n = (Hnode*)(v - Tagsize);
n->filled = 0;
return v;
}
Hmap*
hmaprehash(Hmap *old, int buckets)
{
int i;
uchar *v;
Hmap *new;
if(buckets == 0)
buckets = old->len;
new = allochmap(old->hash, old->cmp, buckets, old->nsz);
for(i=0 ; i < old->len; i++){
v = old->nodes + i*old->nsz;
hmapset(&new, v + Tagsize);
}
free(old);
return new;
}
int
hmapvals(Hmap *h, void *buf, int maxelem)
{
Hnode *n;
uchar *v;
uchar *out;
int i, valsz;
out = buf;
valsz = h->nsz - Tagsize;
for(i=0; i <= maxelem && i < h->len; i++){
v = h->nodes + i*h->nsz;
n = (Hnode*)v;
if(n->filled == 0)
continue;
v += Tagsize;
memmove(out, v, valsz);
out += valsz;
}
return (out - (uchar*)buf)/valsz;
}