| // 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); |