xref: /freebsd/contrib/bmake/hash.c (revision 0b46a53a2f50b5ab0f4598104119a049b9c42cc9)
1*0b46a53aSSimon J. Gerraty /*	$NetBSD: hash.c,v 1.80 2025/04/22 19:28:50 rillig Exp $	*/
23955d011SMarcel Moolenaar 
33955d011SMarcel Moolenaar /*
43955d011SMarcel Moolenaar  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
53955d011SMarcel Moolenaar  * All rights reserved.
63955d011SMarcel Moolenaar  *
73955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
83955d011SMarcel Moolenaar  * Adam de Boor.
93955d011SMarcel Moolenaar  *
103955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
113955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
123955d011SMarcel Moolenaar  * are met:
133955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
143955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
153955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
163955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
173955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
183955d011SMarcel Moolenaar  * 3. Neither the name of the University nor the names of its contributors
193955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
203955d011SMarcel Moolenaar  *    without specific prior written permission.
213955d011SMarcel Moolenaar  *
223955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
233955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
273955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
283955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323955d011SMarcel Moolenaar  * SUCH DAMAGE.
333955d011SMarcel Moolenaar  */
343955d011SMarcel Moolenaar 
353955d011SMarcel Moolenaar /*
363955d011SMarcel Moolenaar  * Copyright (c) 1988, 1989 by Adam de Boor
373955d011SMarcel Moolenaar  * Copyright (c) 1989 by Berkeley Softworks
383955d011SMarcel Moolenaar  * All rights reserved.
393955d011SMarcel Moolenaar  *
403955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
413955d011SMarcel Moolenaar  * Adam de Boor.
423955d011SMarcel Moolenaar  *
433955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
443955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
453955d011SMarcel Moolenaar  * are met:
463955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
473955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
483955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
493955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
503955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
513955d011SMarcel Moolenaar  * 3. All advertising materials mentioning features or use of this software
523955d011SMarcel Moolenaar  *    must display the following acknowledgement:
533955d011SMarcel Moolenaar  *	This product includes software developed by the University of
543955d011SMarcel Moolenaar  *	California, Berkeley and its contributors.
553955d011SMarcel Moolenaar  * 4. Neither the name of the University nor the names of its contributors
563955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
573955d011SMarcel Moolenaar  *    without specific prior written permission.
583955d011SMarcel Moolenaar  *
593955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
603955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
613955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
623955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
633955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
643955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
653955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
663955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
673955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
683955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
693955d011SMarcel Moolenaar  * SUCH DAMAGE.
703955d011SMarcel Moolenaar  */
713955d011SMarcel Moolenaar 
72d5e0a182SSimon J. Gerraty /* Hash tables with string keys and pointer values. */
733955d011SMarcel Moolenaar 
743955d011SMarcel Moolenaar #include "make.h"
753955d011SMarcel Moolenaar 
76956e45f6SSimon J. Gerraty /*	"@(#)hash.c	8.1 (Berkeley) 6/6/93"	*/
77*0b46a53aSSimon J. Gerraty MAKE_RCSID("$NetBSD: hash.c,v 1.80 2025/04/22 19:28:50 rillig Exp $");
783955d011SMarcel Moolenaar 
793955d011SMarcel Moolenaar /*
80956e45f6SSimon J. Gerraty  * The ratio of # entries to # buckets at which we rebuild the table to
81956e45f6SSimon J. Gerraty  * make it larger.
823955d011SMarcel Moolenaar  */
833955d011SMarcel Moolenaar #define rebuildLimit 3
843955d011SMarcel Moolenaar 
85dba7b0efSSimon J. Gerraty /* This hash function matches Gosling's Emacs and java.lang.String. */
86*0b46a53aSSimon J. Gerraty static unsigned
Hash_String(const char * key,const char ** out_keyEnd)879f45a3c8SSimon J. Gerraty Hash_String(const char *key, const char **out_keyEnd)
88956e45f6SSimon J. Gerraty {
89*0b46a53aSSimon J. Gerraty 	unsigned h;
9006b9b3e0SSimon J. Gerraty 	const char *p;
9106b9b3e0SSimon J. Gerraty 
9206b9b3e0SSimon J. Gerraty 	h = 0;
9306b9b3e0SSimon J. Gerraty 	for (p = key; *p != '\0'; p++)
9406b9b3e0SSimon J. Gerraty 		h = 31 * h + (unsigned char)*p;
9506b9b3e0SSimon J. Gerraty 
969f45a3c8SSimon J. Gerraty 	*out_keyEnd = p;
97956e45f6SSimon J. Gerraty 	return h;
98956e45f6SSimon J. Gerraty }
992c3632d1SSimon J. Gerraty 
100b0c40a00SSimon J. Gerraty /* This hash function matches Gosling's Emacs and java.lang.String. */
101*0b46a53aSSimon J. Gerraty unsigned
Hash_Substring(Substring key)102b0c40a00SSimon J. Gerraty Hash_Substring(Substring key)
103956e45f6SSimon J. Gerraty {
104*0b46a53aSSimon J. Gerraty 	unsigned h;
105b0c40a00SSimon J. Gerraty 	const char *p;
106b0c40a00SSimon J. Gerraty 
107b0c40a00SSimon J. Gerraty 	h = 0;
108b0c40a00SSimon J. Gerraty 	for (p = key.start; p != key.end; p++)
109b0c40a00SSimon J. Gerraty 		h = 31 * h + (unsigned char)*p;
110b0c40a00SSimon J. Gerraty 	return h;
111956e45f6SSimon J. Gerraty }
1122c3632d1SSimon J. Gerraty 
113956e45f6SSimon J. Gerraty static HashEntry *
HashTable_Find(HashTable * t,Substring key,unsigned h)114*0b46a53aSSimon J. Gerraty HashTable_Find(HashTable *t, Substring key, unsigned h)
115956e45f6SSimon J. Gerraty {
116d5e0a182SSimon J. Gerraty 	HashEntry *he;
1179f45a3c8SSimon J. Gerraty 	size_t keyLen = Substring_Length(key);
118956e45f6SSimon J. Gerraty 
119956e45f6SSimon J. Gerraty #ifdef DEBUG_HASH_LOOKUP
1209f45a3c8SSimon J. Gerraty 	DEBUG4(HASH, "HashTable_Find: %p h=%08x key=%.*s\n",
1219f45a3c8SSimon J. Gerraty 	    t, h, (int)keyLen, key.start);
1222c3632d1SSimon J. Gerraty #endif
1232c3632d1SSimon J. Gerraty 
124d5e0a182SSimon J. Gerraty 	for (he = t->buckets[h & t->bucketsMask]; he != NULL; he = he->next) {
125d5e0a182SSimon J. Gerraty 		if (he->hash == h &&
126d5e0a182SSimon J. Gerraty 		    strncmp(he->key, key.start, keyLen) == 0 &&
127d5e0a182SSimon J. Gerraty 		    he->key[keyLen] == '\0')
128b0c40a00SSimon J. Gerraty 			break;
129b0c40a00SSimon J. Gerraty 	}
130b0c40a00SSimon J. Gerraty 
131d5e0a182SSimon J. Gerraty 	return he;
132b0c40a00SSimon J. Gerraty }
133b0c40a00SSimon J. Gerraty 
134956e45f6SSimon J. Gerraty /* Set up the hash table. */
135956e45f6SSimon J. Gerraty void
HashTable_Init(HashTable * t)136956e45f6SSimon J. Gerraty HashTable_Init(HashTable *t)
137956e45f6SSimon J. Gerraty {
138*0b46a53aSSimon J. Gerraty 	unsigned n = 16, i;
139e2eeea75SSimon J. Gerraty 	HashEntry **buckets = bmake_malloc(sizeof *buckets * n);
140956e45f6SSimon J. Gerraty 	for (i = 0; i < n; i++)
141956e45f6SSimon J. Gerraty 		buckets[i] = NULL;
142956e45f6SSimon J. Gerraty 
143956e45f6SSimon J. Gerraty 	t->buckets = buckets;
144956e45f6SSimon J. Gerraty 	t->bucketsSize = n;
1453955d011SMarcel Moolenaar 	t->numEntries = 0;
146956e45f6SSimon J. Gerraty 	t->bucketsMask = n - 1;
1473955d011SMarcel Moolenaar }
1483955d011SMarcel Moolenaar 
149dba7b0efSSimon J. Gerraty /*
150dba7b0efSSimon J. Gerraty  * Remove everything from the hash table and free up the memory for the keys
151dba7b0efSSimon J. Gerraty  * of the hash table, but not for the values associated to these keys.
152dba7b0efSSimon J. Gerraty  */
1533955d011SMarcel Moolenaar void
HashTable_Done(HashTable * t)154956e45f6SSimon J. Gerraty HashTable_Done(HashTable *t)
1553955d011SMarcel Moolenaar {
156956e45f6SSimon J. Gerraty 	HashEntry **buckets = t->buckets;
157956e45f6SSimon J. Gerraty 	size_t i, n = t->bucketsSize;
1583955d011SMarcel Moolenaar 
159956e45f6SSimon J. Gerraty 	for (i = 0; i < n; i++) {
160956e45f6SSimon J. Gerraty 		HashEntry *he = buckets[i];
161956e45f6SSimon J. Gerraty 		while (he != NULL) {
162956e45f6SSimon J. Gerraty 			HashEntry *next = he->next;
163956e45f6SSimon J. Gerraty 			free(he);
164956e45f6SSimon J. Gerraty 			he = next;
1653955d011SMarcel Moolenaar 		}
1663955d011SMarcel Moolenaar 	}
1673955d011SMarcel Moolenaar 
168dba7b0efSSimon J. Gerraty 	free(t->buckets);
169956e45f6SSimon J. Gerraty #ifdef CLEANUP
1702c3632d1SSimon J. Gerraty 	t->buckets = NULL;
1712c3632d1SSimon J. Gerraty #endif
1723955d011SMarcel Moolenaar }
1733955d011SMarcel Moolenaar 
174956e45f6SSimon J. Gerraty /* Find the entry corresponding to the key, or return NULL. */
175956e45f6SSimon J. Gerraty HashEntry *
HashTable_FindEntry(HashTable * t,const char * key)176956e45f6SSimon J. Gerraty HashTable_FindEntry(HashTable *t, const char *key)
1773955d011SMarcel Moolenaar {
1789f45a3c8SSimon J. Gerraty 	const char *keyEnd;
179*0b46a53aSSimon J. Gerraty 	unsigned h = Hash_String(key, &keyEnd);
1809f45a3c8SSimon J. Gerraty 	return HashTable_Find(t, Substring_Init(key, keyEnd), h);
181956e45f6SSimon J. Gerraty }
1823955d011SMarcel Moolenaar 
183956e45f6SSimon J. Gerraty /* Find the value corresponding to the key, or return NULL. */
184956e45f6SSimon J. Gerraty void *
HashTable_FindValue(HashTable * t,const char * key)185956e45f6SSimon J. Gerraty HashTable_FindValue(HashTable *t, const char *key)
186956e45f6SSimon J. Gerraty {
187956e45f6SSimon J. Gerraty 	HashEntry *he = HashTable_FindEntry(t, key);
188956e45f6SSimon J. Gerraty 	return he != NULL ? he->value : NULL;
189956e45f6SSimon J. Gerraty }
190956e45f6SSimon J. Gerraty 
19106b9b3e0SSimon J. Gerraty /*
19206b9b3e0SSimon J. Gerraty  * Find the value corresponding to the key and the precomputed hash,
19306b9b3e0SSimon J. Gerraty  * or return NULL.
19406b9b3e0SSimon J. Gerraty  */
195956e45f6SSimon J. Gerraty void *
HashTable_FindValueBySubstringHash(HashTable * t,Substring key,unsigned h)196*0b46a53aSSimon J. Gerraty HashTable_FindValueBySubstringHash(HashTable *t, Substring key, unsigned h)
197956e45f6SSimon J. Gerraty {
1989f45a3c8SSimon J. Gerraty 	HashEntry *he = HashTable_Find(t, key, h);
199956e45f6SSimon J. Gerraty 	return he != NULL ? he->value : NULL;
200956e45f6SSimon J. Gerraty }
201956e45f6SSimon J. Gerraty 
20222619282SSimon J. Gerraty static unsigned
HashTable_MaxChain(const HashTable * t)20322619282SSimon J. Gerraty HashTable_MaxChain(const HashTable *t)
20422619282SSimon J. Gerraty {
20522619282SSimon J. Gerraty 	unsigned b, cl, max_cl = 0;
20622619282SSimon J. Gerraty 	for (b = 0; b < t->bucketsSize; b++) {
20722619282SSimon J. Gerraty 		const HashEntry *he = t->buckets[b];
20822619282SSimon J. Gerraty 		for (cl = 0; he != NULL; he = he->next)
20922619282SSimon J. Gerraty 			cl++;
21022619282SSimon J. Gerraty 		if (cl > max_cl)
21122619282SSimon J. Gerraty 			max_cl = cl;
21222619282SSimon J. Gerraty 	}
21322619282SSimon J. Gerraty 	return max_cl;
21422619282SSimon J. Gerraty }
21522619282SSimon J. Gerraty 
21606b9b3e0SSimon J. Gerraty /*
21706b9b3e0SSimon J. Gerraty  * Make the hash table larger. Any bucket numbers from the old table become
218d5e0a182SSimon J. Gerraty  * invalid; the hash values stay valid though.
21906b9b3e0SSimon J. Gerraty  */
220956e45f6SSimon J. Gerraty static void
HashTable_Enlarge(HashTable * t)221956e45f6SSimon J. Gerraty HashTable_Enlarge(HashTable *t)
222956e45f6SSimon J. Gerraty {
223*0b46a53aSSimon J. Gerraty 	unsigned oldSize = t->bucketsSize;
224956e45f6SSimon J. Gerraty 	HashEntry **oldBuckets = t->buckets;
225*0b46a53aSSimon J. Gerraty 	unsigned newSize = 2 * oldSize;
226*0b46a53aSSimon J. Gerraty 	unsigned newMask = newSize - 1;
227e2eeea75SSimon J. Gerraty 	HashEntry **newBuckets = bmake_malloc(sizeof *newBuckets * newSize);
228956e45f6SSimon J. Gerraty 	size_t i;
229956e45f6SSimon J. Gerraty 
230956e45f6SSimon J. Gerraty 	for (i = 0; i < newSize; i++)
231956e45f6SSimon J. Gerraty 		newBuckets[i] = NULL;
232956e45f6SSimon J. Gerraty 
233956e45f6SSimon J. Gerraty 	for (i = 0; i < oldSize; i++) {
234956e45f6SSimon J. Gerraty 		HashEntry *he = oldBuckets[i];
235956e45f6SSimon J. Gerraty 		while (he != NULL) {
236956e45f6SSimon J. Gerraty 			HashEntry *next = he->next;
237d5e0a182SSimon J. Gerraty 			he->next = newBuckets[he->hash & newMask];
238d5e0a182SSimon J. Gerraty 			newBuckets[he->hash & newMask] = he;
239956e45f6SSimon J. Gerraty 			he = next;
2402c3632d1SSimon J. Gerraty 		}
2412c3632d1SSimon J. Gerraty 	}
2423955d011SMarcel Moolenaar 
243956e45f6SSimon J. Gerraty 	free(oldBuckets);
244956e45f6SSimon J. Gerraty 
245956e45f6SSimon J. Gerraty 	t->bucketsSize = newSize;
246956e45f6SSimon J. Gerraty 	t->bucketsMask = newMask;
247956e45f6SSimon J. Gerraty 	t->buckets = newBuckets;
2489f45a3c8SSimon J. Gerraty 	DEBUG4(HASH, "HashTable_Enlarge: %p size=%d entries=%d maxchain=%d\n",
24922619282SSimon J. Gerraty 	    (void *)t, t->bucketsSize, t->numEntries, HashTable_MaxChain(t));
250956e45f6SSimon J. Gerraty }
251956e45f6SSimon J. Gerraty 
25206b9b3e0SSimon J. Gerraty /*
25306b9b3e0SSimon J. Gerraty  * Find or create an entry corresponding to the key.
25406b9b3e0SSimon J. Gerraty  * Return in out_isNew whether a new entry has been created.
25506b9b3e0SSimon J. Gerraty  */
256956e45f6SSimon J. Gerraty HashEntry *
HashTable_CreateEntry(HashTable * t,const char * key,bool * out_isNew)257b0c40a00SSimon J. Gerraty HashTable_CreateEntry(HashTable *t, const char *key, bool *out_isNew)
258956e45f6SSimon J. Gerraty {
2599f45a3c8SSimon J. Gerraty 	const char *keyEnd;
260*0b46a53aSSimon J. Gerraty 	unsigned h = Hash_String(key, &keyEnd);
2619f45a3c8SSimon J. Gerraty 	HashEntry *he = HashTable_Find(t, Substring_Init(key, keyEnd), h);
262956e45f6SSimon J. Gerraty 
263956e45f6SSimon J. Gerraty 	if (he != NULL) {
264956e45f6SSimon J. Gerraty 		if (out_isNew != NULL)
265b0c40a00SSimon J. Gerraty 			*out_isNew = false;
266956e45f6SSimon J. Gerraty 		return he;
267956e45f6SSimon J. Gerraty 	}
268956e45f6SSimon J. Gerraty 
2692c3632d1SSimon J. Gerraty 	if (t->numEntries >= rebuildLimit * t->bucketsSize)
270956e45f6SSimon J. Gerraty 		HashTable_Enlarge(t);
271956e45f6SSimon J. Gerraty 
2729f45a3c8SSimon J. Gerraty 	he = bmake_malloc(sizeof *he + (size_t)(keyEnd - key));
273956e45f6SSimon J. Gerraty 	he->value = NULL;
274d5e0a182SSimon J. Gerraty 	he->hash = h;
2759f45a3c8SSimon J. Gerraty 	memcpy(he->key, key, (size_t)(keyEnd - key) + 1);
276956e45f6SSimon J. Gerraty 
277956e45f6SSimon J. Gerraty 	he->next = t->buckets[h & t->bucketsMask];
278956e45f6SSimon J. Gerraty 	t->buckets[h & t->bucketsMask] = he;
2793955d011SMarcel Moolenaar 	t->numEntries++;
2803955d011SMarcel Moolenaar 
281956e45f6SSimon J. Gerraty 	if (out_isNew != NULL)
282b0c40a00SSimon J. Gerraty 		*out_isNew = true;
283956e45f6SSimon J. Gerraty 	return he;
2843955d011SMarcel Moolenaar }
2853955d011SMarcel Moolenaar 
2869f45a3c8SSimon J. Gerraty void
HashTable_Set(HashTable * t,const char * key,void * value)287e2eeea75SSimon J. Gerraty HashTable_Set(HashTable *t, const char *key, void *value)
288e2eeea75SSimon J. Gerraty {
289e2eeea75SSimon J. Gerraty 	HashEntry *he = HashTable_CreateEntry(t, key, NULL);
290e2eeea75SSimon J. Gerraty 	HashEntry_Set(he, value);
291e2eeea75SSimon J. Gerraty }
292e2eeea75SSimon J. Gerraty 
2931d3f2ddcSSimon J. Gerraty /* Delete the entry from the table, don't free the value of the entry. */
2943955d011SMarcel Moolenaar void
HashTable_DeleteEntry(HashTable * t,HashEntry * he)295956e45f6SSimon J. Gerraty HashTable_DeleteEntry(HashTable *t, HashEntry *he)
2963955d011SMarcel Moolenaar {
297d5e0a182SSimon J. Gerraty 	HashEntry **ref = &t->buckets[he->hash & t->bucketsMask];
2983955d011SMarcel Moolenaar 
2998d5c8e21SSimon J. Gerraty 	for (; *ref != he; ref = &(*ref)->next)
3008d5c8e21SSimon J. Gerraty 		continue;
3018d5c8e21SSimon J. Gerraty 	*ref = he->next;
3028d5c8e21SSimon J. Gerraty 	free(he);
3033955d011SMarcel Moolenaar 	t->numEntries--;
3043955d011SMarcel Moolenaar }
3053955d011SMarcel Moolenaar 
30606b9b3e0SSimon J. Gerraty /*
3078d5c8e21SSimon J. Gerraty  * Place the next entry from the hash table in hi->entry, or return false if
3088d5c8e21SSimon J. Gerraty  * the end of the table is reached.
30906b9b3e0SSimon J. Gerraty  */
3108d5c8e21SSimon J. Gerraty bool
HashIter_Next(HashIter * hi)311956e45f6SSimon J. Gerraty HashIter_Next(HashIter *hi)
3123955d011SMarcel Moolenaar {
313956e45f6SSimon J. Gerraty 	HashTable *t = hi->table;
314956e45f6SSimon J. Gerraty 	HashEntry *he = hi->entry;
315956e45f6SSimon J. Gerraty 	HashEntry **buckets = t->buckets;
316*0b46a53aSSimon J. Gerraty 	unsigned bucketsSize = t->bucketsSize;
3173955d011SMarcel Moolenaar 
318956e45f6SSimon J. Gerraty 	if (he != NULL)
319956e45f6SSimon J. Gerraty 		he = he->next;	/* skip the most recently returned entry */
320956e45f6SSimon J. Gerraty 
321956e45f6SSimon J. Gerraty 	while (he == NULL) {	/* find the next nonempty chain */
322956e45f6SSimon J. Gerraty 		if (hi->nextBucket >= bucketsSize)
3238d5c8e21SSimon J. Gerraty 			return false;
324956e45f6SSimon J. Gerraty 		he = buckets[hi->nextBucket++];
3253955d011SMarcel Moolenaar 	}
326956e45f6SSimon J. Gerraty 	hi->entry = he;
3278d5c8e21SSimon J. Gerraty 	return true;
3283955d011SMarcel Moolenaar }
3293841c287SSimon J. Gerraty 
3302c3632d1SSimon J. Gerraty void
HashTable_DebugStats(const HashTable * t,const char * name)33122619282SSimon J. Gerraty HashTable_DebugStats(const HashTable *t, const char *name)
3323841c287SSimon J. Gerraty {
33322619282SSimon J. Gerraty 	DEBUG4(HASH, "HashTable \"%s\": size=%u entries=%u maxchain=%u\n",
33422619282SSimon J. Gerraty 	    name, t->bucketsSize, t->numEntries, HashTable_MaxChain(t));
3352c3632d1SSimon J. Gerraty }
336