VirtualBox

source: kBuild/trunk/src/kmk/hash.c@ 3387

Last change on this file since 3387 was 3140, checked in by bird, 6 years ago

kmk: Merged in changes from GNU make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6 / https://git.savannah.gnu.org/git/make.git).

  • Property svn:eol-style set to native
File size: 13.3 KB
Line 
1/* hash.c -- hash table maintenance
2Copyright (C) 1995, 1999, 2002, 2010 Free Software Foundation, Inc.
3Written by Greg McGary <gkm@gnu.org> <greg@mcgary.org>
4
5GNU Make is free software; you can redistribute it and/or modify it under the
6terms of the GNU General Public License as published by the Free Software
7Foundation; either version 3 of the License, or (at your option) any later
8version.
9
10GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "makeint.h"
18#include "hash.h"
19#ifdef CONFIG_WITH_STRCACHE2
20# include <assert.h>
21#endif
22
23#define CALLOC(t, n) ((t *) xcalloc (sizeof (t) * (n)))
24#define MALLOC(t, n) ((t *) xmalloc (sizeof (t) * (n)))
25#define REALLOC(o, t, n) ((t *) xrealloc ((o), sizeof (t) * (n)))
26#define CLONE(o, t, n) ((t *) memcpy (MALLOC (t, (n)), (o), sizeof (t) * (n)))
27
28static void hash_rehash __P((struct hash_table* ht));
29static unsigned long round_up_2 __P((unsigned long rough));
30
31/* Implement double hashing with open addressing. The table size is
32 always a power of two. The secondary ('increment') hash function
33 is forced to return an odd-value, in order to be relatively prime
34 to the table size. This guarantees that the increment can
35 potentially hit every slot in the table during collision
36 resolution. */
37
38void *hash_deleted_item = &hash_deleted_item;
39
40/* Force the table size to be a power of two, possibly rounding up the
41 given size. */
42
43void
44hash_init (struct hash_table *ht, unsigned long size,
45 hash_func_t hash_1, hash_func_t hash_2, hash_cmp_func_t hash_cmp)
46{
47 ht->ht_size = round_up_2 (size);
48 ht->ht_empty_slots = ht->ht_size;
49 ht->ht_vec = (void**) CALLOC (struct token *, ht->ht_size);
50 if (ht->ht_vec == 0)
51 {
52 fprintf (stderr, _("can't allocate %lu bytes for hash table: memory exhausted"),
53 ht->ht_size * (unsigned long) sizeof (struct token *));
54 exit (MAKE_TROUBLE);
55 }
56
57 ht->ht_capacity = ht->ht_size - (ht->ht_size / 16); /* 93.75% loading factor */
58 ht->ht_fill = 0;
59 ht->ht_collisions = 0;
60 ht->ht_lookups = 0;
61 ht->ht_rehashes = 0;
62 ht->ht_hash_1 = hash_1;
63 ht->ht_hash_2 = hash_2;
64 ht->ht_compare = hash_cmp;
65#ifdef CONFIG_WITH_STRCACHE2
66 ht->ht_strcache = 0;
67 ht->ht_off_string = 0;
68#endif
69}
70
71#ifdef CONFIG_WITH_STRCACHE2
72/* Same as hash_init, except that no callbacks are needed since all
73 keys - including the ones being searched for - are from a string
74 cache. This means that any give string will only have one pointer
75 value and that the hash and length can be retrived very cheaply,
76 thus permitting some nice optimizations.
77
78 STRCACHE points to the string cache, while OFF_STRING gives the
79 offset of the string pointer in the item structures the hash table
80 entries points to. */
81void hash_init_strcached (struct hash_table *ht, unsigned long size,
82 struct strcache2 *strcache, unsigned int off_string)
83{
84 hash_init (ht, size, 0, 0, 0);
85 ht->ht_strcache = strcache;
86 ht->ht_off_string = off_string;
87}
88#endif /* CONFIG_WITH_STRCACHE2 */
89
90/* Load an array of items into 'ht'. */
91
92void
93hash_load (struct hash_table *ht, void *item_table,
94 unsigned long cardinality, unsigned long size)
95{
96 char *items = (char *) item_table;
97#ifndef CONFIG_WITH_STRCACHE2
98 while (cardinality--)
99 {
100 hash_insert (ht, items);
101 items += size;
102 }
103#else /* CONFIG_WITH_STRCACHE2 */
104 if (ht->ht_strcache)
105 while (cardinality--)
106 {
107 hash_insert_strcached (ht, items);
108 items += size;
109 }
110 else
111 while (cardinality--)
112 {
113 hash_insert (ht, items);
114 items += size;
115 }
116#endif /* CONFIG_WITH_STRCACHE2 */
117}
118
119/* Returns the address of the table slot matching 'key'. If 'key' is
120 not found, return the address of an empty slot suitable for
121 inserting 'key'. The caller is responsible for incrementing
122 ht_fill on insertion. */
123
124void **
125hash_find_slot (struct hash_table *ht, const void *key)
126{
127 void **slot;
128 void **deleted_slot = 0;
129 unsigned int hash_2 = 0;
130 unsigned int hash_1 = (*ht->ht_hash_1) (key);
131
132#ifdef CONFIG_WITH_STRCACHE2
133 assert (ht->ht_strcache == 0);
134#endif
135
136 MAKE_STATS (ht->ht_lookups++);
137 MAKE_STATS_3 (make_stats_ht_lookups++);
138 for (;;)
139 {
140 hash_1 &= (ht->ht_size - 1);
141 slot = &ht->ht_vec[hash_1];
142
143 if (*slot == 0)
144 return (deleted_slot ? deleted_slot : slot);
145 if (*slot == hash_deleted_item)
146 {
147 if (deleted_slot == 0)
148 deleted_slot = slot;
149 }
150 else
151 {
152 if (key == *slot)
153 return slot;
154 if ((*ht->ht_compare) (key, *slot) == 0)
155 return slot;
156 MAKE_STATS (ht->ht_collisions++);
157 MAKE_STATS_3 (make_stats_ht_collisions++);
158 }
159 if (!hash_2)
160 hash_2 = (*ht->ht_hash_2) (key) | 1;
161 hash_1 += hash_2;
162 }
163}
164
165#ifdef CONFIG_WITH_STRCACHE2
166/* hash_find_slot version for tables created with hash_init_strcached. */
167void **
168hash_find_slot_strcached (struct hash_table *ht, const void *key)
169{
170 void **slot;
171 void **deleted_slot = 0;
172 const char *str1 = *(const char **)((const char *)key + ht->ht_off_string);
173 const char *str2;
174 unsigned int hash_1 = strcache2_calc_ptr_hash (ht->ht_strcache, str1);
175 unsigned int hash_2;
176
177#ifdef CONFIG_WITH_STRCACHE2
178 assert (ht->ht_strcache != 0);
179#endif
180
181 MAKE_STATS (ht->ht_lookups++);
182 MAKE_STATS_3 (make_stats_ht_lookups++);
183
184 /* first iteration unrolled. */
185
186 hash_1 &= (ht->ht_size - 1);
187 slot = &ht->ht_vec[hash_1];
188 if (*slot == 0)
189 return slot;
190 if (*slot != hash_deleted_item)
191 {
192 str2 = *(const char **)((const char *)(*slot) + ht->ht_off_string);
193 if (str1 == str2)
194 return slot;
195
196 MAKE_STATS (ht->ht_collisions++);
197 MAKE_STATS_3 (make_stats_ht_collisions++);
198 }
199 else
200 deleted_slot = slot;
201
202 /* the rest of the loop. */
203
204 hash_2 = strcache2_get_hash (ht->ht_strcache, str1) | 1;
205 hash_1 += hash_2;
206 for (;;)
207 {
208 hash_1 &= (ht->ht_size - 1);
209 slot = &ht->ht_vec[hash_1];
210
211 if (*slot == 0)
212 return (deleted_slot ? deleted_slot : slot);
213 if (*slot == hash_deleted_item)
214 {
215 if (deleted_slot == 0)
216 deleted_slot = slot;
217 }
218 else
219 {
220 str2 = *(const char **)((const char *)(*slot) + ht->ht_off_string);
221 if (str1 == str2)
222 return slot;
223
224 MAKE_STATS (ht->ht_collisions++);
225 MAKE_STATS_3 (make_stats_ht_collisions++);
226 }
227
228 hash_1 += hash_2;
229 }
230}
231#endif /* CONFIG_WITH_STRCACHE2 */
232
233void *
234hash_find_item (struct hash_table *ht, const void *key)
235{
236 void **slot = hash_find_slot (ht, key);
237 return ((HASH_VACANT (*slot)) ? 0 : *slot);
238}
239
240#ifdef CONFIG_WITH_STRCACHE2
241void *
242hash_find_item_strcached (struct hash_table *ht, const void *key)
243{
244 void **slot = hash_find_slot_strcached (ht, key);
245 return ((HASH_VACANT (*slot)) ? 0 : *slot);
246}
247#endif /* CONFIG_WITH_STRCACHE2 */
248
249void *
250hash_insert (struct hash_table *ht, const void *item)
251{
252 void **slot = hash_find_slot (ht, item);
253 const void *old_item = *slot;
254 hash_insert_at (ht, item, slot);
255 return (void *)((HASH_VACANT (old_item)) ? 0 : old_item);
256}
257
258#ifdef CONFIG_WITH_STRCACHE2
259void *
260hash_insert_strcached (struct hash_table *ht, const void *item)
261{
262 void **slot = hash_find_slot_strcached (ht, item);
263 const void *old_item = slot ? *slot : 0;
264 hash_insert_at (ht, item, slot);
265 return (void *)((HASH_VACANT (old_item)) ? 0 : old_item);
266}
267#endif /* CONFIG_WITH_STRCACHE2 */
268
269void *
270hash_insert_at (struct hash_table *ht, const void *item, const void *slot)
271{
272 const void *old_item = *(void **) slot;
273 if (HASH_VACANT (old_item))
274 {
275 ht->ht_fill++;
276 if (old_item == 0)
277 ht->ht_empty_slots--;
278 old_item = item;
279 }
280 *(void const **) slot = item;
281 if (ht->ht_empty_slots < ht->ht_size - ht->ht_capacity)
282 {
283 hash_rehash (ht);
284#ifdef CONFIG_WITH_STRCACHE2
285 if (ht->ht_strcache)
286 return (void *)hash_find_slot_strcached (ht, item);
287#endif /* CONFIG_WITH_STRCACHE2 */
288 return (void *) hash_find_slot (ht, item);
289 }
290 else
291 return (void *) slot;
292}
293
294void *
295hash_delete (struct hash_table *ht, const void *item)
296{
297 void **slot = hash_find_slot (ht, item);
298 return hash_delete_at (ht, slot);
299}
300
301#ifdef CONFIG_WITH_STRCACHE2
302void *
303hash_delete_strcached (struct hash_table *ht, const void *item)
304{
305 void **slot = hash_find_slot_strcached (ht, item);
306 return hash_delete_at (ht, slot);
307}
308#endif /* CONFIG_WITH_STRCACHE2 */
309
310void *
311hash_delete_at (struct hash_table *ht, const void *slot)
312{
313 void *item = *(void **) slot;
314 if (!HASH_VACANT (item))
315 {
316 *(void const **) slot = hash_deleted_item;
317 ht->ht_fill--;
318 return item;
319 }
320 else
321 return 0;
322}
323
324void
325hash_free_items (struct hash_table *ht)
326{
327 void **vec = ht->ht_vec;
328 void **end = &vec[ht->ht_size];
329 for (; vec < end; vec++)
330 {
331 void *item = *vec;
332 if (!HASH_VACANT (item))
333 free (item);
334 *vec = 0;
335 }
336 ht->ht_fill = 0;
337 ht->ht_empty_slots = ht->ht_size;
338}
339
340#ifdef CONFIG_WITH_ALLOC_CACHES
341void
342hash_free_items_cached (struct hash_table *ht, struct alloccache *cache)
343{
344 void **vec = ht->ht_vec;
345 void **end = &vec[ht->ht_size];
346 for (; vec < end; vec++)
347 {
348 void *item = *vec;
349 if (!HASH_VACANT (item))
350 alloccache_free (cache, item);
351 *vec = 0;
352 }
353 ht->ht_fill = 0;
354 ht->ht_empty_slots = ht->ht_size;
355}
356#endif /* CONFIG_WITH_ALLOC_CACHES */
357
358void
359hash_delete_items (struct hash_table *ht)
360{
361 void **vec = ht->ht_vec;
362 void **end = &vec[ht->ht_size];
363 for (; vec < end; vec++)
364 *vec = 0;
365 ht->ht_fill = 0;
366 ht->ht_collisions = 0;
367 ht->ht_lookups = 0;
368 ht->ht_rehashes = 0;
369 ht->ht_empty_slots = ht->ht_size;
370}
371
372void
373hash_free (struct hash_table *ht, int free_items)
374{
375 if (free_items)
376 hash_free_items (ht);
377 else
378 {
379 ht->ht_fill = 0;
380 ht->ht_empty_slots = ht->ht_size;
381 }
382 free (ht->ht_vec);
383 ht->ht_vec = 0;
384 ht->ht_capacity = 0;
385}
386
387#ifdef CONFIG_WITH_ALLOC_CACHES
388void
389hash_free_cached (struct hash_table *ht, int free_items, struct alloccache *cache)
390{
391 if (free_items)
392 hash_free_items_cached (ht, cache);
393 else
394 {
395 ht->ht_fill = 0;
396 ht->ht_empty_slots = ht->ht_size;
397 }
398 free (ht->ht_vec);
399 ht->ht_vec = 0;
400 ht->ht_capacity = 0;
401}
402#endif /* CONFIG_WITH_ALLOC_CACHES */
403
404void
405hash_map (struct hash_table *ht, hash_map_func_t map)
406{
407 void **slot;
408 void **end = &ht->ht_vec[ht->ht_size];
409
410 for (slot = ht->ht_vec; slot < end; slot++)
411 {
412 if (!HASH_VACANT (*slot))
413 (*map) (*slot);
414 }
415}
416
417void
418hash_map_arg (struct hash_table *ht, hash_map_arg_func_t map, void *arg)
419{
420 void **slot;
421 void **end = &ht->ht_vec[ht->ht_size];
422
423 for (slot = ht->ht_vec; slot < end; slot++)
424 {
425 if (!HASH_VACANT (*slot))
426 (*map) (*slot, arg);
427 }
428}
429
430/* Double the size of the hash table in the event of overflow... */
431
432static void
433hash_rehash (struct hash_table *ht)
434{
435 unsigned long old_ht_size = ht->ht_size;
436 void **old_vec = ht->ht_vec;
437 void **ovp;
438
439 if (ht->ht_fill >= ht->ht_capacity)
440 {
441 ht->ht_size *= 2;
442 ht->ht_capacity = ht->ht_size - (ht->ht_size >> 4);
443 }
444 ht->ht_rehashes++;
445 ht->ht_vec = (void **) CALLOC (struct token *, ht->ht_size);
446
447#ifndef CONFIG_WITH_STRCACHE2
448 for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++)
449 {
450 if (! HASH_VACANT (*ovp))
451 {
452 void **slot = hash_find_slot (ht, *ovp);
453 *slot = *ovp;
454 }
455 }
456#else /* CONFIG_WITH_STRCACHE2 */
457 if (ht->ht_strcache)
458 for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++)
459 {
460 if (! HASH_VACANT (*ovp))
461 {
462 void **slot = hash_find_slot_strcached (ht, *ovp);
463 *slot = *ovp;
464 }
465 }
466 else
467 for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++)
468 {
469 if (! HASH_VACANT (*ovp))
470 {
471 void **slot = hash_find_slot (ht, *ovp);
472 *slot = *ovp;
473 }
474 }
475#endif /* CONFIG_WITH_STRCACHE2 */
476 ht->ht_empty_slots = ht->ht_size - ht->ht_fill;
477 free (old_vec);
478}
479
480void
481hash_print_stats (struct hash_table *ht, FILE *out_FILE)
482{
483 /* GKM FIXME: honor NO_FLOAT */
484 fprintf (out_FILE, _("Load=%ld/%ld=%.0f%%, "), ht->ht_fill, ht->ht_size,
485 100.0 * (double) ht->ht_fill / (double) ht->ht_size);
486 fprintf (out_FILE, _("Rehash=%d, "), ht->ht_rehashes);
487 MAKE_STATS(
488 fprintf (out_FILE, _("Collisions=%ld/%ld=%.0f%%"), ht->ht_collisions, ht->ht_lookups,
489 (ht->ht_lookups
490 ? (100.0 * (double) ht->ht_collisions / (double) ht->ht_lookups)
491 : 0));
492 );
493}
494
495/* Dump all items into a NULL-terminated vector. Use the
496 user-supplied vector, or malloc one. */
497
498void **
499hash_dump (struct hash_table *ht, void **vector_0, qsort_cmp_t compare)
500{
501 void **vector;
502 void **slot;
503 void **end = &ht->ht_vec[ht->ht_size];
504
505 if (vector_0 == 0)
506 vector_0 = MALLOC (void *, ht->ht_fill + 1);
507 vector = vector_0;
508
509 for (slot = ht->ht_vec; slot < end; slot++)
510 if (!HASH_VACANT (*slot))
511 *vector++ = *slot;
512 *vector = 0;
513
514 if (compare)
515 qsort (vector_0, ht->ht_fill, sizeof (void *), compare);
516 return vector_0;
517}
518
519/* Round a given number up to the nearest power of 2. */
520
521static unsigned long
522round_up_2 (unsigned long n)
523{
524 n |= (n >> 1);
525 n |= (n >> 2);
526 n |= (n >> 4);
527 n |= (n >> 8);
528 n |= (n >> 16);
529
530#if !defined(HAVE_LIMITS_H) || ULONG_MAX > 4294967295
531 /* We only need this on systems where unsigned long is >32 bits. */
532 n |= (n >> 32);
533#endif
534
535 return n + 1;
536}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use