1 /* A generic hash table package. */
10 # define ZALLOC(Ht, N) obstack_alloc (&(ht->ht_obstack), (N))
12 # define ZALLOC(Ht, N) malloc ((N))
15 #define BUCKET_HEAD(ht, idx) ((ht)->hash_table[(idx)])
19 unsigned long candidate
;
21 /* No even number and none less than 10 will be passed here. */
22 unsigned long divn
= 3;
23 unsigned long sq
= divn
* divn
;
25 while (sq
< candidate
&& (candidate
% divn
))
32 return (candidate
% divn
);
35 /* Round a given number up to the nearest prime. */
38 next_prime (candidate
)
39 unsigned long candidate
;
41 /* Make it definitely odd. */
44 while (!is_prime (candidate
))
51 hash_free_entry (HT
*ht
, HASH_ENT
*e
)
54 e
->next
= ht
->hash_free_entry_list
;
55 ht
->hash_free_entry_list
= e
;
59 hash_allocate_entry (HT
*ht
)
62 if (ht
->hash_free_entry_list
)
64 new = ht
->hash_free_entry_list
;
65 ht
->hash_free_entry_list
= new->next
;
69 new = (HASH_ENT
*) ZALLOC (ht
, sizeof (HASH_ENT
));
75 hash_get_n_slots_used (const HT
*ht
)
77 return ht
->hash_n_slots_used
;
80 /* Free all storage associated with HT that functions in this package
81 have allocated. If a key_freer function has been supplied (when HT
82 was created), this function applies it to the key of each entry before
83 freeing that entry. */
86 hash_free_0 (HT
*ht
, int free_user_data
)
88 if (free_user_data
&& ht
->hash_key_freer
!= NULL
)
92 for (i
= 0; i
< ht
->hash_table_size
; i
++)
97 for (p
= BUCKET_HEAD (ht
, i
); p
; p
= next
)
100 ht
->hash_key_freer (p
->key
);
106 obstack_free (&(ht
->ht_obstack
), NULL
);
110 for (i
= 0; i
< ht
->hash_table_size
; i
++)
115 for (p
= BUCKET_HEAD (ht
, i
); p
; p
= next
)
123 ht
->hash_free_entry_list
= NULL
;
124 free (ht
->hash_table
);
130 hash_rehash (HT
*ht
, unsigned int new_table_size
)
135 if (ht
->hash_table_size
<= 0 || new_table_size
== 0)
138 ht_new
= hash_initialize (new_table_size
, ht
->hash_key_freer
,
139 ht
->hash_hash
, ht
->hash_key_comparator
);
144 for (i
= 0; i
< ht
->hash_table_size
; i
++)
146 HASH_ENT
*p
= BUCKET_HEAD (ht
, i
);
147 for ( /* empty */ ; p
; p
= p
->next
)
150 const void *already_in_table
;
151 already_in_table
= hash_insert_if_absent (ht_new
, p
->key
, &failed
);
152 assert (failed
== 0 && already_in_table
== 0);
159 assert (hash_table_ok (ht_new
));
164 /* FIXME: fill in ht_new->n_slots_used and other statistics fields. */
172 hash_get_max_chain_length (HT
*ht
)
175 unsigned int max_chain_length
= 0;
177 if (!ht
->hash_dirty_max_chain_length
)
178 return ht
->hash_max_chain_length
;
180 for (i
= 0; i
< ht
->hash_table_size
; i
++)
182 unsigned int chain_length
= 0;
183 HASH_ENT
*p
= BUCKET_HEAD (ht
, i
);
184 for ( /* empty */ ; p
; p
= p
->next
)
186 if (chain_length
> max_chain_length
)
187 max_chain_length
= chain_length
;
190 ht
->hash_max_chain_length
= max_chain_length
;
191 ht
->hash_dirty_max_chain_length
= 0;
192 return ht
->hash_max_chain_length
;
196 hash_get_n_keys (const HT
*ht
)
198 return ht
->hash_n_keys
;
202 hash_get_table_size (const HT
*ht
)
204 return ht
->hash_table_size
;
207 /* CANDIDATE_TABLE_SIZE need not be prime. If WHEN_TO_REHASH (FIXME: add
208 this parameter) is positive, when that percentage of table entries have
209 been used, the table size is increased; then a new, larger table
210 (GROW_FACTOR (FIXME: maybe add this parameter) times larger than the previous
211 size) is allocated and all entries in the old table are rehashed into
212 the new, larger one. The old table is freed. If WHEN_TO_REHASH is zero
213 or negative, the table is never resized.
215 The function returns non-zero
216 - if CANDIDATE_TABLE_SIZE is zero or negative
217 - if KEY_COMPARATOR or HASH is null
218 - if it was unable to allocate sufficient storage for the hash table
219 - if WHEN_TO_REHASH is zero or negative
220 Otherwise it returns zero. */
223 hash_initialize (unsigned int candidate_table_size
,
224 Hash_key_freer_type key_freer
,
225 unsigned int (*hash
) (const void *, unsigned int),
226 int (*key_comparator
) (const void *, const void *))
230 unsigned int table_size
;
232 if (candidate_table_size
<= 0)
235 if (hash
== NULL
|| key_comparator
== NULL
)
238 ht
= (HT
*) malloc (sizeof (HT
));
242 table_size
= next_prime (candidate_table_size
);
243 ht
->hash_table
= (HASH_ENT
**) malloc (table_size
* sizeof (HASH_ENT
*));
244 if (ht
->hash_table
== NULL
)
247 for (i
= 0; i
< table_size
; i
++)
249 BUCKET_HEAD (ht
, i
) = NULL
;
252 ht
->hash_free_entry_list
= NULL
;
253 ht
->hash_table_size
= table_size
;
254 ht
->hash_hash
= hash
;
255 ht
->hash_key_comparator
= key_comparator
;
256 ht
->hash_key_freer
= key_freer
;
257 ht
->hash_n_slots_used
= 0;
258 ht
->hash_max_chain_length
= 0;
260 ht
->hash_dirty_max_chain_length
= 0;
262 obstack_init (&(ht
->ht_obstack
));
268 /* This private function is used to help with insertion and deletion.
269 If E does *not* compare equal to the key of any entry in the table,
271 When E matches an entry in the table, return a pointer to the matching
272 entry. When DELETE is non-zero and E matches an entry in the table,
273 unlink the matching entry. Set *CHAIN_LENGTH to the number of keys
274 that have hashed to the bucket E hashed to. */
277 hash_find_entry (HT
*ht
, const void *e
, unsigned int *table_idx
,
278 unsigned int *chain_length
, int delete)
284 idx
= ht
->hash_hash (e
, ht
->hash_table_size
);
285 assert (idx
< ht
->hash_table_size
);
290 prev
= ht
->hash_table
[idx
];
296 if (ht
->hash_key_comparator (e
, prev
->key
) == 0)
299 ht
->hash_table
[idx
] = prev
->next
;
308 if (ht
->hash_key_comparator (e
, p
->key
) == 0)
322 prev
->next
= p
->next
;
327 /* Return non-zero if E is already in the table, zero otherwise. */
330 hash_query_in_table (const HT
*ht
, const void *e
)
335 idx
= ht
->hash_hash (e
, ht
->hash_table_size
);
336 assert (idx
< ht
->hash_table_size
);
337 for (p
= BUCKET_HEAD (ht
, idx
); p
!= NULL
; p
= p
->next
)
338 if (ht
->hash_key_comparator (e
, p
->key
) == 0)
344 hash_lookup (const HT
*ht
, const void *e
)
349 idx
= ht
->hash_hash (e
, ht
->hash_table_size
);
350 assert (idx
< ht
->hash_table_size
);
351 for (p
= BUCKET_HEAD (ht
, idx
); p
!= NULL
; p
= p
->next
)
352 if (ht
->hash_key_comparator (e
, p
->key
) == 0)
357 /* If E matches an entry already in the hash table, don't modify the
358 table and return a pointer to the matched entry. If E does not
359 match any item in the table, insert E and return NULL.
360 If the storage required for insertion cannot be allocated
361 set *FAILED to non-zero and return NULL. */
364 hash_insert_if_absent (HT
*ht
, const void *e
, int *failed
)
369 unsigned int chain_length
;
371 assert (e
!= NULL
); /* Can't insert a NULL key. */
374 ent
= hash_find_entry (ht
, e
, &idx
, &chain_length
, 0);
377 /* E matches a key from an entry already in the table. */
381 new = hash_allocate_entry (ht
);
388 new->key
= (void *) e
;
389 new->next
= BUCKET_HEAD (ht
, idx
);
390 BUCKET_HEAD (ht
, idx
) = new;
392 if (chain_length
== 0)
393 ++(ht
->hash_n_slots_used
);
395 /* The insertion has just increased chain_length by 1. */
398 if (chain_length
> ht
->hash_max_chain_length
)
399 ht
->hash_max_chain_length
= chain_length
;
402 if ((double) ht
->hash_n_keys
/ ht
->hash_table_size
> 0.80)
404 unsigned int new_size
;
405 new_size
= next_prime (2 * ht
->hash_table_size
+ 1);
406 *failed
= hash_rehash (ht
, new_size
);
410 assert (hash_table_ok (ht
));
416 /* If E is already in the table, remove it and return a pointer to
417 the just-deleted key (the user may want to deallocate its storage).
418 If E is not in the table, don't modify the table and return NULL. */
421 hash_delete_if_present (HT
*ht
, const void *e
)
426 unsigned int chain_length
;
428 ent
= hash_find_entry (ht
, e
, &idx
, &chain_length
, 1);
432 if (ent
->next
== NULL
&& chain_length
== 1)
433 --(ht
->hash_n_slots_used
);
438 ht
->hash_dirty_max_chain_length
= 1;
439 if (ent
->next
== NULL
&& chain_length
< ht
->hash_max_chain_length
)
440 ht
->hash_dirty_max_chain_length
= 0;
442 hash_free_entry (ht
, ent
);
445 assert (hash_table_ok (ht
));
451 hash_print_statistics (const HT
*ht
, FILE *stream
)
453 unsigned int n_slots_used
;
455 unsigned int max_chain_length
;
458 err
= hash_get_statistics (ht
, &n_slots_used
, &n_keys
, &max_chain_length
);
460 fprintf (stream
, "table size: %d\n", ht
->hash_table_size
);
461 fprintf (stream
, "# slots used: %u (%.2f%%)\n", n_slots_used
,
462 (100.0 * n_slots_used
) / ht
->hash_table_size
);
463 fprintf (stream
, "# keys: %u\n", n_keys
);
464 fprintf (stream
, "max chain length: %u\n", max_chain_length
);
467 /* If there is *NO* table (so, no meaningful stats) return non-zero
468 and don't reference the argument pointers. Otherwise compute the
469 performance statistics and return non-zero. */
472 hash_get_statistics (const HT
*ht
,
473 unsigned int *n_slots_used
,
474 unsigned int *n_keys
,
475 unsigned int *max_chain_length
)
479 if (ht
== NULL
|| ht
->hash_table
== NULL
)
482 *max_chain_length
= 0;
486 for (i
= 0; i
< ht
->hash_table_size
; i
++)
488 unsigned int chain_length
= 0;
491 p
= BUCKET_HEAD (ht
, i
);
495 for (; p
; p
= p
->next
)
498 *n_keys
+= chain_length
;
499 if (chain_length
> *max_chain_length
)
500 *max_chain_length
= chain_length
;
506 hash_table_ok (HT
*ht
)
509 unsigned int n_slots_used
;
511 unsigned int max_chain_length
;
513 if (ht
== NULL
|| ht
->hash_table
== NULL
)
516 code
= hash_get_statistics (ht
, &n_slots_used
, &n_keys
,
520 || n_slots_used
!= ht
->hash_n_slots_used
521 || n_keys
!= ht
->hash_n_keys
522 || max_chain_length
!= hash_get_max_chain_length (ht
))
528 /* See hash_do_for_each_2 (below) for a variant. */
531 hash_do_for_each (HT
*ht
, void (*f
) (void *e
, void *aux
), void *aux
)
536 assert (hash_table_ok (ht
));
539 if (ht
->hash_table
== NULL
)
542 for (i
= 0; i
< ht
->hash_table_size
; i
++)
545 for (p
= BUCKET_HEAD (ht
, i
); p
; p
= p
->next
)
552 /* Just like hash_do_for_each, except that function F returns an int
553 that can signal (when non-zero) we should return early. */
556 hash_do_for_each_2 (HT
*ht
, int (*f
) (void *e
, void *aux
), void *aux
)
561 assert (hash_table_ok (ht
));
564 if (ht
->hash_table
== NULL
)
567 for (i
= 0; i
< ht
->hash_table_size
; i
++)
570 for (p
= BUCKET_HEAD (ht
, i
); p
; p
= p
->next
)
574 return_code
= (*f
) (p
->key
, aux
);
575 if (return_code
!= 0)
582 /* For each entry in the bucket addressed by BUCKET_KEY of the hash
583 table HT, invoke the function F. If F returns non-zero, stop
584 iterating and return that value. Otherwise, apply F to all entries
585 in the selected bucket and return zero. The AUX argument to this
586 function is passed as the last argument in each invocation of F.
587 The first argument to F is BUCKET_KEY, and the second is the key of
588 an entry in the selected bucket. */
591 hash_do_for_each_in_selected_bucket (HT
*ht
, const void *bucket_key
,
592 int (*f
) (const void *bucket_key
,
600 assert (hash_table_ok (ht
));
603 if (ht
->hash_table
== NULL
)
606 idx
= ht
->hash_hash (bucket_key
, ht
->hash_table_size
);
608 for (p
= BUCKET_HEAD (ht
, idx
); p
!= NULL
; p
= p
->next
)
612 return_code
= (*f
) (bucket_key
, p
->key
, aux
);
613 if (return_code
!= 0)
620 /* Make all buckets empty, placing any chained entries on the free list.
621 As with hash_free, apply the user-specified function key_freer
622 (if it's not NULL) to the keys of any affected entries. */
630 for (i
= 0; i
< ht
->hash_table_size
; i
++)
632 HASH_ENT
*tail
= NULL
;
633 HASH_ENT
*head
= BUCKET_HEAD (ht
, i
);
635 /* Free any keys and get tail pointer to last entry in chain. */
636 for (p
= head
; p
; p
= p
->next
)
638 if (ht
->hash_key_freer
!= NULL
)
639 ht
->hash_key_freer (p
->key
);
640 p
->key
= NULL
; /* Make sure no one tries to use this key later. */
643 BUCKET_HEAD (ht
, i
) = NULL
;
645 /* If there's a chain in this bucket, tack it onto the
646 beginning of the free list. */
649 assert (tail
!= NULL
&& tail
->next
== NULL
);
650 tail
->next
= ht
->hash_free_entry_list
;
651 ht
->hash_free_entry_list
= head
;
654 ht
->hash_n_slots_used
= 0;
655 ht
->hash_max_chain_length
= 0;
657 ht
->hash_dirty_max_chain_length
= 0;
670 hash_print (const HT
*ht
)
674 for (i
= 0; i
< ht
->hash_table_size
; i
++)
678 if (BUCKET_HEAD (ht
, i
) != NULL
)
681 for (p
= BUCKET_HEAD (ht
, i
); p
; p
= p
->next
)
683 char *s
= (char *) p
->key
;
693 hash_get_key_list (const HT
*ht
, unsigned int bufsize
, void **buf
)
698 for (i
= 0; i
< ht
->hash_table_size
; i
++)
702 for (p
= BUCKET_HEAD (ht
, i
); p
; p
= p
->next
)
711 /* Return the first key in the table. If the table is empty, return NULL. */
714 hash_get_first (const HT
*ht
)
719 if (ht
->hash_n_keys
== 0)
722 for (idx
= 0; idx
< ht
->hash_table_size
; idx
++)
724 if ((p
= BUCKET_HEAD (ht
, idx
)) != NULL
)
730 /* Return the key in the entry following the entry whose key matches E.
731 If there is the only one key in the table and that key matches E,
732 return the matching key. If E is not in the table, return NULL. */
735 hash_get_next (const HT
*ht
, const void *e
)
740 idx
= ht
->hash_hash (e
, ht
->hash_table_size
);
741 assert (idx
< ht
->hash_table_size
);
742 for (p
= BUCKET_HEAD (ht
, idx
); p
!= NULL
; p
= p
->next
)
744 if (ht
->hash_key_comparator (e
, p
->key
) == 0)
754 /* E is the last or only key in the bucket chain. */
755 if (ht
->hash_n_keys
== 1)
757 /* There is only one key in the table, and it matches E. */
763 idx
= (idx
+ 1) % ht
->hash_table_size
;
764 if ((p
= BUCKET_HEAD (ht
, idx
)) != NULL
)
767 while (idx
!= bucket
);
772 /* E is not in the table. */