diff options
Diffstat (limited to 'contrib/bmake/hash.c')
-rw-r--r-- | contrib/bmake/hash.c | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/contrib/bmake/hash.c b/contrib/bmake/hash.c new file mode 100644 index 000000000000..2a75fb32b50e --- /dev/null +++ b/contrib/bmake/hash.c @@ -0,0 +1,310 @@ +/* $NetBSD: hash.c,v 1.55 2020/10/25 19:28:44 rillig Exp $ */ + +/* + * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam de Boor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1988, 1989 by Adam de Boor + * Copyright (c) 1989 by Berkeley Softworks + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam de Boor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Hash tables with string keys. */ + +#include "make.h" + +/* "@(#)hash.c 8.1 (Berkeley) 6/6/93" */ +MAKE_RCSID("$NetBSD: hash.c,v 1.55 2020/10/25 19:28:44 rillig Exp $"); + +/* + * The ratio of # entries to # buckets at which we rebuild the table to + * make it larger. + */ +#define rebuildLimit 3 + +/* This hash function matches Gosling's emacs and java.lang.String. */ +static unsigned int +hash(const char *key, size_t *out_keylen) +{ + unsigned int h = 0; + const char *p = key; + while (*p != '\0') + h = (h << 5) - h + (unsigned char)*p++; + if (out_keylen != NULL) + *out_keylen = (size_t)(p - key); + return h; +} + +unsigned int +Hash_Hash(const char *key) +{ + return hash(key, NULL); +} + +static HashEntry * +HashTable_Find(HashTable *t, unsigned int h, const char *key) +{ + HashEntry *e; + unsigned int chainlen = 0; + +#ifdef DEBUG_HASH_LOOKUP + DEBUG4(HASH, "%s: %p h=%08x key=%s\n", __func__, t, h, key); +#endif + + for (e = t->buckets[h & t->bucketsMask]; e != NULL; e = e->next) { + chainlen++; + if (e->key_hash == h && strcmp(e->key, key) == 0) + break; + } + + if (chainlen > t->maxchain) + t->maxchain = chainlen; + + return e; +} + +/* Set up the hash table. */ +void +HashTable_Init(HashTable *t) +{ + unsigned int n = 16, i; + HashEntry **buckets = bmake_malloc(sizeof(*buckets) * n); + for (i = 0; i < n; i++) + buckets[i] = NULL; + + t->buckets = buckets; + t->bucketsSize = n; + t->numEntries = 0; + t->bucketsMask = n - 1; + t->maxchain = 0; +} + +/* Remove everything from the hash table and frees up the memory. */ +void +HashTable_Done(HashTable *t) +{ + HashEntry **buckets = t->buckets; + size_t i, n = t->bucketsSize; + + for (i = 0; i < n; i++) { + HashEntry *he = buckets[i]; + while (he != NULL) { + HashEntry *next = he->next; + free(he); + he = next; + } + } + free(t->buckets); + +#ifdef CLEANUP + t->buckets = NULL; +#endif +} + +/* Find the entry corresponding to the key, or return NULL. */ +HashEntry * +HashTable_FindEntry(HashTable *t, const char *key) +{ + unsigned int h = hash(key, NULL); + return HashTable_Find(t, h, key); +} + +/* Find the value corresponding to the key, or return NULL. */ +void * +HashTable_FindValue(HashTable *t, const char *key) +{ + HashEntry *he = HashTable_FindEntry(t, key); + return he != NULL ? he->value : NULL; +} + +/* Find the value corresponding to the key and the precomputed hash, + * or return NULL. */ +void * +HashTable_FindValueHash(HashTable *t, const char *key, unsigned int h) +{ + HashEntry *he = HashTable_Find(t, h, key); + return he != NULL ? he->value : NULL; +} + +/* Make the hash table larger. Any bucket numbers from the old table become + * invalid; the hash codes stay valid though. */ +static void +HashTable_Enlarge(HashTable *t) +{ + unsigned int oldSize = t->bucketsSize; + HashEntry **oldBuckets = t->buckets; + unsigned int newSize = 2 * oldSize; + unsigned int newMask = newSize - 1; + HashEntry **newBuckets = bmake_malloc(sizeof(*newBuckets) * newSize); + size_t i; + + for (i = 0; i < newSize; i++) + newBuckets[i] = NULL; + + for (i = 0; i < oldSize; i++) { + HashEntry *he = oldBuckets[i]; + while (he != NULL) { + HashEntry *next = he->next; + he->next = newBuckets[he->key_hash & newMask]; + newBuckets[he->key_hash & newMask] = he; + he = next; + } + } + + free(oldBuckets); + + t->bucketsSize = newSize; + t->bucketsMask = newMask; + t->buckets = newBuckets; + DEBUG5(HASH, "%s: %p size=%d entries=%d maxchain=%d\n", + __func__, t, t->bucketsSize, t->numEntries, t->maxchain); + t->maxchain = 0; +} + +/* Find or create an entry corresponding to the key. + * Return in out_isNew whether a new entry has been created. */ +HashEntry * +HashTable_CreateEntry(HashTable *t, const char *key, Boolean *out_isNew) +{ + size_t keylen; + unsigned int h = hash(key, &keylen); + HashEntry *he = HashTable_Find(t, h, key); + + if (he != NULL) { + if (out_isNew != NULL) + *out_isNew = FALSE; + return he; + } + + if (t->numEntries >= rebuildLimit * t->bucketsSize) + HashTable_Enlarge(t); + + he = bmake_malloc(sizeof(*he) + keylen); + he->value = NULL; + he->key_hash = h; + memcpy(he->key, key, keylen + 1); + + he->next = t->buckets[h & t->bucketsMask]; + t->buckets[h & t->bucketsMask] = he; + t->numEntries++; + + if (out_isNew != NULL) + *out_isNew = TRUE; + return he; +} + +/* Delete the entry from the table and free the associated memory. */ +void +HashTable_DeleteEntry(HashTable *t, HashEntry *he) +{ + HashEntry **ref = &t->buckets[he->key_hash & t->bucketsMask]; + HashEntry *p; + + for (; (p = *ref) != NULL; ref = &p->next) { + if (p == he) { + *ref = p->next; + free(p); + t->numEntries--; + return; + } + } + abort(); +} + +/* Set things up for iterating over all entries in the hash table. */ +void +HashIter_Init(HashIter *hi, HashTable *t) +{ + hi->table = t; + hi->nextBucket = 0; + hi->entry = NULL; +} + +/* Return the next entry in the hash table, or NULL if the end of the table + * is reached. */ +HashEntry * +HashIter_Next(HashIter *hi) +{ + HashTable *t = hi->table; + HashEntry *he = hi->entry; + HashEntry **buckets = t->buckets; + unsigned int bucketsSize = t->bucketsSize; + + if (he != NULL) + he = he->next; /* skip the most recently returned entry */ + + while (he == NULL) { /* find the next nonempty chain */ + if (hi->nextBucket >= bucketsSize) + return NULL; + he = buckets[hi->nextBucket++]; + } + hi->entry = he; + return he; +} + +void +HashTable_DebugStats(HashTable *t, const char *name) +{ + DEBUG4(HASH, "HashTable %s: size=%u numEntries=%u maxchain=%u\n", + name, t->bucketsSize, t->numEntries, t->maxchain); +} |