1
0
mirror of https://github.com/golang/go synced 2024-10-02 18:18:33 -06:00
go/src/pkg/runtime/hashmap.h
Russ Cox 196b663075 gc: implement == on structs and arrays
To allow these types as map keys, we must fill in
equal and hash functions in their algorithm tables.
Structs or arrays that are "just memory", like [2]int,
can and do continue to use the AMEM algorithm.
Structs or arrays that contain special values like
strings or interface values use generated functions
for both equal and hash.

The runtime helper func runtime.equal(t, x, y) bool handles
the general equality case for x == y and calls out to
the equal implementation in the algorithm table.

For short values (<= 4 struct fields or array elements),
the sequence of elementwise comparisons is inlined
instead of calling runtime.equal.

R=ken, mpimenov
CC=golang-dev
https://golang.org/cl/5451105
2011-12-12 22:22:09 -05:00

163 lines
6.0 KiB
C

// 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 runtime·mal
#define memset(a,b,c) runtime·memclr((byte*)(a), (uint32)(c))
#define memcpy(a,b,c) runtime·memmove((byte*)(a),(byte*)(b),(uint32)(c))
#define assert(a) if(!(a)) runtime·throw("hashmap assert")
#define free(x) runtime·free(x)
#define memmove(a,b,c) runtime·memmove(a, b, c)
struct Hmap; /* opaque */
struct hash_subtable; /* opaque */
struct hash_entry; /* opaque */
typedef uintptr uintptr_t;
typedef uintptr_t hash_hash_t;
struct hash_iter {
uint8* data; /* returned from next */
int32 elemsize; /* size of elements in table */
int32 changes; /* number of changes observed last time */
int32 i; /* stack pointer in subtable_state */
bool cycled; /* have reached the end and wrapped to 0 */
hash_hash_t last_hash; /* last hash value returned */
hash_hash_t cycle; /* hash value where we started */
struct Hmap *h; /* the hash table */
MapType *t; /* the map type */
struct hash_iter_sub {
struct hash_entry *e; /* pointer into subtable */
struct hash_entry *start; /* start of subtable */
struct hash_entry *last; /* last entry in subtable */
} subtable_state[4]; /* 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);