| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: hash.c,v 1.28 2020/08/28 20:16:19 rillig Exp $ */ | | 1 | /* $NetBSD: hash.c,v 1.29 2020/09/01 21:11:31 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | | 4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Adam de Boor. | | 8 | * Adam de Boor. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -60,34 +60,34 @@ | | | @@ -60,34 +60,34 @@ |
60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
69 | * SUCH DAMAGE. | | 69 | * SUCH DAMAGE. |
70 | */ | | 70 | */ |
71 | | | 71 | |
72 | #ifndef MAKE_NATIVE | | 72 | #ifndef MAKE_NATIVE |
73 | static char rcsid[] = "$NetBSD: hash.c,v 1.28 2020/08/28 20:16:19 rillig Exp $"; | | 73 | static char rcsid[] = "$NetBSD: hash.c,v 1.29 2020/09/01 21:11:31 rillig Exp $"; |
74 | #else | | 74 | #else |
75 | #include <sys/cdefs.h> | | 75 | #include <sys/cdefs.h> |
76 | #ifndef lint | | 76 | #ifndef lint |
77 | #if 0 | | 77 | #if 0 |
78 | static char sccsid[] = "@(#)hash.c 8.1 (Berkeley) 6/6/93"; | | 78 | static char sccsid[] = "@(#)hash.c 8.1 (Berkeley) 6/6/93"; |
79 | #else | | 79 | #else |
80 | __RCSID("$NetBSD: hash.c,v 1.28 2020/08/28 20:16:19 rillig Exp $"); | | 80 | __RCSID("$NetBSD: hash.c,v 1.29 2020/09/01 21:11:31 rillig Exp $"); |
81 | #endif | | 81 | #endif |
82 | #endif /* not lint */ | | 82 | #endif /* not lint */ |
83 | #endif | | 83 | #endif |
84 | | | 84 | |
85 | /* hash.c -- | | 85 | /* hash.c -- |
86 | * | | 86 | * |
87 | * This module contains routines to manipulate a hash table. | | 87 | * This module contains routines to manipulate a hash table. |
88 | * See hash.h for a definition of the structure of the hash | | 88 | * See hash.h for a definition of the structure of the hash |
89 | * table. Hash tables grow automatically as the amount of | | 89 | * table. Hash tables grow automatically as the amount of |
90 | * information increases. | | 90 | * information increases. |
91 | */ | | 91 | */ |
92 | #include "make.h" | | 92 | #include "make.h" |
93 | | | 93 | |
| @@ -132,86 +132,86 @@ Hash_InitTable(Hash_Table *t, int numBuc | | | @@ -132,86 +132,86 @@ Hash_InitTable(Hash_Table *t, int numBuc |
132 | struct Hash_Entry **hp; | | 132 | struct Hash_Entry **hp; |
133 | | | 133 | |
134 | /* | | 134 | /* |
135 | * Round up the size to a power of two. | | 135 | * Round up the size to a power of two. |
136 | */ | | 136 | */ |
137 | if (numBuckets <= 0) | | 137 | if (numBuckets <= 0) |
138 | i = 16; | | 138 | i = 16; |
139 | else { | | 139 | else { |
140 | for (i = 2; i < numBuckets; i <<= 1) | | 140 | for (i = 2; i < numBuckets; i <<= 1) |
141 | continue; | | 141 | continue; |
142 | } | | 142 | } |
143 | t->numEntries = 0; | | 143 | t->numEntries = 0; |
144 | t->maxchain = 0; | | 144 | t->maxchain = 0; |
145 | t->size = i; | | 145 | t->bucketsSize = i; |
146 | t->mask = i - 1; | | 146 | t->bucketsMask = i - 1; |
147 | t->bucketPtr = hp = bmake_malloc(sizeof(*hp) * i); | | 147 | t->buckets = hp = bmake_malloc(sizeof(*hp) * i); |
148 | while (--i >= 0) | | 148 | while (--i >= 0) |
149 | *hp++ = NULL; | | 149 | *hp++ = NULL; |
150 | } | | 150 | } |
151 | | | 151 | |
152 | /* Removes everything from the hash table and frees up the memory space it | | 152 | /* Removes everything from the hash table and frees up the memory space it |
153 | * occupied (except for the space in the Hash_Table structure). */ | | 153 | * occupied (except for the space in the Hash_Table structure). */ |
154 | void | | 154 | void |
155 | Hash_DeleteTable(Hash_Table *t) | | 155 | Hash_DeleteTable(Hash_Table *t) |
156 | { | | 156 | { |
157 | struct Hash_Entry **hp, *h, *nexth = NULL; | | 157 | struct Hash_Entry **hp, *h, *nexth = NULL; |
158 | int i; | | 158 | int i; |
159 | | | 159 | |
160 | for (hp = t->bucketPtr, i = t->size; --i >= 0;) { | | 160 | for (hp = t->buckets, i = t->bucketsSize; --i >= 0;) { |
161 | for (h = *hp++; h != NULL; h = nexth) { | | 161 | for (h = *hp++; h != NULL; h = nexth) { |
162 | nexth = h->next; | | 162 | nexth = h->next; |
163 | free(h); | | 163 | free(h); |
164 | } | | 164 | } |
165 | } | | 165 | } |
166 | free(t->bucketPtr); | | 166 | free(t->buckets); |
167 | | | 167 | |
168 | /* | | 168 | /* |
169 | * Set up the hash table to cause memory faults on any future access | | 169 | * Set up the hash table to cause memory faults on any future access |
170 | * attempts until re-initialization. | | 170 | * attempts until re-initialization. |
171 | */ | | 171 | */ |
172 | t->bucketPtr = NULL; | | 172 | t->buckets = NULL; |
173 | } | | 173 | } |
174 | | | 174 | |
175 | /* Searches the hash table for an entry corresponding to the key. | | 175 | /* Searches the hash table for an entry corresponding to the key. |
176 | * | | 176 | * |
177 | * Input: | | 177 | * Input: |
178 | * t Hash table to search. | | 178 | * t Hash table to search. |
179 | * key A hash key. | | 179 | * key A hash key. |
180 | * | | 180 | * |
181 | * Results: | | 181 | * Results: |
182 | * Returns a pointer to the entry for key, or NULL if the table contains | | 182 | * Returns a pointer to the entry for key, or NULL if the table contains |
183 | * no entry for the key. | | 183 | * no entry for the key. |
184 | */ | | 184 | */ |
185 | Hash_Entry * | | 185 | Hash_Entry * |
186 | Hash_FindEntry(Hash_Table *t, const char *key) | | 186 | Hash_FindEntry(Hash_Table *t, const char *key) |
187 | { | | 187 | { |
188 | Hash_Entry *e; | | 188 | Hash_Entry *e; |
189 | unsigned h; | | 189 | unsigned h; |
190 | const char *p; | | 190 | const char *p; |
191 | int chainlen; | | 191 | int chainlen; |
192 | | | 192 | |
193 | if (t == NULL || t->bucketPtr == NULL) { | | 193 | if (t == NULL || t->buckets == NULL) { |
194 | return NULL; | | 194 | return NULL; |
195 | } | | 195 | } |
196 | HASH(h, key, p); | | 196 | HASH(h, key, p); |
197 | p = key; | | 197 | p = key; |
198 | chainlen = 0; | | 198 | chainlen = 0; |
199 | #ifdef DEBUG_HASH_LOOKUP | | 199 | #ifdef DEBUG_HASH_LOOKUP |
200 | if (DEBUG(HASH)) | | 200 | if (DEBUG(HASH)) |
201 | fprintf(debug_file, "%s: %p h=%x key=%s\n", __func__, | | 201 | fprintf(debug_file, "%s: %p h=%x key=%s\n", __func__, |
202 | t, h, key); | | 202 | t, h, key); |
203 | #endif | | 203 | #endif |
204 | for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) { | | 204 | for (e = t->buckets[h & t->bucketsMask]; e != NULL; e = e->next) { |
205 | chainlen++; | | 205 | chainlen++; |
206 | if (e->namehash == h && strcmp(e->name, p) == 0) | | 206 | if (e->namehash == h && strcmp(e->name, p) == 0) |
207 | break; | | 207 | break; |
208 | } | | 208 | } |
209 | if (chainlen > t->maxchain) | | 209 | if (chainlen > t->maxchain) |
210 | t->maxchain = chainlen; | | 210 | t->maxchain = chainlen; |
211 | return e; | | 211 | return e; |
212 | } | | 212 | } |
213 | | | 213 | |
214 | /* Searches the hash table for an entry corresponding to the key. | | 214 | /* Searches the hash table for an entry corresponding to the key. |
215 | * If no entry is found, then one is created. | | 215 | * If no entry is found, then one is created. |
216 | * | | 216 | * |
217 | * Input: | | 217 | * Input: |
| @@ -233,172 +233,172 @@ Hash_CreateEntry(Hash_Table *t, const ch | | | @@ -233,172 +233,172 @@ Hash_CreateEntry(Hash_Table *t, const ch |
233 | /* | | 233 | /* |
234 | * Hash the key. As a side effect, save the length (strlen) of the | | 234 | * Hash the key. As a side effect, save the length (strlen) of the |
235 | * key in case we need to create the entry. | | 235 | * key in case we need to create the entry. |
236 | */ | | 236 | */ |
237 | HASH(h, key, p); | | 237 | HASH(h, key, p); |
238 | keylen = p - key; | | 238 | keylen = p - key; |
239 | p = key; | | 239 | p = key; |
240 | chainlen = 0; | | 240 | chainlen = 0; |
241 | #ifdef DEBUG_HASH_LOOKUP | | 241 | #ifdef DEBUG_HASH_LOOKUP |
242 | if (DEBUG(HASH)) | | 242 | if (DEBUG(HASH)) |
243 | fprintf(debug_file, "%s: %p h=%x key=%s\n", __func__, | | 243 | fprintf(debug_file, "%s: %p h=%x key=%s\n", __func__, |
244 | t, h, key); | | 244 | t, h, key); |
245 | #endif | | 245 | #endif |
246 | for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) { | | 246 | for (e = t->buckets[h & t->bucketsMask]; e != NULL; e = e->next) { |
247 | chainlen++; | | 247 | chainlen++; |
248 | if (e->namehash == h && strcmp(e->name, p) == 0) { | | 248 | if (e->namehash == h && strcmp(e->name, p) == 0) { |
249 | if (newPtr != NULL) | | 249 | if (newPtr != NULL) |
250 | *newPtr = FALSE; | | 250 | *newPtr = FALSE; |
251 | break; | | 251 | break; |
252 | } | | 252 | } |
253 | } | | 253 | } |
254 | if (chainlen > t->maxchain) | | 254 | if (chainlen > t->maxchain) |
255 | t->maxchain = chainlen; | | 255 | t->maxchain = chainlen; |
256 | if (e) | | 256 | if (e) |
257 | return e; | | 257 | return e; |
258 | | | 258 | |
259 | /* | | 259 | /* |
260 | * The desired entry isn't there. Before allocating a new entry, | | 260 | * The desired entry isn't there. Before allocating a new entry, |
261 | * expand the table if necessary (and this changes the resulting | | 261 | * expand the table if necessary (and this changes the resulting |
262 | * bucket chain). | | 262 | * bucket chain). |
263 | */ | | 263 | */ |
264 | if (t->numEntries >= rebuildLimit * t->size) | | 264 | if (t->numEntries >= rebuildLimit * t->bucketsSize) |
265 | RebuildTable(t); | | 265 | RebuildTable(t); |
266 | e = bmake_malloc(sizeof(*e) + keylen); | | 266 | e = bmake_malloc(sizeof(*e) + keylen); |
267 | hp = &t->bucketPtr[h & t->mask]; | | 267 | hp = &t->buckets[h & t->bucketsMask]; |
268 | e->next = *hp; | | 268 | e->next = *hp; |
269 | *hp = e; | | 269 | *hp = e; |
270 | Hash_SetValue(e, NULL); | | 270 | Hash_SetValue(e, NULL); |
271 | e->namehash = h; | | 271 | e->namehash = h; |
272 | (void)strcpy(e->name, p); | | 272 | (void)strcpy(e->name, p); |
273 | t->numEntries++; | | 273 | t->numEntries++; |
274 | | | 274 | |
275 | if (newPtr != NULL) | | 275 | if (newPtr != NULL) |
276 | *newPtr = TRUE; | | 276 | *newPtr = TRUE; |
277 | return e; | | 277 | return e; |
278 | } | | 278 | } |
279 | | | 279 | |
280 | /* Delete the given hash table entry and free memory associated with it. */ | | 280 | /* Delete the given hash table entry and free memory associated with it. */ |
281 | void | | 281 | void |
282 | Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e) | | 282 | Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e) |
283 | { | | 283 | { |
284 | Hash_Entry **hp, *p; | | 284 | Hash_Entry **hp, *p; |
285 | | | 285 | |
286 | if (e == NULL) | | 286 | if (e == NULL) |
287 | return; | | 287 | return; |
288 | for (hp = &t->bucketPtr[e->namehash & t->mask]; | | 288 | for (hp = &t->buckets[e->namehash & t->bucketsMask]; |
289 | (p = *hp) != NULL; hp = &p->next) { | | 289 | (p = *hp) != NULL; hp = &p->next) { |
290 | if (p == e) { | | 290 | if (p == e) { |
291 | *hp = p->next; | | 291 | *hp = p->next; |
292 | free(p); | | 292 | free(p); |
293 | t->numEntries--; | | 293 | t->numEntries--; |
294 | return; | | 294 | return; |
295 | } | | 295 | } |
296 | } | | 296 | } |
297 | (void)write(2, "bad call to Hash_DeleteEntry\n", 29); | | 297 | (void)write(2, "bad call to Hash_DeleteEntry\n", 29); |
298 | abort(); | | 298 | abort(); |
299 | } | | 299 | } |
300 | | | 300 | |
301 | /* Sets things up for enumerating all entries in the hash table. | | 301 | /* Sets things up for enumerating all entries in the hash table. |
302 | * | | 302 | * |
303 | * Input: | | 303 | * Input: |
304 | * t Table to be searched. | | 304 | * t Table to be searched. |
305 | * searchPtr Area in which to keep state about search. | | 305 | * searchPtr Area in which to keep state about search. |
306 | * | | 306 | * |
307 | * Results: | | 307 | * Results: |
308 | * The return value is the address of the first entry in | | 308 | * The return value is the address of the first entry in |
309 | * the hash table, or NULL if the table is empty. | | 309 | * the hash table, or NULL if the table is empty. |
310 | */ | | 310 | */ |
311 | Hash_Entry * | | 311 | Hash_Entry * |
312 | Hash_EnumFirst(Hash_Table *t, Hash_Search *searchPtr) | | 312 | Hash_EnumFirst(Hash_Table *t, Hash_Search *searchPtr) |
313 | { | | 313 | { |
314 | searchPtr->tablePtr = t; | | 314 | searchPtr->table = t; |
315 | searchPtr->nextIndex = 0; | | 315 | searchPtr->nextBucket = 0; |
316 | searchPtr->hashEntryPtr = NULL; | | 316 | searchPtr->entry = NULL; |
317 | return Hash_EnumNext(searchPtr); | | 317 | return Hash_EnumNext(searchPtr); |
318 | } | | 318 | } |
319 | | | 319 | |
320 | /* Returns the next entry in the hash table, or NULL if the end of the table | | 320 | /* Returns the next entry in the hash table, or NULL if the end of the table |
321 | * is reached. | | 321 | * is reached. |
322 | * | | 322 | * |
323 | * Input: | | 323 | * Input: |
324 | * searchPtr Area used to keep state about search. | | 324 | * searchPtr Area used to keep state about search. |
325 | */ | | 325 | */ |
326 | Hash_Entry * | | 326 | Hash_Entry * |
327 | Hash_EnumNext(Hash_Search *searchPtr) | | 327 | Hash_EnumNext(Hash_Search *searchPtr) |
328 | { | | 328 | { |
329 | Hash_Entry *e; | | 329 | Hash_Entry *e; |
330 | Hash_Table *t = searchPtr->tablePtr; | | 330 | Hash_Table *t = searchPtr->table; |
331 | | | 331 | |
332 | /* | | 332 | /* |
333 | * The hashEntryPtr field points to the most recently returned | | 333 | * The entry field points to the most recently returned |
334 | * entry, or is nil if we are starting up. If not nil, we have | | 334 | * entry, or is NULL if we are starting up. If not NULL, we have |
335 | * to start at the next one in the chain. | | 335 | * to start at the next one in the chain. |
336 | */ | | 336 | */ |
337 | e = searchPtr->hashEntryPtr; | | 337 | e = searchPtr->entry; |
338 | if (e != NULL) | | 338 | if (e != NULL) |
339 | e = e->next; | | 339 | e = e->next; |
340 | /* | | 340 | /* |
341 | * If the chain ran out, or if we are starting up, we need to | | 341 | * If the chain ran out, or if we are starting up, we need to |
342 | * find the next nonempty chain. | | 342 | * find the next nonempty chain. |
343 | */ | | 343 | */ |
344 | while (e == NULL) { | | 344 | while (e == NULL) { |
345 | if (searchPtr->nextIndex >= t->size) | | 345 | if (searchPtr->nextBucket >= t->bucketsSize) |
346 | return NULL; | | 346 | return NULL; |
347 | e = t->bucketPtr[searchPtr->nextIndex++]; | | 347 | e = t->buckets[searchPtr->nextBucket++]; |
348 | } | | 348 | } |
349 | searchPtr->hashEntryPtr = e; | | 349 | searchPtr->entry = e; |
350 | return e; | | 350 | return e; |
351 | } | | 351 | } |
352 | | | 352 | |
353 | /* Makes a new hash table that is larger than the old one. The entire hash | | 353 | /* Makes a new hash table that is larger than the old one. The entire hash |
354 | * table is moved, so any bucket numbers from the old table become invalid. */ | | 354 | * table is moved, so any bucket numbers from the old table become invalid. */ |
355 | static void | | 355 | static void |
356 | RebuildTable(Hash_Table *t) | | 356 | RebuildTable(Hash_Table *t) |
357 | { | | 357 | { |
358 | Hash_Entry *e, *next = NULL, **hp, **xp; | | 358 | Hash_Entry *e, *next = NULL, **hp, **xp; |
359 | int i, mask; | | 359 | int i, mask; |
360 | Hash_Entry **oldhp; | | 360 | Hash_Entry **oldhp; |
361 | int oldsize; | | 361 | int oldsize; |
362 | | | 362 | |
363 | oldhp = t->bucketPtr; | | 363 | oldhp = t->buckets; |
364 | oldsize = i = t->size; | | 364 | oldsize = i = t->bucketsSize; |
365 | i <<= 1; | | 365 | i <<= 1; |
366 | t->size = i; | | 366 | t->bucketsSize = i; |
367 | t->mask = mask = i - 1; | | 367 | t->bucketsMask = mask = i - 1; |
368 | t->bucketPtr = hp = bmake_malloc(sizeof(*hp) * i); | | 368 | t->buckets = hp = bmake_malloc(sizeof(*hp) * i); |
369 | while (--i >= 0) | | 369 | while (--i >= 0) |
370 | *hp++ = NULL; | | 370 | *hp++ = NULL; |
371 | for (hp = oldhp, i = oldsize; --i >= 0;) { | | 371 | for (hp = oldhp, i = oldsize; --i >= 0;) { |
372 | for (e = *hp++; e != NULL; e = next) { | | 372 | for (e = *hp++; e != NULL; e = next) { |
373 | next = e->next; | | 373 | next = e->next; |
374 | xp = &t->bucketPtr[e->namehash & mask]; | | 374 | xp = &t->buckets[e->namehash & mask]; |
375 | e->next = *xp; | | 375 | e->next = *xp; |
376 | *xp = e; | | 376 | *xp = e; |
377 | } | | 377 | } |
378 | } | | 378 | } |
379 | free(oldhp); | | 379 | free(oldhp); |
380 | if (DEBUG(HASH)) | | 380 | if (DEBUG(HASH)) |
381 | fprintf(debug_file, "%s: %p size=%d entries=%d maxchain=%d\n", | | 381 | fprintf(debug_file, "%s: %p size=%d entries=%d maxchain=%d\n", |
382 | __func__, t, t->size, t->numEntries, t->maxchain); | | 382 | __func__, t, t->bucketsSize, t->numEntries, t->maxchain); |
383 | t->maxchain = 0; | | 383 | t->maxchain = 0; |
384 | } | | 384 | } |
385 | | | 385 | |
386 | void | | 386 | void |
387 | Hash_ForEach(Hash_Table *t, void (*action)(void *, void *), void *data) | | 387 | Hash_ForEach(Hash_Table *t, void (*action)(void *, void *), void *data) |
388 | { | | 388 | { |
389 | Hash_Search search; | | 389 | Hash_Search search; |
390 | Hash_Entry *e; | | 390 | Hash_Entry *e; |
391 | | | 391 | |
392 | for (e = Hash_EnumFirst(t, &search); | | 392 | for (e = Hash_EnumFirst(t, &search); |
393 | e != NULL; | | 393 | e != NULL; |
394 | e = Hash_EnumNext(&search)) | | 394 | e = Hash_EnumNext(&search)) |
395 | action(Hash_GetValue(e), data); | | 395 | action(Hash_GetValue(e), data); |
396 | } | | 396 | } |
397 | | | 397 | |
398 | void | | 398 | void |
399 | Hash_DebugStats(Hash_Table *t, const char *name) | | 399 | Hash_DebugStats(Hash_Table *t, const char *name) |
400 | { | | 400 | { |
401 | if (DEBUG(HASH)) | | 401 | if (DEBUG(HASH)) |
402 | fprintf(debug_file, "Hash_Table %s: size=%d numEntries=%d maxchain=%d\n", | | 402 | fprintf(debug_file, "Hash_Table %s: size=%d numEntries=%d maxchain=%d\n", |
403 | name, t->size, t->numEntries, t->maxchain); | | 403 | name, t->bucketsSize, t->numEntries, t->maxchain); |
404 | } | | 404 | } |