1 /* A type-safe hash table template.
3 Free Software Foundation, Inc.
4 Contributed by Lawrence Crowl <crowl@google.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
23 /* This file implements a typed hash table.
24 The implementation borrows from libiberty's hashtab. */
27 #ifndef TYPED_HASHTAB_H
28 #define TYPED_HASHTAB_H
33 /* The ordinary memory allocator. */
34 /* FIXME (crowl): This allocator may be extracted for wider sharing later. */
36 template <typename Type
>
39 static Type
*control_alloc (size_t count
);
40 static Type
*data_alloc (size_t count
);
41 static void control_free (Type
*memory
);
42 static void data_free (Type
*memory
);
46 /* Allocate memory for COUNT control blocks. */
48 template <typename Type
>
50 xcallocator
<Type
>::control_alloc (size_t count
)
52 return static_cast <Type
*> (xcalloc (count
, sizeof (Type
)));
56 /* Allocate memory for COUNT data blocks. */
58 template <typename Type
>
60 xcallocator
<Type
>::data_alloc (size_t count
)
62 return static_cast <Type
*> (xcalloc (count
, sizeof (Type
)));
66 /* Free memory for control blocks. */
68 template <typename Type
>
70 xcallocator
<Type
>::control_free (Type
*memory
)
72 return ::free (memory
);
76 /* Free memory for data blocks. */
78 template <typename Type
>
80 xcallocator
<Type
>::data_free (Type
*memory
)
82 return ::free (memory
);
86 /* Remove method dispatching to free. */
88 template <typename Element
>
89 struct typed_free_remove
91 static inline void remove (Element
*p
) { free (p
); }
94 /* No-op remove method. */
96 template <typename Element
>
97 struct typed_noop_remove
99 static inline void remove (Element
*) {}
103 /* Pointer hash with a no-op remove method. */
105 template <typename Element
>
106 struct pointer_hash
: typed_noop_remove
<Element
>
110 static inline hashval_t
114 equal (const T
*existing
, const T
* candidate
);
117 template <typename Element
>
119 pointer_hash
<Element
>::hash (const T
*candidate
)
121 /* This is a really poor hash function, but it is what the current code uses,
122 so I am reusing it to avoid an additional axis in testing. */
123 return (hashval_t
) ((intptr_t)candidate
>> 3);
126 template <typename Element
>
128 pointer_hash
<Element
>::equal (const T
*existing
,
131 return existing
== candidate
;
135 /* Table of primes and their inversion information. */
141 hashval_t inv_m2
; /* inverse of prime-2 */
145 extern struct prime_ent
const prime_tab
[];
148 /* Functions for computing hash table indexes. */
150 extern unsigned int hash_table_higher_prime_index (unsigned long n
);
151 extern hashval_t
hash_table_mod1 (hashval_t hash
, unsigned int index
);
152 extern hashval_t
hash_table_mod2 (hashval_t hash
, unsigned int index
);
155 /* Internal implementation type. */
157 template <typename T
>
158 struct hash_table_control
163 /* Current size (in entries) of the hash table. */
166 /* Current number of elements including also deleted elements. */
169 /* Current number of deleted elements in the table. */
172 /* The following member is used for debugging. Its value is number
173 of all calls of `htab_find_slot' for the hash table. */
174 unsigned int searches
;
176 /* The following member is used for debugging. Its value is number
177 of collisions fixed for time of work with the hash table. */
178 unsigned int collisions
;
180 /* Current size (in entries) of the hash table, as an index into the
182 unsigned int size_prime_index
;
186 /* User-facing hash table type.
188 The table stores elements of type Element.
190 It hashes elements with the hash function.
191 The table currently works with relatively weak hash functions.
192 Use typed_pointer_hash <Element> when hashing pointers instead of objects.
194 It compares elements with the equal function.
195 Two elements with the same hash may not be equal.
196 Use typed_pointer_equal <Element> when hashing pointers instead of objects.
198 It removes elements with the remove function.
199 This feature is useful for freeing memory.
200 Use typed_null_remove <Element> when not freeing objects.
201 Use typed_free_remove <Element> when doing a simple object free.
203 Use the Allocator template to allocate and free memory.
204 The default is xcallocator.
208 template <typename Descr
,
209 template <typename Type
> class Allocator
= xcallocator
>
213 typedef typename
Descr::T T
;
216 hash_table_control
<T
> *htab
;
218 T
**find_empty_slot_for_expand (hashval_t hash
);
223 void create (size_t initial_slots
);
226 T
*find (T
*comparable
);
227 T
*find_with_hash (T
*comparable
, hashval_t hash
);
228 T
**find_slot (T
*comparable
, enum insert_option insert
);
229 T
**find_slot_with_hash (T
*comparable
, hashval_t hash
,
230 enum insert_option insert
);
232 void clear_slot (T
**slot
);
233 void remove_elt (T
*comparable
);
234 void remove_elt_with_hash (T
*comparable
, hashval_t hash
);
239 template <typename Argument
,
240 int (*Callback
) (T
**slot
, Argument argument
)>
241 void traverse_noresize (Argument argument
);
243 template <typename Argument
,
244 int (*Callback
) (T
**slot
, Argument argument
)>
245 void traverse (Argument argument
);
249 /* Construct the hash table. The only useful operation next is create. */
251 template <typename Descr
,
252 template <typename Type
> class Allocator
>
254 hash_table
<Descr
, Allocator
>::hash_table ()
260 /* See if the table has been created, as opposed to constructed. */
262 template <typename Descr
,
263 template <typename Type
> class Allocator
>
265 hash_table
<Descr
, Allocator
>::is_created ()
271 /* Like find_with_hash, but compute the hash value from the element. */
273 template <typename Descr
,
274 template <typename Type
> class Allocator
>
275 inline typename
Descr::T
*
276 hash_table
<Descr
, Allocator
>::find (T
*comparable
)
278 return find_with_hash (comparable
, Descr::hash (comparable
));
282 /* Like find_slot_with_hash, but compute the hash value from the element. */
284 template <typename Descr
,
285 template <typename Type
> class Allocator
>
286 inline typename
Descr::T
**
287 hash_table
<Descr
, Allocator
>
288 ::find_slot (T
*comparable
, enum insert_option insert
)
290 return find_slot_with_hash (comparable
, Descr::hash (comparable
), insert
);
294 /* Like remove_elt_with_hash, but compute the hash value from the element. */
296 template <typename Descr
,
297 template <typename Type
> class Allocator
>
299 hash_table
<Descr
, Allocator
>
300 ::remove_elt (T
*comparable
)
302 remove_elt_with_hash (comparable
, Descr::hash (comparable
));
306 /* Return the current size of this hash table. */
308 template <typename Descr
,
309 template <typename Type
> class Allocator
>
311 hash_table
<Descr
, Allocator
>::size()
317 /* Return the current number of elements in this hash table. */
319 template <typename Descr
,
320 template <typename Type
> class Allocator
>
322 hash_table
<Descr
, Allocator
>::elements()
324 return htab
->n_elements
- htab
->n_deleted
;
328 /* Return the fraction of fixed collisions during all work with given
331 template <typename Descr
,
332 template <typename Type
> class Allocator
>
334 hash_table
<Descr
, Allocator
>::collisions()
336 if (htab
->searches
== 0)
339 return static_cast <double> (htab
->collisions
) / htab
->searches
;
343 /* Create a hash table with at least the given number of INITIAL_SLOTS. */
345 template <typename Descr
,
346 template <typename Type
> class Allocator
>
348 hash_table
<Descr
, Allocator
>::create (size_t size
)
350 unsigned int size_prime_index
;
352 size_prime_index
= hash_table_higher_prime_index (size
);
353 size
= prime_tab
[size_prime_index
].prime
;
355 htab
= Allocator
<hash_table_control
<T
> > ::control_alloc (1);
356 gcc_assert (htab
!= NULL
);
357 htab
->entries
= Allocator
<T
*> ::data_alloc (size
);
358 gcc_assert (htab
->entries
!= NULL
);
360 htab
->size_prime_index
= size_prime_index
;
364 /* Dispose of a hash table. Free all memory and return this hash table to
365 the non-created state. Naturally the hash table must already exist. */
367 template <typename Descr
,
368 template <typename Type
> class Allocator
>
370 hash_table
<Descr
, Allocator
>::dispose ()
372 size_t size
= htab
->size
;
373 T
**entries
= htab
->entries
;
375 for (int i
= size
- 1; i
>= 0; i
--)
376 if (entries
[i
] != HTAB_EMPTY_ENTRY
&& entries
[i
] != HTAB_DELETED_ENTRY
)
377 Descr::remove (entries
[i
]);
379 Allocator
<T
*> ::data_free (entries
);
380 Allocator
<hash_table_control
<T
> > ::control_free (htab
);
385 /* Similar to find_slot, but without several unwanted side effects:
386 - Does not call equal when it finds an existing entry.
387 - Does not change the count of elements/searches/collisions in the
389 This function also assumes there are no deleted entries in the table.
390 HASH is the hash value for the element to be inserted. */
392 template <typename Descr
,
393 template <typename Type
> class Allocator
>
395 hash_table
<Descr
, Allocator
>
396 ::find_empty_slot_for_expand (hashval_t hash
)
398 hashval_t index
= hash_table_mod1 (hash
, htab
->size_prime_index
);
399 size_t size
= htab
->size
;
400 T
**slot
= htab
->entries
+ index
;
403 if (*slot
== HTAB_EMPTY_ENTRY
)
405 else if (*slot
== HTAB_DELETED_ENTRY
)
408 hash2
= hash_table_mod2 (hash
, htab
->size_prime_index
);
415 slot
= htab
->entries
+ index
;
416 if (*slot
== HTAB_EMPTY_ENTRY
)
418 else if (*slot
== HTAB_DELETED_ENTRY
)
424 /* The following function changes size of memory allocated for the
425 entries and repeatedly inserts the table elements. The occupancy
426 of the table after the call will be about 50%. Naturally the hash
427 table must already exist. Remember also that the place of the
428 table entries is changed. If memory allocation fails, this function
431 template <typename Descr
,
432 template <typename Type
> class Allocator
>
434 hash_table
<Descr
, Allocator
>::expand ()
440 size_t nsize
, osize
, elts
;
441 unsigned int oindex
, nindex
;
443 oentries
= htab
->entries
;
444 oindex
= htab
->size_prime_index
;
446 olimit
= oentries
+ osize
;
449 /* Resize only when table after removal of unused elements is either
450 too full or too empty. */
451 if (elts
* 2 > osize
|| (elts
* 8 < osize
&& osize
> 32))
453 nindex
= hash_table_higher_prime_index (elts
* 2);
454 nsize
= prime_tab
[nindex
].prime
;
462 nentries
= Allocator
<T
*> ::data_alloc (nsize
);
463 gcc_assert (nentries
!= NULL
);
464 htab
->entries
= nentries
;
466 htab
->size_prime_index
= nindex
;
467 htab
->n_elements
-= htab
->n_deleted
;
475 if (x
!= HTAB_EMPTY_ENTRY
&& x
!= HTAB_DELETED_ENTRY
)
477 T
**q
= find_empty_slot_for_expand (Descr::hash (x
));
486 Allocator
<T
*> ::data_free (oentries
);
490 /* This function searches for a hash table entry equal to the given
491 COMPARABLE element starting with the given HASH value. It cannot
492 be used to insert or delete an element. */
494 template <typename Descr
,
495 template <typename Type
> class Allocator
>
497 hash_table
<Descr
, Allocator
>
498 ::find_with_hash (T
*comparable
, hashval_t hash
)
500 hashval_t index
, hash2
;
506 index
= hash_table_mod1 (hash
, htab
->size_prime_index
);
508 entry
= htab
->entries
[index
];
509 if (entry
== HTAB_EMPTY_ENTRY
510 || (entry
!= HTAB_DELETED_ENTRY
&& Descr::equal (entry
, comparable
)))
513 hash2
= hash_table_mod2 (hash
, htab
->size_prime_index
);
521 entry
= htab
->entries
[index
];
522 if (entry
== HTAB_EMPTY_ENTRY
523 || (entry
!= HTAB_DELETED_ENTRY
&& Descr::equal (entry
, comparable
)))
529 /* This function searches for a hash table slot containing an entry
530 equal to the given COMPARABLE element and starting with the given
531 HASH. To delete an entry, call this with insert=NO_INSERT, then
532 call clear_slot on the slot returned (possibly after doing some
533 checks). To insert an entry, call this with insert=INSERT, then
534 write the value you want into the returned slot. When inserting an
535 entry, NULL may be returned if memory allocation fails. */
537 template <typename Descr
,
538 template <typename Type
> class Allocator
>
540 hash_table
<Descr
, Allocator
>
541 ::find_slot_with_hash (T
*comparable
, hashval_t hash
,
542 enum insert_option insert
)
544 T
**first_deleted_slot
;
545 hashval_t index
, hash2
;
550 if (insert
== INSERT
&& size
* 3 <= htab
->n_elements
* 4)
556 index
= hash_table_mod1 (hash
, htab
->size_prime_index
);
559 first_deleted_slot
= NULL
;
561 entry
= htab
->entries
[index
];
562 if (entry
== HTAB_EMPTY_ENTRY
)
564 else if (entry
== HTAB_DELETED_ENTRY
)
565 first_deleted_slot
= &htab
->entries
[index
];
566 else if (Descr::equal (entry
, comparable
))
567 return &htab
->entries
[index
];
569 hash2
= hash_table_mod2 (hash
, htab
->size_prime_index
);
577 entry
= htab
->entries
[index
];
578 if (entry
== HTAB_EMPTY_ENTRY
)
580 else if (entry
== HTAB_DELETED_ENTRY
)
582 if (!first_deleted_slot
)
583 first_deleted_slot
= &htab
->entries
[index
];
585 else if (Descr::equal (entry
, comparable
))
586 return &htab
->entries
[index
];
590 if (insert
== NO_INSERT
)
593 if (first_deleted_slot
)
596 *first_deleted_slot
= static_cast <T
*> (HTAB_EMPTY_ENTRY
);
597 return first_deleted_slot
;
601 return &htab
->entries
[index
];
605 /* This function clears all entries in the given hash table. */
607 template <typename Descr
,
608 template <typename Type
> class Allocator
>
610 hash_table
<Descr
, Allocator
>::empty ()
612 size_t size
= htab_size (htab
);
613 T
**entries
= htab
->entries
;
616 for (i
= size
- 1; i
>= 0; i
--)
617 if (entries
[i
] != HTAB_EMPTY_ENTRY
&& entries
[i
] != HTAB_DELETED_ENTRY
)
618 Descr::remove (entries
[i
]);
620 /* Instead of clearing megabyte, downsize the table. */
621 if (size
> 1024*1024 / sizeof (PTR
))
623 int nindex
= hash_table_higher_prime_index (1024 / sizeof (PTR
));
624 int nsize
= prime_tab
[nindex
].prime
;
626 Allocator
<T
*> ::data_free (htab
->entries
);
627 htab
->entries
= Allocator
<T
*> ::data_alloc (nsize
);
629 htab
->size_prime_index
= nindex
;
632 memset (entries
, 0, size
* sizeof (T
*));
634 htab
->n_elements
= 0;
638 /* This function clears a specified SLOT in a hash table. It is
639 useful when you've already done the lookup and don't want to do it
642 template <typename Descr
,
643 template <typename Type
> class Allocator
>
645 hash_table
<Descr
, Allocator
>
646 ::clear_slot (T
**slot
)
648 if (slot
< htab
->entries
|| slot
>= htab
->entries
+ htab
->size
649 || *slot
== HTAB_EMPTY_ENTRY
|| *slot
== HTAB_DELETED_ENTRY
)
652 Descr::remove (*slot
);
654 *slot
= HTAB_DELETED_ENTRY
;
659 /* This function deletes an element with the given COMPARABLE value
660 from hash table starting with the given HASH. If there is no
661 matching element in the hash table, this function does nothing. */
663 template <typename Descr
,
664 template <typename Type
> class Allocator
>
666 hash_table
<Descr
, Allocator
>
667 ::remove_elt_with_hash (T
*comparable
, hashval_t hash
)
671 slot
= find_slot_with_hash (comparable
, hash
, NO_INSERT
);
672 if (*slot
== HTAB_EMPTY_ENTRY
)
675 Descr::remove (*slot
);
677 *slot
= static_cast <T
*> (HTAB_DELETED_ENTRY
);
682 /* This function scans over the entire hash table calling CALLBACK for
683 each live entry. If CALLBACK returns false, the iteration stops.
684 ARGUMENT is passed as CALLBACK's second argument. */
686 template <typename Descr
,
687 template <typename Type
> class Allocator
>
688 template <typename Argument
,
689 int (*Callback
) (typename
Descr::T
**slot
, Argument argument
)>
691 hash_table
<Descr
, Allocator
>
692 ::traverse_noresize (Argument argument
)
697 slot
= htab
->entries
;
698 limit
= slot
+ htab
->size
;
704 if (x
!= HTAB_EMPTY_ENTRY
&& x
!= HTAB_DELETED_ENTRY
)
705 if (! Callback (slot
, argument
))
708 while (++slot
< limit
);
712 /* Like traverse_noresize, but does resize the table when it is too empty
713 to improve effectivity of subsequent calls. */
715 template <typename Descr
,
716 template <typename Type
> class Allocator
>
717 template <typename Argument
,
718 int (*Callback
) (typename
Descr::T
**slot
, Argument argument
)>
720 hash_table
<Descr
, Allocator
>
721 ::traverse (Argument argument
)
723 size_t size
= htab
->size
;
724 if (elements () * 8 < size
&& size
> 32)
727 traverse_noresize
<Argument
, Callback
> (argument
);
730 #endif /* TYPED_HASHTAB_H */