169 lines
2.6 KiB
C
169 lines
2.6 KiB
C
#include "dat.h"
|
|
#include "fn.h"
|
|
|
|
enum {
|
|
Tagsize = sizeof(Hnode),
|
|
};
|
|
|
|
static uvlong
|
|
hash(Str *s)
|
|
{
|
|
uvlong h;
|
|
int i;
|
|
|
|
h = 7;
|
|
for(i = 0; i < s->n; i++)
|
|
h = h*31 + s->r[i];
|
|
return h;
|
|
}
|
|
|
|
Hmap*
|
|
hmapalloc(int nbuckets)
|
|
{
|
|
void *store;
|
|
Hmap *h;
|
|
int nsz;
|
|
|
|
if(nbuckets < 1)
|
|
return nil;
|
|
nsz = Tagsize;
|
|
store = emalloc(sizeof(*h) + nbuckets * nsz);
|
|
h = store;
|
|
h->nbs = nbuckets;
|
|
h->nsz = nsz;
|
|
h->len = h->cap = nbuckets;
|
|
h->nodes = (uchar*)store + sizeof(*h);
|
|
return h;
|
|
}
|
|
|
|
static int
|
|
keycmp(Hnode *n, Str *key)
|
|
{
|
|
char buf[Maxutf];
|
|
int len;
|
|
|
|
len = stoutf(key, buf, sizeof(buf));
|
|
if(n->klen != len)
|
|
return 1;
|
|
return memcmp(n->key, buf, len);
|
|
}
|
|
|
|
Hnode*
|
|
hmapget(Hmap *h, Str *key)
|
|
{
|
|
Hnode *n;
|
|
uchar *v;
|
|
|
|
if(h == nil || key == nil || key->n < 0 || key->n > Maxrunes)
|
|
return nil;
|
|
v = h->nodes + (hash(key) % h->nbs) * h->nsz;
|
|
for(;;){
|
|
n = (Hnode*)v;
|
|
if(n->filled && keycmp(n, key) == 0)
|
|
return n;
|
|
if(n->next == 0)
|
|
break;
|
|
v = h->nodes + n->next * h->nsz;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
static char*
|
|
sdup(Str *s, int *len)
|
|
{
|
|
char buf[Maxutf];
|
|
char *p;
|
|
int n;
|
|
|
|
n = stoutf(s, buf, sizeof(buf));
|
|
p = emalloc(n + 1);
|
|
memmove(p, buf, n);
|
|
p[n] = '\0';
|
|
*len = n;
|
|
return p;
|
|
}
|
|
|
|
static char*
|
|
memdup(const char *src, int n)
|
|
{
|
|
char *p;
|
|
|
|
if(n == 0)
|
|
return nil;
|
|
p = emalloc(n + 1);
|
|
memmove(p, src, n);
|
|
p[n] = '\0';
|
|
return p;
|
|
}
|
|
|
|
void
|
|
hmapfree(Hmap *h)
|
|
{
|
|
Hnode *n;
|
|
int i;
|
|
|
|
if(h == nil)
|
|
return;
|
|
for(i = 0; i < h->len; i++){
|
|
n = (Hnode*)(h->nodes + i * h->nsz);
|
|
if(!n->filled)
|
|
continue;
|
|
free(n->key);
|
|
free(n->val);
|
|
}
|
|
free(h);
|
|
}
|
|
|
|
void
|
|
hmapset(Hmap **store, Str *key, const char *val, int vlen)
|
|
{
|
|
char *newval;
|
|
Hnode *n;
|
|
uchar *v;
|
|
Hmap *h;
|
|
int next;
|
|
vlong diff;
|
|
|
|
if(store == nil || *store == nil || key == nil ||
|
|
key->n < 0 || key->n > Maxrunes || vlen < 0 ||
|
|
(vlen > 0 && val == nil))
|
|
return;
|
|
newval = memdup(val, vlen);
|
|
h = *store;
|
|
v = h->nodes + (hash(key) % h->nbs) * h->nsz;
|
|
for(;;){
|
|
n = (Hnode*)v;
|
|
next = n->next;
|
|
if(n->filled == 0)
|
|
goto replace;
|
|
if(keycmp(n, key) == 0)
|
|
goto replace;
|
|
if(next == 0)
|
|
break;
|
|
v = h->nodes + next * h->nsz;
|
|
}
|
|
if(h->cap == h->len){
|
|
diff = v - h->nodes;
|
|
h->cap *= 2;
|
|
*store = erealloc(*store, sizeof(*h) + h->cap * h->nsz);
|
|
h = *store;
|
|
h->nodes = (uchar*)*store + sizeof(*h);
|
|
v = h->nodes + diff;
|
|
n = (Hnode*)v;
|
|
}
|
|
n->next = h->len;
|
|
memset(h->nodes + h->len * h->nsz, 0, h->nsz);
|
|
h->len++;
|
|
v = h->nodes + n->next * h->nsz;
|
|
n = (Hnode*)v;
|
|
replace:
|
|
if(n->filled == 0){
|
|
n->key = sdup(key, &n->klen);
|
|
n->filled = 1;
|
|
}
|
|
n->next = next;
|
|
free(n->val);
|
|
n->val = newval;
|
|
n->vlen = vlen;
|
|
}
|