Commit bc0b4f0d authored by Ken Thompson's avatar Ken Thompson

mike's map code

R=r
OCL=19146
CL=19146
parent c4d8dc0b
......@@ -18,7 +18,7 @@ LIBOFILES=\
rt2_$(GOARCH).$O\
sys_$(GOARCH)_$(GOOS).$O\
runtime.$O\
map.$O\
hashmap.$O\
chan.$O\
iface.$O\
array.$O\
......@@ -30,7 +30,7 @@ LIBOFILES=\
OFILES=$(RT0OFILES) $(LIBOFILES)
OS_H=$(GOARCH)_$(GOOS).h
HFILES=runtime.h $(OS_H_)
HFILES=runtime.h hashmap.h $(OS_H_)
install: rt0 $(LIB) runtime.acid
cp $(RT0OFILES) $(GOROOT)/lib
......
This diff is collapsed.
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/* A hash table.
Example, hashing nul-terminated char*s:
hash_hash_t str_hash (void *v) {
char *s;
hash_hash_t hash = 0;
for (s = *(char **)v; *s != 0; s++) {
hash = (hash ^ *s) * 2654435769U;
}
return (hash);
}
int str_eq (void *a, void *b) {
return (strcmp (*(char **)a, *(char **)b) == 0);
}
void str_del (void *arg, void *data) {
*(char **)arg = *(char **)data;
}
struct hash *h = hash_new (sizeof (char *), &str_hash, &str_eq, &str_del, 3, 12, 15);
... 3=> 2**3 entries initial size
... 12=> 2**12 entries before sprouting sub-tables
... 15=> number of adjacent probes to attempt before growing
Example lookup:
char *key = "foobar";
char **result_ptr;
if (hash_lookup (h, &key, (void **) &result_ptr)) {
printf ("found in table: %s\n", *result_ptr);
} else {
printf ("not found in table\n");
}
Example insertion:
char *key = strdup ("foobar");
char **result_ptr;
if (hash_lookup (h, &key, (void **) &result_ptr)) {
printf ("found in table: %s\n", *result_ptr);
printf ("to overwrite, do *result_ptr = key\n");
} else {
printf ("not found in table; inserted as %s\n", *result_ptr);
assert (*result_ptr == key);
}
Example deletion:
char *key = "foobar";
char *result;
if (hash_remove (h, &key, &result)) {
printf ("key found and deleted from table\n");
printf ("called str_del (&result, data) to copy data to result: %s\n", result);
} else {
printf ("not found in table\n");
}
Example iteration over the elements of *h:
char **data;
struct hash_iter it;
hash_iter_init (h, &it);
for (data = hash_next (&it); data != 0; data = hash_next (&it)) {
printf ("%s\n", *data);
}
*/
#define malloc mal
#define free(a) USED(a)
#define offsetof(s,m) (uint32)(&(((s*)0)->m))
#define memset(a,b,c) sys·memclr((byte*)(a), (uint32)(c))
#define memmove(a,b,c) mmov((byte*)(a),(byte*)(b),(uint32)(c))
#define memcpy(a,b,c) mcpy((byte*)(a),(byte*)(b),(uint32)(c))
#define assert(a) if(!(a)) throw("assert")
struct hash; /* opaque */
struct hash_subtable; /* opaque */
struct hash_entry; /* opaque */
typedef uint64 uintptr_t;
typedef uintptr_t hash_hash_t;
struct hash_iter {
int32 elemsize; /* size of elements in table */
int32 changes; /* number of changes observed last time */
int32 i; /* stack pointer in subtable_state */
hash_hash_t last_hash; /* last hash value returned */
struct hash *h; /* the hash table */
struct hash_iter_sub {
struct hash_entry *e; /* pointer into subtable */
struct hash_entry *start; /* start of subtable */
struct hash_entry *end; /* end of subtable */
} subtable_state[16]; /* Should be large enough unless the hashing is
so bad that many distinct data values hash
to the same hash value. */
};
/* Return a hashtable h 2**init_power empty entries, each with
"datasize" data bytes.
(*data_hash)(a) should return the hash value of data element *a.
(*data_eq)(a,b) should return whether the data at "a" and the data at "b"
are equal.
(*data_del)(arg, a) will be invoked when data element *a is about to be removed
from the table. "arg" is the argument passed to "hash_remove()".
Growing is accomplished by resizing if the current tables size is less than
a threshold, and by adding subtables otherwise. hint should be set
the expected maximum size of the table.
"datasize" should be in [sizeof (void*), ..., 255]. If you need a
bigger "datasize", store a pointer to another piece of memory. */
//struct hash *hash_new (int32 datasize,
// hash_hash_t (*data_hash) (void *),
// int32 (*data_eq) (void *, void *),
// void (*data_del) (void *, void *),
// int64 hint);
/* Lookup *data in *h. If the data is found, return 1 and place a pointer to
the found element in *pres. Otherwise return 0 and place 0 in *pres. */
int32 hash_lookup (struct hash *h, void *data, void **pres);
/* Lookup *data in *h. If the data is found, execute (*data_del) (arg, p)
where p points to the data in the table, then remove it from *h and return
1. Otherwise return 0. */
int32 hash_remove (struct hash *h, void *data, void *arg);
/* Lookup *data in *h. If the data is found, return 1, and place a pointer
to the found element in *pres. Otherwise, return 0, allocate a region
for the data to be inserted, and place a pointer to the inserted element
in *pres; it is the caller's responsibility to copy the data to be
inserted to the pointer returned in *pres in this case.
If using garbage collection, it is the caller's responsibility to
add references for **pres if HASH_ADDED is returned. */
int32 hash_insert (struct hash *h, void *data, void **pres);
/* Return the number of elements in the table. */
uint32 hash_count (struct hash *h);
/* The following call is useful only if not using garbage collection on the
table.
Remove all sub-tables associated with *h.
This undoes the effects of hash_init().
If other memory pointed to by user data must be freed, the caller is
responsible for doiing do by iterating over *h first; see
hash_iter_init()/hash_next(). */
void hash_destroy (struct hash *h);
/*----- iteration -----*/
/* Initialize *it from *h. */
void hash_iter_init (struct hash *h, struct hash_iter *it);
/* Return the next used entry in the table which which *it was initialized. */
void *hash_next (struct hash_iter *it);
/*---- test interface ----*/
/* Call (*data_visit) (arg, level, data) for every data entry in the table,
whether used or not. "level" is the subtable level, 0 means first level. */
/* TESTING ONLY: DO NOT USE THIS ROUTINE IN NORMAL CODE */
void hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg);
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "runtime.h"
static int32 debug = 0;
typedef struct Link Link;
typedef struct Hmap Hmap;
struct Link
{
Link* link;
byte data[8];
};
struct Hmap
{
uint32 len; // must be first
uint32 keysize;
uint32 valsize;
uint32 hint;
uint32 valoffset;
uint32 ko;
uint32 vo;
uint32 po;
Alg* keyalg;
Alg* valalg;
Link* link;
};
// newmap(keysize uint32, valsize uint32,
// keyalg uint32, valalg uint32,
// hint uint32) (hmap *map[any]any);
void
sys·newmap(uint32 keysize, uint32 valsize,
uint32 keyalg, uint32 valalg, uint32 hint,
Hmap* ret)
{
Hmap *m;
if(keyalg >= 3 ||
valalg >= 3) {
prints("0<=");
sys·printint(keyalg);
prints("<");
sys·printint(nelem(algarray));
prints("\n0<=");
sys·printint(valalg);
prints("<");
sys·printint(nelem(algarray));
prints("\n");
throw("sys·newmap: key/val algorithm out of range");
}
m = mal(sizeof(*m));
m->len = 0;
m->keysize = keysize;
m->valsize = valsize;
m->keyalg = &algarray[keyalg];
m->valalg = &algarray[valalg];
m->hint = hint;
// these calculations are compiler dependent
m->valoffset = rnd(keysize, valsize);
m->ko = rnd(sizeof(m), keysize);
m->vo = rnd(m->ko+keysize, valsize);
m->po = rnd(m->vo+valsize, 1);
ret = m;
FLUSH(&ret);
if(debug) {
prints("newmap: map=");
sys·printpointer(m);
prints("; keysize=");
sys·printint(keysize);
prints("; valsize=");
sys·printint(valsize);
prints("; keyalg=");
sys·printint(keyalg);
prints("; valalg=");
sys·printint(valalg);
prints("; valoffset=");
sys·printint(m->valoffset);
prints("; ko=");
sys·printint(m->ko);
prints("; vo=");
sys·printint(m->vo);
prints("; po=");
sys·printint(m->po);
prints("\n");
}
}
// mapaccess1(hmap *map[any]any, key any) (val any);
void
sys·mapaccess1(Hmap *m, ...)
{
Link *l;
byte *ak, *av;
ak = (byte*)&m + m->ko;
av = (byte*)&m + m->vo;
for(l=m->link; l!=nil; l=l->link) {
if(m->keyalg->equal(m->keysize, ak, l->data)) {
m->valalg->copy(m->valsize, av, l->data+m->valoffset);
goto out;
}
}
m->valalg->copy(m->valsize, av, 0);
throw("sys·mapaccess1: key not in map");
out:
if(debug) {
prints("sys·mapaccess1: map=");
sys·printpointer(m);
prints("; key=");
m->keyalg->print(m->keysize, ak);
prints("; val=");
m->valalg->print(m->valsize, av);
prints("\n");
}
}
// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
void
sys·mapaccess2(Hmap *m, ...)
{
Link *l;
byte *ak, *av, *ap;
ak = (byte*)&m + m->ko;
av = (byte*)&m + m->vo;
ap = (byte*)&m + m->po;
for(l=m->link; l!=nil; l=l->link) {
if(m->keyalg->equal(m->keysize, ak, l->data)) {
*ap = true;
m->valalg->copy(m->valsize, av, l->data+m->valoffset);
goto out;
}
}
*ap = false;
m->valalg->copy(m->valsize, av, nil);
out:
if(debug) {
prints("sys·mapaccess2: map=");
sys·printpointer(m);
prints("; key=");
m->keyalg->print(m->keysize, ak);
prints("; val=");
m->valalg->print(m->valsize, av);
prints("; pres=");
sys·printbool(*ap);
prints("\n");
}
}
static void
sys·mapassign(Hmap *m, byte *ak, byte *av)
{
Link *l;
// mapassign(hmap *map[any]any, key any, val any);
for(l=m->link; l!=nil; l=l->link) {
if(m->keyalg->equal(m->keysize, ak, l->data))
goto out;
}
l = mal((sizeof(*l)-8) + m->keysize + m->valsize);
l->link = m->link;
m->link = l;
m->keyalg->copy(m->keysize, l->data, ak);
m->len++;
out:
m->valalg->copy(m->valsize, l->data+m->valoffset, av);
if(debug) {
prints("mapassign: map=");
sys·printpointer(m);
prints("; key=");
m->keyalg->print(m->keysize, ak);
prints("; val=");
m->valalg->print(m->valsize, av);
prints("\n");
}
}
// mapassign1(hmap *map[any]any, key any, val any);
void
sys·mapassign1(Hmap *m, ...)
{
byte *ak, *av;
ak = (byte*)&m + m->ko;
av = (byte*)&m + m->vo;
sys·mapassign(m, ak, av);
}
// mapassign2(hmap *map[any]any, key any, val any, pres bool);
void
sys·mapassign2(Hmap *m, ...)
{
Link **ll;
byte *ak, *av, *ap;
ak = (byte*)&m + m->ko;
av = (byte*)&m + m->vo;
ap = (byte*)&m + m->po;
if(*ap == true) {
// assign
sys·mapassign(m, ak, av);
return;
}
// delete
for(ll=&m->link; (*ll)!=nil; ll=&(*ll)->link) {
if(m->keyalg->equal(m->keysize, ak, (*ll)->data)) {
m->valalg->copy(m->valsize, (*ll)->data+m->valoffset, nil);
(*ll) = (*ll)->link;
m->len--;
if(debug) {
prints("mapdelete (found): map=");
sys·printpointer(m);
prints("; key=");
m->keyalg->print(m->keysize, ak);
prints("\n");
}
return;
}
}
if(debug) {
prints("mapdelete (not found): map=");
sys·printpointer(m);
prints("; key=");
m->keyalg->print(m->keysize, ak);
prints(" *** not found\n");
}
}
......@@ -87,6 +87,28 @@ mcpy(byte *t, byte *f, uint32 n)
}
}
void
mmov(byte *t, byte *f, uint32 n)
{
if(t < f) {
while(n > 0) {
*t = *f;
t++;
f++;
n--;
}
} else {
t += n;
f += n;
while(n > 0) {
t--;
f--;
*t = *f;
n--;
}
}
}
uint32
rnd(uint32 n, uint32 m)
{
......@@ -582,9 +604,17 @@ check(void)
static uint64
memhash(uint32 s, void *a)
{
USED(s, a);
prints("memhash\n");
return 0x12345;
byte *b;
uint64 hash;
b = a;
hash = 33054211828000289ULL;
while(s > 0) {
hash = (hash ^ *b) * 23344194077549503ULL;
b++;
s--;
}
return hash;
}
static uint32
......@@ -644,9 +674,7 @@ memcopy(uint32 s, void *a, void *b)
static uint64
stringhash(uint32 s, string *a)
{
USED(s, a);
prints("stringhash\n");
return 0x12345;
return memhash((*a)->len, (*a)->str);
}
static uint32
......@@ -677,9 +705,7 @@ stringcopy(uint32 s, string *a, string *b)
static uint64
pointerhash(uint32 s, void **a)
{
USED(s, a);
prints("pointerhash\n");
return 0x12345;
return memhash(s, *a);
}
static uint32
......
......@@ -215,6 +215,7 @@ void throw(int8*);
uint32 rnd(uint32, uint32);
void prints(int8*);
void mcpy(byte*, byte*, uint32);
void mmov(byte*, byte*, uint32);
void* mal(uint32);
uint32 cmpstring(string, string);
void initsig(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment