195b7b453SJohn Marino /* hash - hashing table processing.
295b7b453SJohn Marino
3*09d4459fSDaniel Fojt Copyright (C) 1998-2004, 2006-2007, 2009-2020 Free Software Foundation, Inc.
495b7b453SJohn Marino
595b7b453SJohn Marino Written by Jim Meyering, 1992.
695b7b453SJohn Marino
795b7b453SJohn Marino This program is free software: you can redistribute it and/or modify
895b7b453SJohn Marino it under the terms of the GNU General Public License as published by
995b7b453SJohn Marino the Free Software Foundation; either version 3 of the License, or
1095b7b453SJohn Marino (at your option) any later version.
1195b7b453SJohn Marino
1295b7b453SJohn Marino This program is distributed in the hope that it will be useful,
1395b7b453SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1495b7b453SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1595b7b453SJohn Marino GNU General Public License for more details.
1695b7b453SJohn Marino
1795b7b453SJohn Marino You should have received a copy of the GNU General Public License
18*09d4459fSDaniel Fojt along with this program. If not, see <https://www.gnu.org/licenses/>. */
1995b7b453SJohn Marino
2095b7b453SJohn Marino /* A generic hash table package. */
2195b7b453SJohn Marino
2295b7b453SJohn Marino /* Define USE_OBSTACK to 1 if you want the allocator to use obstacks instead
2395b7b453SJohn Marino of malloc. If you change USE_OBSTACK, you have to recompile! */
2495b7b453SJohn Marino
2595b7b453SJohn Marino #include <config.h>
2695b7b453SJohn Marino
2795b7b453SJohn Marino #include "hash.h"
2895b7b453SJohn Marino
2995b7b453SJohn Marino #include "bitrotate.h"
30200fbe8dSJohn Marino #include "xalloc-oversized.h"
3195b7b453SJohn Marino
3295b7b453SJohn Marino #include <stdint.h>
3395b7b453SJohn Marino #include <stdio.h>
3495b7b453SJohn Marino #include <stdlib.h>
3595b7b453SJohn Marino
3695b7b453SJohn Marino #if USE_OBSTACK
3795b7b453SJohn Marino # include "obstack.h"
3895b7b453SJohn Marino # ifndef obstack_chunk_alloc
3995b7b453SJohn Marino # define obstack_chunk_alloc malloc
4095b7b453SJohn Marino # endif
4195b7b453SJohn Marino # ifndef obstack_chunk_free
4295b7b453SJohn Marino # define obstack_chunk_free free
4395b7b453SJohn Marino # endif
4495b7b453SJohn Marino #endif
4595b7b453SJohn Marino
4695b7b453SJohn Marino struct hash_entry
4795b7b453SJohn Marino {
4895b7b453SJohn Marino void *data;
4995b7b453SJohn Marino struct hash_entry *next;
5095b7b453SJohn Marino };
5195b7b453SJohn Marino
5295b7b453SJohn Marino struct hash_table
5395b7b453SJohn Marino {
5495b7b453SJohn Marino /* The array of buckets starts at BUCKET and extends to BUCKET_LIMIT-1,
5595b7b453SJohn Marino for a possibility of N_BUCKETS. Among those, N_BUCKETS_USED buckets
5695b7b453SJohn Marino are not empty, there are N_ENTRIES active entries in the table. */
5795b7b453SJohn Marino struct hash_entry *bucket;
5895b7b453SJohn Marino struct hash_entry const *bucket_limit;
5995b7b453SJohn Marino size_t n_buckets;
6095b7b453SJohn Marino size_t n_buckets_used;
6195b7b453SJohn Marino size_t n_entries;
6295b7b453SJohn Marino
6395b7b453SJohn Marino /* Tuning arguments, kept in a physically separate structure. */
6495b7b453SJohn Marino const Hash_tuning *tuning;
6595b7b453SJohn Marino
66cf28ed85SJohn Marino /* Three functions are given to 'hash_initialize', see the documentation
6795b7b453SJohn Marino block for this function. In a word, HASHER randomizes a user entry
6895b7b453SJohn Marino into a number up from 0 up to some maximum minus 1; COMPARATOR returns
6995b7b453SJohn Marino true if two user entries compare equally; and DATA_FREER is the cleanup
7095b7b453SJohn Marino function for a user entry. */
7195b7b453SJohn Marino Hash_hasher hasher;
7295b7b453SJohn Marino Hash_comparator comparator;
7395b7b453SJohn Marino Hash_data_freer data_freer;
7495b7b453SJohn Marino
7595b7b453SJohn Marino /* A linked list of freed struct hash_entry structs. */
7695b7b453SJohn Marino struct hash_entry *free_entry_list;
7795b7b453SJohn Marino
7895b7b453SJohn Marino #if USE_OBSTACK
7995b7b453SJohn Marino /* Whenever obstacks are used, it is possible to allocate all overflowed
8095b7b453SJohn Marino entries into a single stack, so they all can be freed in a single
8195b7b453SJohn Marino operation. It is not clear if the speedup is worth the trouble. */
8295b7b453SJohn Marino struct obstack entry_stack;
8395b7b453SJohn Marino #endif
8495b7b453SJohn Marino };
8595b7b453SJohn Marino
8695b7b453SJohn Marino /* A hash table contains many internal entries, each holding a pointer to
8795b7b453SJohn Marino some user-provided data (also called a user entry). An entry indistinctly
8895b7b453SJohn Marino refers to both the internal entry and its associated user entry. A user
8995b7b453SJohn Marino entry contents may be hashed by a randomization function (the hashing
90cf28ed85SJohn Marino function, or just "hasher" for short) into a number (or "slot") between 0
9195b7b453SJohn Marino and the current table size. At each slot position in the hash table,
9295b7b453SJohn Marino starts a linked chain of entries for which the user data all hash to this
9395b7b453SJohn Marino slot. A bucket is the collection of all entries hashing to the same slot.
9495b7b453SJohn Marino
95cf28ed85SJohn Marino A good "hasher" function will distribute entries rather evenly in buckets.
9695b7b453SJohn Marino In the ideal case, the length of each bucket is roughly the number of
9795b7b453SJohn Marino entries divided by the table size. Finding the slot for a data is usually
98cf28ed85SJohn Marino done in constant time by the "hasher", and the later finding of a precise
9995b7b453SJohn Marino entry is linear in time with the size of the bucket. Consequently, a
10095b7b453SJohn Marino larger hash table size (that is, a larger number of buckets) is prone to
101cf28ed85SJohn Marino yielding shorter chains, *given* the "hasher" function behaves properly.
10295b7b453SJohn Marino
10395b7b453SJohn Marino Long buckets slow down the lookup algorithm. One might use big hash table
10495b7b453SJohn Marino sizes in hope to reduce the average length of buckets, but this might
10595b7b453SJohn Marino become inordinate, as unused slots in the hash table take some space. The
106cf28ed85SJohn Marino best bet is to make sure you are using a good "hasher" function (beware
10795b7b453SJohn Marino that those are not that easy to write! :-), and to use a table size
10895b7b453SJohn Marino larger than the actual number of entries. */
10995b7b453SJohn Marino
11095b7b453SJohn Marino /* If an insertion makes the ratio of nonempty buckets to table size larger
11195b7b453SJohn Marino than the growth threshold (a number between 0.0 and 1.0), then increase
11295b7b453SJohn Marino the table size by multiplying by the growth factor (a number greater than
11395b7b453SJohn Marino 1.0). The growth threshold defaults to 0.8, and the growth factor
11495b7b453SJohn Marino defaults to 1.414, meaning that the table will have doubled its size
11595b7b453SJohn Marino every second time 80% of the buckets get used. */
116cf28ed85SJohn Marino #define DEFAULT_GROWTH_THRESHOLD 0.8f
117cf28ed85SJohn Marino #define DEFAULT_GROWTH_FACTOR 1.414f
11895b7b453SJohn Marino
11995b7b453SJohn Marino /* If a deletion empties a bucket and causes the ratio of used buckets to
12095b7b453SJohn Marino table size to become smaller than the shrink threshold (a number between
12195b7b453SJohn Marino 0.0 and 1.0), then shrink the table by multiplying by the shrink factor (a
12295b7b453SJohn Marino number greater than the shrink threshold but smaller than 1.0). The shrink
12395b7b453SJohn Marino threshold and factor default to 0.0 and 1.0, meaning that the table never
12495b7b453SJohn Marino shrinks. */
125cf28ed85SJohn Marino #define DEFAULT_SHRINK_THRESHOLD 0.0f
126cf28ed85SJohn Marino #define DEFAULT_SHRINK_FACTOR 1.0f
12795b7b453SJohn Marino
12895b7b453SJohn Marino /* Use this to initialize or reset a TUNING structure to
12995b7b453SJohn Marino some sensible values. */
13095b7b453SJohn Marino static const Hash_tuning default_tuning =
13195b7b453SJohn Marino {
13295b7b453SJohn Marino DEFAULT_SHRINK_THRESHOLD,
13395b7b453SJohn Marino DEFAULT_SHRINK_FACTOR,
13495b7b453SJohn Marino DEFAULT_GROWTH_THRESHOLD,
13595b7b453SJohn Marino DEFAULT_GROWTH_FACTOR,
13695b7b453SJohn Marino false
13795b7b453SJohn Marino };
13895b7b453SJohn Marino
13995b7b453SJohn Marino /* Information and lookup. */
14095b7b453SJohn Marino
14195b7b453SJohn Marino /* The following few functions provide information about the overall hash
14295b7b453SJohn Marino table organization: the number of entries, number of buckets and maximum
14395b7b453SJohn Marino length of buckets. */
14495b7b453SJohn Marino
14595b7b453SJohn Marino /* Return the number of buckets in the hash table. The table size, the total
14695b7b453SJohn Marino number of buckets (used plus unused), or the maximum number of slots, are
14795b7b453SJohn Marino the same quantity. */
14895b7b453SJohn Marino
14995b7b453SJohn Marino size_t
hash_get_n_buckets(const Hash_table * table)15095b7b453SJohn Marino hash_get_n_buckets (const Hash_table *table)
15195b7b453SJohn Marino {
15295b7b453SJohn Marino return table->n_buckets;
15395b7b453SJohn Marino }
15495b7b453SJohn Marino
15595b7b453SJohn Marino /* Return the number of slots in use (non-empty buckets). */
15695b7b453SJohn Marino
15795b7b453SJohn Marino size_t
hash_get_n_buckets_used(const Hash_table * table)15895b7b453SJohn Marino hash_get_n_buckets_used (const Hash_table *table)
15995b7b453SJohn Marino {
16095b7b453SJohn Marino return table->n_buckets_used;
16195b7b453SJohn Marino }
16295b7b453SJohn Marino
16395b7b453SJohn Marino /* Return the number of active entries. */
16495b7b453SJohn Marino
16595b7b453SJohn Marino size_t
hash_get_n_entries(const Hash_table * table)16695b7b453SJohn Marino hash_get_n_entries (const Hash_table *table)
16795b7b453SJohn Marino {
16895b7b453SJohn Marino return table->n_entries;
16995b7b453SJohn Marino }
17095b7b453SJohn Marino
17195b7b453SJohn Marino /* Return the length of the longest chain (bucket). */
17295b7b453SJohn Marino
17395b7b453SJohn Marino size_t
hash_get_max_bucket_length(const Hash_table * table)17495b7b453SJohn Marino hash_get_max_bucket_length (const Hash_table *table)
17595b7b453SJohn Marino {
17695b7b453SJohn Marino struct hash_entry const *bucket;
17795b7b453SJohn Marino size_t max_bucket_length = 0;
17895b7b453SJohn Marino
17995b7b453SJohn Marino for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
18095b7b453SJohn Marino {
18195b7b453SJohn Marino if (bucket->data)
18295b7b453SJohn Marino {
18395b7b453SJohn Marino struct hash_entry const *cursor = bucket;
18495b7b453SJohn Marino size_t bucket_length = 1;
18595b7b453SJohn Marino
18695b7b453SJohn Marino while (cursor = cursor->next, cursor)
18795b7b453SJohn Marino bucket_length++;
18895b7b453SJohn Marino
18995b7b453SJohn Marino if (bucket_length > max_bucket_length)
19095b7b453SJohn Marino max_bucket_length = bucket_length;
19195b7b453SJohn Marino }
19295b7b453SJohn Marino }
19395b7b453SJohn Marino
19495b7b453SJohn Marino return max_bucket_length;
19595b7b453SJohn Marino }
19695b7b453SJohn Marino
19795b7b453SJohn Marino /* Do a mild validation of a hash table, by traversing it and checking two
19895b7b453SJohn Marino statistics. */
19995b7b453SJohn Marino
20095b7b453SJohn Marino bool
hash_table_ok(const Hash_table * table)20195b7b453SJohn Marino hash_table_ok (const Hash_table *table)
20295b7b453SJohn Marino {
20395b7b453SJohn Marino struct hash_entry const *bucket;
20495b7b453SJohn Marino size_t n_buckets_used = 0;
20595b7b453SJohn Marino size_t n_entries = 0;
20695b7b453SJohn Marino
20795b7b453SJohn Marino for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
20895b7b453SJohn Marino {
20995b7b453SJohn Marino if (bucket->data)
21095b7b453SJohn Marino {
21195b7b453SJohn Marino struct hash_entry const *cursor = bucket;
21295b7b453SJohn Marino
21395b7b453SJohn Marino /* Count bucket head. */
21495b7b453SJohn Marino n_buckets_used++;
21595b7b453SJohn Marino n_entries++;
21695b7b453SJohn Marino
21795b7b453SJohn Marino /* Count bucket overflow. */
21895b7b453SJohn Marino while (cursor = cursor->next, cursor)
21995b7b453SJohn Marino n_entries++;
22095b7b453SJohn Marino }
22195b7b453SJohn Marino }
22295b7b453SJohn Marino
22395b7b453SJohn Marino if (n_buckets_used == table->n_buckets_used && n_entries == table->n_entries)
22495b7b453SJohn Marino return true;
22595b7b453SJohn Marino
22695b7b453SJohn Marino return false;
22795b7b453SJohn Marino }
22895b7b453SJohn Marino
22995b7b453SJohn Marino void
hash_print_statistics(const Hash_table * table,FILE * stream)23095b7b453SJohn Marino hash_print_statistics (const Hash_table *table, FILE *stream)
23195b7b453SJohn Marino {
23295b7b453SJohn Marino size_t n_entries = hash_get_n_entries (table);
23395b7b453SJohn Marino size_t n_buckets = hash_get_n_buckets (table);
23495b7b453SJohn Marino size_t n_buckets_used = hash_get_n_buckets_used (table);
23595b7b453SJohn Marino size_t max_bucket_length = hash_get_max_bucket_length (table);
23695b7b453SJohn Marino
23795b7b453SJohn Marino fprintf (stream, "# entries: %lu\n", (unsigned long int) n_entries);
23895b7b453SJohn Marino fprintf (stream, "# buckets: %lu\n", (unsigned long int) n_buckets);
23995b7b453SJohn Marino fprintf (stream, "# buckets used: %lu (%.2f%%)\n",
24095b7b453SJohn Marino (unsigned long int) n_buckets_used,
24195b7b453SJohn Marino (100.0 * n_buckets_used) / n_buckets);
24295b7b453SJohn Marino fprintf (stream, "max bucket length: %lu\n",
24395b7b453SJohn Marino (unsigned long int) max_bucket_length);
24495b7b453SJohn Marino }
24595b7b453SJohn Marino
24695b7b453SJohn Marino /* Hash KEY and return a pointer to the selected bucket.
24795b7b453SJohn Marino If TABLE->hasher misbehaves, abort. */
24895b7b453SJohn Marino static struct hash_entry *
safe_hasher(const Hash_table * table,const void * key)24995b7b453SJohn Marino safe_hasher (const Hash_table *table, const void *key)
25095b7b453SJohn Marino {
25195b7b453SJohn Marino size_t n = table->hasher (key, table->n_buckets);
25295b7b453SJohn Marino if (! (n < table->n_buckets))
25395b7b453SJohn Marino abort ();
25495b7b453SJohn Marino return table->bucket + n;
25595b7b453SJohn Marino }
25695b7b453SJohn Marino
25795b7b453SJohn Marino /* If ENTRY matches an entry already in the hash table, return the
25895b7b453SJohn Marino entry from the table. Otherwise, return NULL. */
25995b7b453SJohn Marino
26095b7b453SJohn Marino void *
hash_lookup(const Hash_table * table,const void * entry)26195b7b453SJohn Marino hash_lookup (const Hash_table *table, const void *entry)
26295b7b453SJohn Marino {
26395b7b453SJohn Marino struct hash_entry const *bucket = safe_hasher (table, entry);
26495b7b453SJohn Marino struct hash_entry const *cursor;
26595b7b453SJohn Marino
26695b7b453SJohn Marino if (bucket->data == NULL)
26795b7b453SJohn Marino return NULL;
26895b7b453SJohn Marino
26995b7b453SJohn Marino for (cursor = bucket; cursor; cursor = cursor->next)
27095b7b453SJohn Marino if (entry == cursor->data || table->comparator (entry, cursor->data))
27195b7b453SJohn Marino return cursor->data;
27295b7b453SJohn Marino
27395b7b453SJohn Marino return NULL;
27495b7b453SJohn Marino }
27595b7b453SJohn Marino
27695b7b453SJohn Marino /* Walking. */
27795b7b453SJohn Marino
27895b7b453SJohn Marino /* The functions in this page traverse the hash table and process the
27995b7b453SJohn Marino contained entries. For the traversal to work properly, the hash table
28095b7b453SJohn Marino should not be resized nor modified while any particular entry is being
28195b7b453SJohn Marino processed. In particular, entries should not be added, and an entry
28295b7b453SJohn Marino may be removed only if there is no shrink threshold and the entry being
28395b7b453SJohn Marino removed has already been passed to hash_get_next. */
28495b7b453SJohn Marino
28595b7b453SJohn Marino /* Return the first data in the table, or NULL if the table is empty. */
28695b7b453SJohn Marino
28795b7b453SJohn Marino void *
hash_get_first(const Hash_table * table)28895b7b453SJohn Marino hash_get_first (const Hash_table *table)
28995b7b453SJohn Marino {
29095b7b453SJohn Marino struct hash_entry const *bucket;
29195b7b453SJohn Marino
29295b7b453SJohn Marino if (table->n_entries == 0)
29395b7b453SJohn Marino return NULL;
29495b7b453SJohn Marino
29595b7b453SJohn Marino for (bucket = table->bucket; ; bucket++)
29695b7b453SJohn Marino if (! (bucket < table->bucket_limit))
29795b7b453SJohn Marino abort ();
29895b7b453SJohn Marino else if (bucket->data)
29995b7b453SJohn Marino return bucket->data;
30095b7b453SJohn Marino }
30195b7b453SJohn Marino
30295b7b453SJohn Marino /* Return the user data for the entry following ENTRY, where ENTRY has been
303cf28ed85SJohn Marino returned by a previous call to either 'hash_get_first' or 'hash_get_next'.
30495b7b453SJohn Marino Return NULL if there are no more entries. */
30595b7b453SJohn Marino
30695b7b453SJohn Marino void *
hash_get_next(const Hash_table * table,const void * entry)30795b7b453SJohn Marino hash_get_next (const Hash_table *table, const void *entry)
30895b7b453SJohn Marino {
30995b7b453SJohn Marino struct hash_entry const *bucket = safe_hasher (table, entry);
31095b7b453SJohn Marino struct hash_entry const *cursor;
31195b7b453SJohn Marino
31295b7b453SJohn Marino /* Find next entry in the same bucket. */
31395b7b453SJohn Marino cursor = bucket;
31495b7b453SJohn Marino do
31595b7b453SJohn Marino {
31695b7b453SJohn Marino if (cursor->data == entry && cursor->next)
31795b7b453SJohn Marino return cursor->next->data;
31895b7b453SJohn Marino cursor = cursor->next;
31995b7b453SJohn Marino }
32095b7b453SJohn Marino while (cursor != NULL);
32195b7b453SJohn Marino
32295b7b453SJohn Marino /* Find first entry in any subsequent bucket. */
32395b7b453SJohn Marino while (++bucket < table->bucket_limit)
32495b7b453SJohn Marino if (bucket->data)
32595b7b453SJohn Marino return bucket->data;
32695b7b453SJohn Marino
32795b7b453SJohn Marino /* None found. */
32895b7b453SJohn Marino return NULL;
32995b7b453SJohn Marino }
33095b7b453SJohn Marino
33195b7b453SJohn Marino /* Fill BUFFER with pointers to active user entries in the hash table, then
33295b7b453SJohn Marino return the number of pointers copied. Do not copy more than BUFFER_SIZE
33395b7b453SJohn Marino pointers. */
33495b7b453SJohn Marino
33595b7b453SJohn Marino size_t
hash_get_entries(const Hash_table * table,void ** buffer,size_t buffer_size)33695b7b453SJohn Marino hash_get_entries (const Hash_table *table, void **buffer,
33795b7b453SJohn Marino size_t buffer_size)
33895b7b453SJohn Marino {
33995b7b453SJohn Marino size_t counter = 0;
34095b7b453SJohn Marino struct hash_entry const *bucket;
34195b7b453SJohn Marino struct hash_entry const *cursor;
34295b7b453SJohn Marino
34395b7b453SJohn Marino for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
34495b7b453SJohn Marino {
34595b7b453SJohn Marino if (bucket->data)
34695b7b453SJohn Marino {
34795b7b453SJohn Marino for (cursor = bucket; cursor; cursor = cursor->next)
34895b7b453SJohn Marino {
34995b7b453SJohn Marino if (counter >= buffer_size)
35095b7b453SJohn Marino return counter;
35195b7b453SJohn Marino buffer[counter++] = cursor->data;
35295b7b453SJohn Marino }
35395b7b453SJohn Marino }
35495b7b453SJohn Marino }
35595b7b453SJohn Marino
35695b7b453SJohn Marino return counter;
35795b7b453SJohn Marino }
35895b7b453SJohn Marino
35995b7b453SJohn Marino /* Call a PROCESSOR function for each entry of a hash table, and return the
36095b7b453SJohn Marino number of entries for which the processor function returned success. A
36195b7b453SJohn Marino pointer to some PROCESSOR_DATA which will be made available to each call to
36295b7b453SJohn Marino the processor function. The PROCESSOR accepts two arguments: the first is
36395b7b453SJohn Marino the user entry being walked into, the second is the value of PROCESSOR_DATA
36495b7b453SJohn Marino as received. The walking continue for as long as the PROCESSOR function
36595b7b453SJohn Marino returns nonzero. When it returns zero, the walking is interrupted. */
36695b7b453SJohn Marino
36795b7b453SJohn Marino size_t
hash_do_for_each(const Hash_table * table,Hash_processor processor,void * processor_data)36895b7b453SJohn Marino hash_do_for_each (const Hash_table *table, Hash_processor processor,
36995b7b453SJohn Marino void *processor_data)
37095b7b453SJohn Marino {
37195b7b453SJohn Marino size_t counter = 0;
37295b7b453SJohn Marino struct hash_entry const *bucket;
37395b7b453SJohn Marino struct hash_entry const *cursor;
37495b7b453SJohn Marino
37595b7b453SJohn Marino for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
37695b7b453SJohn Marino {
37795b7b453SJohn Marino if (bucket->data)
37895b7b453SJohn Marino {
37995b7b453SJohn Marino for (cursor = bucket; cursor; cursor = cursor->next)
38095b7b453SJohn Marino {
38195b7b453SJohn Marino if (! processor (cursor->data, processor_data))
38295b7b453SJohn Marino return counter;
38395b7b453SJohn Marino counter++;
38495b7b453SJohn Marino }
38595b7b453SJohn Marino }
38695b7b453SJohn Marino }
38795b7b453SJohn Marino
38895b7b453SJohn Marino return counter;
38995b7b453SJohn Marino }
39095b7b453SJohn Marino
39195b7b453SJohn Marino /* Allocation and clean-up. */
39295b7b453SJohn Marino
39395b7b453SJohn Marino /* Return a hash index for a NUL-terminated STRING between 0 and N_BUCKETS-1.
39495b7b453SJohn Marino This is a convenience routine for constructing other hashing functions. */
39595b7b453SJohn Marino
39695b7b453SJohn Marino #if USE_DIFF_HASH
39795b7b453SJohn Marino
39895b7b453SJohn Marino /* About hashings, Paul Eggert writes to me (FP), on 1994-01-01: "Please see
39995b7b453SJohn Marino B. J. McKenzie, R. Harries & T. Bell, Selecting a hashing algorithm,
40095b7b453SJohn Marino Software--practice & experience 20, 2 (Feb 1990), 209-224. Good hash
40195b7b453SJohn Marino algorithms tend to be domain-specific, so what's good for [diffutils'] io.c
40295b7b453SJohn Marino may not be good for your application." */
40395b7b453SJohn Marino
40495b7b453SJohn Marino size_t
hash_string(const char * string,size_t n_buckets)40595b7b453SJohn Marino hash_string (const char *string, size_t n_buckets)
40695b7b453SJohn Marino {
40795b7b453SJohn Marino # define HASH_ONE_CHAR(Value, Byte) \
40895b7b453SJohn Marino ((Byte) + rotl_sz (Value, 7))
40995b7b453SJohn Marino
41095b7b453SJohn Marino size_t value = 0;
41195b7b453SJohn Marino unsigned char ch;
41295b7b453SJohn Marino
41395b7b453SJohn Marino for (; (ch = *string); string++)
41495b7b453SJohn Marino value = HASH_ONE_CHAR (value, ch);
41595b7b453SJohn Marino return value % n_buckets;
41695b7b453SJohn Marino
41795b7b453SJohn Marino # undef HASH_ONE_CHAR
41895b7b453SJohn Marino }
41995b7b453SJohn Marino
42095b7b453SJohn Marino #else /* not USE_DIFF_HASH */
42195b7b453SJohn Marino
422cf28ed85SJohn Marino /* This one comes from 'recode', and performs a bit better than the above as
42395b7b453SJohn Marino per a few experiments. It is inspired from a hashing routine found in the
424cf28ed85SJohn Marino very old Cyber 'snoop', itself written in typical Greg Mansfield style.
42595b7b453SJohn Marino (By the way, what happened to this excellent man? Is he still alive?) */
42695b7b453SJohn Marino
42795b7b453SJohn Marino size_t
hash_string(const char * string,size_t n_buckets)42895b7b453SJohn Marino hash_string (const char *string, size_t n_buckets)
42995b7b453SJohn Marino {
43095b7b453SJohn Marino size_t value = 0;
43195b7b453SJohn Marino unsigned char ch;
43295b7b453SJohn Marino
43395b7b453SJohn Marino for (; (ch = *string); string++)
43495b7b453SJohn Marino value = (value * 31 + ch) % n_buckets;
43595b7b453SJohn Marino return value;
43695b7b453SJohn Marino }
43795b7b453SJohn Marino
43895b7b453SJohn Marino #endif /* not USE_DIFF_HASH */
43995b7b453SJohn Marino
44095b7b453SJohn Marino /* Return true if CANDIDATE is a prime number. CANDIDATE should be an odd
44195b7b453SJohn Marino number at least equal to 11. */
44295b7b453SJohn Marino
443cf28ed85SJohn Marino static bool _GL_ATTRIBUTE_CONST
is_prime(size_t candidate)44495b7b453SJohn Marino is_prime (size_t candidate)
44595b7b453SJohn Marino {
44695b7b453SJohn Marino size_t divisor = 3;
44795b7b453SJohn Marino size_t square = divisor * divisor;
44895b7b453SJohn Marino
44995b7b453SJohn Marino while (square < candidate && (candidate % divisor))
45095b7b453SJohn Marino {
45195b7b453SJohn Marino divisor++;
45295b7b453SJohn Marino square += 4 * divisor;
45395b7b453SJohn Marino divisor++;
45495b7b453SJohn Marino }
45595b7b453SJohn Marino
45695b7b453SJohn Marino return (candidate % divisor ? true : false);
45795b7b453SJohn Marino }
45895b7b453SJohn Marino
45995b7b453SJohn Marino /* Round a given CANDIDATE number up to the nearest prime, and return that
46095b7b453SJohn Marino prime. Primes lower than 10 are merely skipped. */
46195b7b453SJohn Marino
462cf28ed85SJohn Marino static size_t _GL_ATTRIBUTE_CONST
next_prime(size_t candidate)46395b7b453SJohn Marino next_prime (size_t candidate)
46495b7b453SJohn Marino {
46595b7b453SJohn Marino /* Skip small primes. */
46695b7b453SJohn Marino if (candidate < 10)
46795b7b453SJohn Marino candidate = 10;
46895b7b453SJohn Marino
46995b7b453SJohn Marino /* Make it definitely odd. */
47095b7b453SJohn Marino candidate |= 1;
47195b7b453SJohn Marino
47295b7b453SJohn Marino while (SIZE_MAX != candidate && !is_prime (candidate))
47395b7b453SJohn Marino candidate += 2;
47495b7b453SJohn Marino
47595b7b453SJohn Marino return candidate;
47695b7b453SJohn Marino }
47795b7b453SJohn Marino
47895b7b453SJohn Marino void
hash_reset_tuning(Hash_tuning * tuning)47995b7b453SJohn Marino hash_reset_tuning (Hash_tuning *tuning)
48095b7b453SJohn Marino {
48195b7b453SJohn Marino *tuning = default_tuning;
48295b7b453SJohn Marino }
48395b7b453SJohn Marino
48495b7b453SJohn Marino /* If the user passes a NULL hasher, we hash the raw pointer. */
48595b7b453SJohn Marino static size_t
raw_hasher(const void * data,size_t n)48695b7b453SJohn Marino raw_hasher (const void *data, size_t n)
48795b7b453SJohn Marino {
48895b7b453SJohn Marino /* When hashing unique pointers, it is often the case that they were
48995b7b453SJohn Marino generated by malloc and thus have the property that the low-order
49095b7b453SJohn Marino bits are 0. As this tends to give poorer performance with small
49195b7b453SJohn Marino tables, we rotate the pointer value before performing division,
49295b7b453SJohn Marino in an attempt to improve hash quality. */
49395b7b453SJohn Marino size_t val = rotr_sz ((size_t) data, 3);
49495b7b453SJohn Marino return val % n;
49595b7b453SJohn Marino }
49695b7b453SJohn Marino
49795b7b453SJohn Marino /* If the user passes a NULL comparator, we use pointer comparison. */
49895b7b453SJohn Marino static bool
raw_comparator(const void * a,const void * b)49995b7b453SJohn Marino raw_comparator (const void *a, const void *b)
50095b7b453SJohn Marino {
50195b7b453SJohn Marino return a == b;
50295b7b453SJohn Marino }
50395b7b453SJohn Marino
50495b7b453SJohn Marino
50595b7b453SJohn Marino /* For the given hash TABLE, check the user supplied tuning structure for
50695b7b453SJohn Marino reasonable values, and return true if there is no gross error with it.
50795b7b453SJohn Marino Otherwise, definitively reset the TUNING field to some acceptable default
50895b7b453SJohn Marino in the hash table (that is, the user loses the right of further modifying
50995b7b453SJohn Marino tuning arguments), and return false. */
51095b7b453SJohn Marino
51195b7b453SJohn Marino static bool
check_tuning(Hash_table * table)51295b7b453SJohn Marino check_tuning (Hash_table *table)
51395b7b453SJohn Marino {
51495b7b453SJohn Marino const Hash_tuning *tuning = table->tuning;
51595b7b453SJohn Marino float epsilon;
51695b7b453SJohn Marino if (tuning == &default_tuning)
51795b7b453SJohn Marino return true;
51895b7b453SJohn Marino
51995b7b453SJohn Marino /* Be a bit stricter than mathematics would require, so that
52095b7b453SJohn Marino rounding errors in size calculations do not cause allocations to
52195b7b453SJohn Marino fail to grow or shrink as they should. The smallest allocation
52295b7b453SJohn Marino is 11 (due to next_prime's algorithm), so an epsilon of 0.1
52395b7b453SJohn Marino should be good enough. */
52495b7b453SJohn Marino epsilon = 0.1f;
52595b7b453SJohn Marino
52695b7b453SJohn Marino if (epsilon < tuning->growth_threshold
52795b7b453SJohn Marino && tuning->growth_threshold < 1 - epsilon
52895b7b453SJohn Marino && 1 + epsilon < tuning->growth_factor
52995b7b453SJohn Marino && 0 <= tuning->shrink_threshold
53095b7b453SJohn Marino && tuning->shrink_threshold + epsilon < tuning->shrink_factor
53195b7b453SJohn Marino && tuning->shrink_factor <= 1
53295b7b453SJohn Marino && tuning->shrink_threshold + epsilon < tuning->growth_threshold)
53395b7b453SJohn Marino return true;
53495b7b453SJohn Marino
53595b7b453SJohn Marino table->tuning = &default_tuning;
53695b7b453SJohn Marino return false;
53795b7b453SJohn Marino }
53895b7b453SJohn Marino
53995b7b453SJohn Marino /* Compute the size of the bucket array for the given CANDIDATE and
54095b7b453SJohn Marino TUNING, or return 0 if there is no possible way to allocate that
54195b7b453SJohn Marino many entries. */
54295b7b453SJohn Marino
543cf28ed85SJohn Marino static size_t _GL_ATTRIBUTE_PURE
compute_bucket_size(size_t candidate,const Hash_tuning * tuning)54495b7b453SJohn Marino compute_bucket_size (size_t candidate, const Hash_tuning *tuning)
54595b7b453SJohn Marino {
54695b7b453SJohn Marino if (!tuning->is_n_buckets)
54795b7b453SJohn Marino {
54895b7b453SJohn Marino float new_candidate = candidate / tuning->growth_threshold;
54995b7b453SJohn Marino if (SIZE_MAX <= new_candidate)
55095b7b453SJohn Marino return 0;
55195b7b453SJohn Marino candidate = new_candidate;
55295b7b453SJohn Marino }
55395b7b453SJohn Marino candidate = next_prime (candidate);
55495b7b453SJohn Marino if (xalloc_oversized (candidate, sizeof (struct hash_entry *)))
55595b7b453SJohn Marino return 0;
55695b7b453SJohn Marino return candidate;
55795b7b453SJohn Marino }
55895b7b453SJohn Marino
55995b7b453SJohn Marino /* Allocate and return a new hash table, or NULL upon failure. The initial
56095b7b453SJohn Marino number of buckets is automatically selected so as to _guarantee_ that you
56195b7b453SJohn Marino may insert at least CANDIDATE different user entries before any growth of
56295b7b453SJohn Marino the hash table size occurs. So, if have a reasonably tight a-priori upper
56395b7b453SJohn Marino bound on the number of entries you intend to insert in the hash table, you
56495b7b453SJohn Marino may save some table memory and insertion time, by specifying it here. If
56595b7b453SJohn Marino the IS_N_BUCKETS field of the TUNING structure is true, the CANDIDATE
56695b7b453SJohn Marino argument has its meaning changed to the wanted number of buckets.
56795b7b453SJohn Marino
56895b7b453SJohn Marino TUNING points to a structure of user-supplied values, in case some fine
56995b7b453SJohn Marino tuning is wanted over the default behavior of the hasher. If TUNING is
57095b7b453SJohn Marino NULL, the default tuning parameters are used instead. If TUNING is
57195b7b453SJohn Marino provided but the values requested are out of bounds or might cause
57295b7b453SJohn Marino rounding errors, return NULL.
57395b7b453SJohn Marino
57495b7b453SJohn Marino The user-supplied HASHER function, when not NULL, accepts two
57595b7b453SJohn Marino arguments ENTRY and TABLE_SIZE. It computes, by hashing ENTRY contents, a
57695b7b453SJohn Marino slot number for that entry which should be in the range 0..TABLE_SIZE-1.
57795b7b453SJohn Marino This slot number is then returned.
57895b7b453SJohn Marino
57995b7b453SJohn Marino The user-supplied COMPARATOR function, when not NULL, accepts two
58095b7b453SJohn Marino arguments pointing to user data, it then returns true for a pair of entries
58195b7b453SJohn Marino that compare equal, or false otherwise. This function is internally called
58295b7b453SJohn Marino on entries which are already known to hash to the same bucket index,
58395b7b453SJohn Marino but which are distinct pointers.
58495b7b453SJohn Marino
58595b7b453SJohn Marino The user-supplied DATA_FREER function, when not NULL, may be later called
58695b7b453SJohn Marino with the user data as an argument, just before the entry containing the
587cf28ed85SJohn Marino data gets freed. This happens from within 'hash_free' or 'hash_clear'.
58895b7b453SJohn Marino You should specify this function only if you want these functions to free
589cf28ed85SJohn Marino all of your 'data' data. This is typically the case when your data is
59095b7b453SJohn Marino simply an auxiliary struct that you have malloc'd to aggregate several
59195b7b453SJohn Marino values. */
59295b7b453SJohn Marino
59395b7b453SJohn Marino Hash_table *
hash_initialize(size_t candidate,const Hash_tuning * tuning,Hash_hasher hasher,Hash_comparator comparator,Hash_data_freer data_freer)59495b7b453SJohn Marino hash_initialize (size_t candidate, const Hash_tuning *tuning,
59595b7b453SJohn Marino Hash_hasher hasher, Hash_comparator comparator,
59695b7b453SJohn Marino Hash_data_freer data_freer)
59795b7b453SJohn Marino {
59895b7b453SJohn Marino Hash_table *table;
59995b7b453SJohn Marino
60095b7b453SJohn Marino if (hasher == NULL)
60195b7b453SJohn Marino hasher = raw_hasher;
60295b7b453SJohn Marino if (comparator == NULL)
60395b7b453SJohn Marino comparator = raw_comparator;
60495b7b453SJohn Marino
60595b7b453SJohn Marino table = malloc (sizeof *table);
60695b7b453SJohn Marino if (table == NULL)
60795b7b453SJohn Marino return NULL;
60895b7b453SJohn Marino
60995b7b453SJohn Marino if (!tuning)
61095b7b453SJohn Marino tuning = &default_tuning;
61195b7b453SJohn Marino table->tuning = tuning;
61295b7b453SJohn Marino if (!check_tuning (table))
61395b7b453SJohn Marino {
61495b7b453SJohn Marino /* Fail if the tuning options are invalid. This is the only occasion
61595b7b453SJohn Marino when the user gets some feedback about it. Once the table is created,
61695b7b453SJohn Marino if the user provides invalid tuning options, we silently revert to
61795b7b453SJohn Marino using the defaults, and ignore further request to change the tuning
61895b7b453SJohn Marino options. */
61995b7b453SJohn Marino goto fail;
62095b7b453SJohn Marino }
62195b7b453SJohn Marino
62295b7b453SJohn Marino table->n_buckets = compute_bucket_size (candidate, tuning);
62395b7b453SJohn Marino if (!table->n_buckets)
62495b7b453SJohn Marino goto fail;
62595b7b453SJohn Marino
62695b7b453SJohn Marino table->bucket = calloc (table->n_buckets, sizeof *table->bucket);
62795b7b453SJohn Marino if (table->bucket == NULL)
62895b7b453SJohn Marino goto fail;
62995b7b453SJohn Marino table->bucket_limit = table->bucket + table->n_buckets;
63095b7b453SJohn Marino table->n_buckets_used = 0;
63195b7b453SJohn Marino table->n_entries = 0;
63295b7b453SJohn Marino
63395b7b453SJohn Marino table->hasher = hasher;
63495b7b453SJohn Marino table->comparator = comparator;
63595b7b453SJohn Marino table->data_freer = data_freer;
63695b7b453SJohn Marino
63795b7b453SJohn Marino table->free_entry_list = NULL;
63895b7b453SJohn Marino #if USE_OBSTACK
63995b7b453SJohn Marino obstack_init (&table->entry_stack);
64095b7b453SJohn Marino #endif
64195b7b453SJohn Marino return table;
64295b7b453SJohn Marino
64395b7b453SJohn Marino fail:
64495b7b453SJohn Marino free (table);
64595b7b453SJohn Marino return NULL;
64695b7b453SJohn Marino }
64795b7b453SJohn Marino
64895b7b453SJohn Marino /* Make all buckets empty, placing any chained entries on the free list.
64995b7b453SJohn Marino Apply the user-specified function data_freer (if any) to the datas of any
65095b7b453SJohn Marino affected entries. */
65195b7b453SJohn Marino
65295b7b453SJohn Marino void
hash_clear(Hash_table * table)65395b7b453SJohn Marino hash_clear (Hash_table *table)
65495b7b453SJohn Marino {
65595b7b453SJohn Marino struct hash_entry *bucket;
65695b7b453SJohn Marino
65795b7b453SJohn Marino for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
65895b7b453SJohn Marino {
65995b7b453SJohn Marino if (bucket->data)
66095b7b453SJohn Marino {
66195b7b453SJohn Marino struct hash_entry *cursor;
66295b7b453SJohn Marino struct hash_entry *next;
66395b7b453SJohn Marino
66495b7b453SJohn Marino /* Free the bucket overflow. */
66595b7b453SJohn Marino for (cursor = bucket->next; cursor; cursor = next)
66695b7b453SJohn Marino {
66795b7b453SJohn Marino if (table->data_freer)
66895b7b453SJohn Marino table->data_freer (cursor->data);
66995b7b453SJohn Marino cursor->data = NULL;
67095b7b453SJohn Marino
67195b7b453SJohn Marino next = cursor->next;
67295b7b453SJohn Marino /* Relinking is done one entry at a time, as it is to be expected
67395b7b453SJohn Marino that overflows are either rare or short. */
67495b7b453SJohn Marino cursor->next = table->free_entry_list;
67595b7b453SJohn Marino table->free_entry_list = cursor;
67695b7b453SJohn Marino }
67795b7b453SJohn Marino
67895b7b453SJohn Marino /* Free the bucket head. */
67995b7b453SJohn Marino if (table->data_freer)
68095b7b453SJohn Marino table->data_freer (bucket->data);
68195b7b453SJohn Marino bucket->data = NULL;
68295b7b453SJohn Marino bucket->next = NULL;
68395b7b453SJohn Marino }
68495b7b453SJohn Marino }
68595b7b453SJohn Marino
68695b7b453SJohn Marino table->n_buckets_used = 0;
68795b7b453SJohn Marino table->n_entries = 0;
68895b7b453SJohn Marino }
68995b7b453SJohn Marino
69095b7b453SJohn Marino /* Reclaim all storage associated with a hash table. If a data_freer
69195b7b453SJohn Marino function has been supplied by the user when the hash table was created,
69295b7b453SJohn Marino this function applies it to the data of each entry before freeing that
69395b7b453SJohn Marino entry. */
69495b7b453SJohn Marino
69595b7b453SJohn Marino void
hash_free(Hash_table * table)69695b7b453SJohn Marino hash_free (Hash_table *table)
69795b7b453SJohn Marino {
69895b7b453SJohn Marino struct hash_entry *bucket;
69995b7b453SJohn Marino struct hash_entry *cursor;
70095b7b453SJohn Marino struct hash_entry *next;
70195b7b453SJohn Marino
70295b7b453SJohn Marino /* Call the user data_freer function. */
70395b7b453SJohn Marino if (table->data_freer && table->n_entries)
70495b7b453SJohn Marino {
70595b7b453SJohn Marino for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
70695b7b453SJohn Marino {
70795b7b453SJohn Marino if (bucket->data)
70895b7b453SJohn Marino {
70995b7b453SJohn Marino for (cursor = bucket; cursor; cursor = cursor->next)
71095b7b453SJohn Marino table->data_freer (cursor->data);
71195b7b453SJohn Marino }
71295b7b453SJohn Marino }
71395b7b453SJohn Marino }
71495b7b453SJohn Marino
71595b7b453SJohn Marino #if USE_OBSTACK
71695b7b453SJohn Marino
71795b7b453SJohn Marino obstack_free (&table->entry_stack, NULL);
71895b7b453SJohn Marino
71995b7b453SJohn Marino #else
72095b7b453SJohn Marino
72195b7b453SJohn Marino /* Free all bucket overflowed entries. */
72295b7b453SJohn Marino for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
72395b7b453SJohn Marino {
72495b7b453SJohn Marino for (cursor = bucket->next; cursor; cursor = next)
72595b7b453SJohn Marino {
72695b7b453SJohn Marino next = cursor->next;
72795b7b453SJohn Marino free (cursor);
72895b7b453SJohn Marino }
72995b7b453SJohn Marino }
73095b7b453SJohn Marino
73195b7b453SJohn Marino /* Also reclaim the internal list of previously freed entries. */
73295b7b453SJohn Marino for (cursor = table->free_entry_list; cursor; cursor = next)
73395b7b453SJohn Marino {
73495b7b453SJohn Marino next = cursor->next;
73595b7b453SJohn Marino free (cursor);
73695b7b453SJohn Marino }
73795b7b453SJohn Marino
73895b7b453SJohn Marino #endif
73995b7b453SJohn Marino
74095b7b453SJohn Marino /* Free the remainder of the hash table structure. */
74195b7b453SJohn Marino free (table->bucket);
74295b7b453SJohn Marino free (table);
74395b7b453SJohn Marino }
74495b7b453SJohn Marino
74595b7b453SJohn Marino /* Insertion and deletion. */
74695b7b453SJohn Marino
74795b7b453SJohn Marino /* Get a new hash entry for a bucket overflow, possibly by recycling a
74895b7b453SJohn Marino previously freed one. If this is not possible, allocate a new one. */
74995b7b453SJohn Marino
75095b7b453SJohn Marino static struct hash_entry *
allocate_entry(Hash_table * table)75195b7b453SJohn Marino allocate_entry (Hash_table *table)
75295b7b453SJohn Marino {
75395b7b453SJohn Marino struct hash_entry *new;
75495b7b453SJohn Marino
75595b7b453SJohn Marino if (table->free_entry_list)
75695b7b453SJohn Marino {
75795b7b453SJohn Marino new = table->free_entry_list;
75895b7b453SJohn Marino table->free_entry_list = new->next;
75995b7b453SJohn Marino }
76095b7b453SJohn Marino else
76195b7b453SJohn Marino {
76295b7b453SJohn Marino #if USE_OBSTACK
76395b7b453SJohn Marino new = obstack_alloc (&table->entry_stack, sizeof *new);
76495b7b453SJohn Marino #else
76595b7b453SJohn Marino new = malloc (sizeof *new);
76695b7b453SJohn Marino #endif
76795b7b453SJohn Marino }
76895b7b453SJohn Marino
76995b7b453SJohn Marino return new;
77095b7b453SJohn Marino }
77195b7b453SJohn Marino
77295b7b453SJohn Marino /* Free a hash entry which was part of some bucket overflow,
77395b7b453SJohn Marino saving it for later recycling. */
77495b7b453SJohn Marino
77595b7b453SJohn Marino static void
free_entry(Hash_table * table,struct hash_entry * entry)77695b7b453SJohn Marino free_entry (Hash_table *table, struct hash_entry *entry)
77795b7b453SJohn Marino {
77895b7b453SJohn Marino entry->data = NULL;
77995b7b453SJohn Marino entry->next = table->free_entry_list;
78095b7b453SJohn Marino table->free_entry_list = entry;
78195b7b453SJohn Marino }
78295b7b453SJohn Marino
78395b7b453SJohn Marino /* This private function is used to help with insertion and deletion. When
78495b7b453SJohn Marino ENTRY matches an entry in the table, return a pointer to the corresponding
78595b7b453SJohn Marino user data and set *BUCKET_HEAD to the head of the selected bucket.
78695b7b453SJohn Marino Otherwise, return NULL. When DELETE is true and ENTRY matches an entry in
78795b7b453SJohn Marino the table, unlink the matching entry. */
78895b7b453SJohn Marino
78995b7b453SJohn Marino static void *
hash_find_entry(Hash_table * table,const void * entry,struct hash_entry ** bucket_head,bool delete)79095b7b453SJohn Marino hash_find_entry (Hash_table *table, const void *entry,
79195b7b453SJohn Marino struct hash_entry **bucket_head, bool delete)
79295b7b453SJohn Marino {
79395b7b453SJohn Marino struct hash_entry *bucket = safe_hasher (table, entry);
79495b7b453SJohn Marino struct hash_entry *cursor;
79595b7b453SJohn Marino
79695b7b453SJohn Marino *bucket_head = bucket;
79795b7b453SJohn Marino
79895b7b453SJohn Marino /* Test for empty bucket. */
79995b7b453SJohn Marino if (bucket->data == NULL)
80095b7b453SJohn Marino return NULL;
80195b7b453SJohn Marino
80295b7b453SJohn Marino /* See if the entry is the first in the bucket. */
80395b7b453SJohn Marino if (entry == bucket->data || table->comparator (entry, bucket->data))
80495b7b453SJohn Marino {
80595b7b453SJohn Marino void *data = bucket->data;
80695b7b453SJohn Marino
80795b7b453SJohn Marino if (delete)
80895b7b453SJohn Marino {
80995b7b453SJohn Marino if (bucket->next)
81095b7b453SJohn Marino {
81195b7b453SJohn Marino struct hash_entry *next = bucket->next;
81295b7b453SJohn Marino
81395b7b453SJohn Marino /* Bump the first overflow entry into the bucket head, then save
81495b7b453SJohn Marino the previous first overflow entry for later recycling. */
81595b7b453SJohn Marino *bucket = *next;
81695b7b453SJohn Marino free_entry (table, next);
81795b7b453SJohn Marino }
81895b7b453SJohn Marino else
81995b7b453SJohn Marino {
82095b7b453SJohn Marino bucket->data = NULL;
82195b7b453SJohn Marino }
82295b7b453SJohn Marino }
82395b7b453SJohn Marino
82495b7b453SJohn Marino return data;
82595b7b453SJohn Marino }
82695b7b453SJohn Marino
82795b7b453SJohn Marino /* Scan the bucket overflow. */
82895b7b453SJohn Marino for (cursor = bucket; cursor->next; cursor = cursor->next)
82995b7b453SJohn Marino {
83095b7b453SJohn Marino if (entry == cursor->next->data
83195b7b453SJohn Marino || table->comparator (entry, cursor->next->data))
83295b7b453SJohn Marino {
83395b7b453SJohn Marino void *data = cursor->next->data;
83495b7b453SJohn Marino
83595b7b453SJohn Marino if (delete)
83695b7b453SJohn Marino {
83795b7b453SJohn Marino struct hash_entry *next = cursor->next;
83895b7b453SJohn Marino
83995b7b453SJohn Marino /* Unlink the entry to delete, then save the freed entry for later
84095b7b453SJohn Marino recycling. */
84195b7b453SJohn Marino cursor->next = next->next;
84295b7b453SJohn Marino free_entry (table, next);
84395b7b453SJohn Marino }
84495b7b453SJohn Marino
84595b7b453SJohn Marino return data;
84695b7b453SJohn Marino }
84795b7b453SJohn Marino }
84895b7b453SJohn Marino
84995b7b453SJohn Marino /* No entry found. */
85095b7b453SJohn Marino return NULL;
85195b7b453SJohn Marino }
85295b7b453SJohn Marino
85395b7b453SJohn Marino /* Internal helper, to move entries from SRC to DST. Both tables must
85495b7b453SJohn Marino share the same free entry list. If SAFE, only move overflow
85595b7b453SJohn Marino entries, saving bucket heads for later, so that no allocations will
85695b7b453SJohn Marino occur. Return false if the free entry list is exhausted and an
85795b7b453SJohn Marino allocation fails. */
85895b7b453SJohn Marino
85995b7b453SJohn Marino static bool
transfer_entries(Hash_table * dst,Hash_table * src,bool safe)86095b7b453SJohn Marino transfer_entries (Hash_table *dst, Hash_table *src, bool safe)
86195b7b453SJohn Marino {
86295b7b453SJohn Marino struct hash_entry *bucket;
86395b7b453SJohn Marino struct hash_entry *cursor;
86495b7b453SJohn Marino struct hash_entry *next;
86595b7b453SJohn Marino for (bucket = src->bucket; bucket < src->bucket_limit; bucket++)
86695b7b453SJohn Marino if (bucket->data)
86795b7b453SJohn Marino {
86895b7b453SJohn Marino void *data;
86995b7b453SJohn Marino struct hash_entry *new_bucket;
87095b7b453SJohn Marino
87195b7b453SJohn Marino /* Within each bucket, transfer overflow entries first and
87295b7b453SJohn Marino then the bucket head, to minimize memory pressure. After
87395b7b453SJohn Marino all, the only time we might allocate is when moving the
87495b7b453SJohn Marino bucket head, but moving overflow entries first may create
87595b7b453SJohn Marino free entries that can be recycled by the time we finally
87695b7b453SJohn Marino get to the bucket head. */
87795b7b453SJohn Marino for (cursor = bucket->next; cursor; cursor = next)
87895b7b453SJohn Marino {
87995b7b453SJohn Marino data = cursor->data;
88095b7b453SJohn Marino new_bucket = safe_hasher (dst, data);
88195b7b453SJohn Marino
88295b7b453SJohn Marino next = cursor->next;
88395b7b453SJohn Marino
88495b7b453SJohn Marino if (new_bucket->data)
88595b7b453SJohn Marino {
88695b7b453SJohn Marino /* Merely relink an existing entry, when moving from a
88795b7b453SJohn Marino bucket overflow into a bucket overflow. */
88895b7b453SJohn Marino cursor->next = new_bucket->next;
88995b7b453SJohn Marino new_bucket->next = cursor;
89095b7b453SJohn Marino }
89195b7b453SJohn Marino else
89295b7b453SJohn Marino {
89395b7b453SJohn Marino /* Free an existing entry, when moving from a bucket
89495b7b453SJohn Marino overflow into a bucket header. */
89595b7b453SJohn Marino new_bucket->data = data;
89695b7b453SJohn Marino dst->n_buckets_used++;
89795b7b453SJohn Marino free_entry (dst, cursor);
89895b7b453SJohn Marino }
89995b7b453SJohn Marino }
90095b7b453SJohn Marino /* Now move the bucket head. Be sure that if we fail due to
90195b7b453SJohn Marino allocation failure that the src table is in a consistent
90295b7b453SJohn Marino state. */
90395b7b453SJohn Marino data = bucket->data;
90495b7b453SJohn Marino bucket->next = NULL;
90595b7b453SJohn Marino if (safe)
90695b7b453SJohn Marino continue;
90795b7b453SJohn Marino new_bucket = safe_hasher (dst, data);
90895b7b453SJohn Marino
90995b7b453SJohn Marino if (new_bucket->data)
91095b7b453SJohn Marino {
91195b7b453SJohn Marino /* Allocate or recycle an entry, when moving from a bucket
91295b7b453SJohn Marino header into a bucket overflow. */
91395b7b453SJohn Marino struct hash_entry *new_entry = allocate_entry (dst);
91495b7b453SJohn Marino
91595b7b453SJohn Marino if (new_entry == NULL)
91695b7b453SJohn Marino return false;
91795b7b453SJohn Marino
91895b7b453SJohn Marino new_entry->data = data;
91995b7b453SJohn Marino new_entry->next = new_bucket->next;
92095b7b453SJohn Marino new_bucket->next = new_entry;
92195b7b453SJohn Marino }
92295b7b453SJohn Marino else
92395b7b453SJohn Marino {
92495b7b453SJohn Marino /* Move from one bucket header to another. */
92595b7b453SJohn Marino new_bucket->data = data;
92695b7b453SJohn Marino dst->n_buckets_used++;
92795b7b453SJohn Marino }
92895b7b453SJohn Marino bucket->data = NULL;
92995b7b453SJohn Marino src->n_buckets_used--;
93095b7b453SJohn Marino }
93195b7b453SJohn Marino return true;
93295b7b453SJohn Marino }
93395b7b453SJohn Marino
93495b7b453SJohn Marino /* For an already existing hash table, change the number of buckets through
93595b7b453SJohn Marino specifying CANDIDATE. The contents of the hash table are preserved. The
93695b7b453SJohn Marino new number of buckets is automatically selected so as to _guarantee_ that
93795b7b453SJohn Marino the table may receive at least CANDIDATE different user entries, including
93895b7b453SJohn Marino those already in the table, before any other growth of the hash table size
93995b7b453SJohn Marino occurs. If TUNING->IS_N_BUCKETS is true, then CANDIDATE specifies the
94095b7b453SJohn Marino exact number of buckets desired. Return true iff the rehash succeeded. */
94195b7b453SJohn Marino
94295b7b453SJohn Marino bool
hash_rehash(Hash_table * table,size_t candidate)94395b7b453SJohn Marino hash_rehash (Hash_table *table, size_t candidate)
94495b7b453SJohn Marino {
94595b7b453SJohn Marino Hash_table storage;
94695b7b453SJohn Marino Hash_table *new_table;
94795b7b453SJohn Marino size_t new_size = compute_bucket_size (candidate, table->tuning);
94895b7b453SJohn Marino
94995b7b453SJohn Marino if (!new_size)
95095b7b453SJohn Marino return false;
95195b7b453SJohn Marino if (new_size == table->n_buckets)
95295b7b453SJohn Marino return true;
95395b7b453SJohn Marino new_table = &storage;
95495b7b453SJohn Marino new_table->bucket = calloc (new_size, sizeof *new_table->bucket);
95595b7b453SJohn Marino if (new_table->bucket == NULL)
95695b7b453SJohn Marino return false;
95795b7b453SJohn Marino new_table->n_buckets = new_size;
95895b7b453SJohn Marino new_table->bucket_limit = new_table->bucket + new_size;
95995b7b453SJohn Marino new_table->n_buckets_used = 0;
96095b7b453SJohn Marino new_table->n_entries = 0;
96195b7b453SJohn Marino new_table->tuning = table->tuning;
96295b7b453SJohn Marino new_table->hasher = table->hasher;
96395b7b453SJohn Marino new_table->comparator = table->comparator;
96495b7b453SJohn Marino new_table->data_freer = table->data_freer;
96595b7b453SJohn Marino
96695b7b453SJohn Marino /* In order for the transfer to successfully complete, we need
96795b7b453SJohn Marino additional overflow entries when distinct buckets in the old
96895b7b453SJohn Marino table collide into a common bucket in the new table. The worst
96995b7b453SJohn Marino case possible is a hasher that gives a good spread with the old
97095b7b453SJohn Marino size, but returns a constant with the new size; if we were to
97195b7b453SJohn Marino guarantee table->n_buckets_used-1 free entries in advance, then
97295b7b453SJohn Marino the transfer would be guaranteed to not allocate memory.
97395b7b453SJohn Marino However, for large tables, a guarantee of no further allocation
97495b7b453SJohn Marino introduces a lot of extra memory pressure, all for an unlikely
97595b7b453SJohn Marino corner case (most rehashes reduce, rather than increase, the
97695b7b453SJohn Marino number of overflow entries needed). So, we instead ensure that
97795b7b453SJohn Marino the transfer process can be reversed if we hit a memory
97895b7b453SJohn Marino allocation failure mid-transfer. */
97995b7b453SJohn Marino
98095b7b453SJohn Marino /* Merely reuse the extra old space into the new table. */
98195b7b453SJohn Marino #if USE_OBSTACK
98295b7b453SJohn Marino new_table->entry_stack = table->entry_stack;
98395b7b453SJohn Marino #endif
98495b7b453SJohn Marino new_table->free_entry_list = table->free_entry_list;
98595b7b453SJohn Marino
98695b7b453SJohn Marino if (transfer_entries (new_table, table, false))
98795b7b453SJohn Marino {
98895b7b453SJohn Marino /* Entries transferred successfully; tie up the loose ends. */
98995b7b453SJohn Marino free (table->bucket);
99095b7b453SJohn Marino table->bucket = new_table->bucket;
99195b7b453SJohn Marino table->bucket_limit = new_table->bucket_limit;
99295b7b453SJohn Marino table->n_buckets = new_table->n_buckets;
99395b7b453SJohn Marino table->n_buckets_used = new_table->n_buckets_used;
99495b7b453SJohn Marino table->free_entry_list = new_table->free_entry_list;
99595b7b453SJohn Marino /* table->n_entries and table->entry_stack already hold their value. */
99695b7b453SJohn Marino return true;
99795b7b453SJohn Marino }
99895b7b453SJohn Marino
99995b7b453SJohn Marino /* We've allocated new_table->bucket (and possibly some entries),
100095b7b453SJohn Marino exhausted the free list, and moved some but not all entries into
100195b7b453SJohn Marino new_table. We must undo the partial move before returning
100295b7b453SJohn Marino failure. The only way to get into this situation is if new_table
100395b7b453SJohn Marino uses fewer buckets than the old table, so we will reclaim some
100495b7b453SJohn Marino free entries as overflows in the new table are put back into
100595b7b453SJohn Marino distinct buckets in the old table.
100695b7b453SJohn Marino
100795b7b453SJohn Marino There are some pathological cases where a single pass through the
100895b7b453SJohn Marino table requires more intermediate overflow entries than using two
100995b7b453SJohn Marino passes. Two passes give worse cache performance and takes
101095b7b453SJohn Marino longer, but at this point, we're already out of memory, so slow
101195b7b453SJohn Marino and safe is better than failure. */
101295b7b453SJohn Marino table->free_entry_list = new_table->free_entry_list;
101395b7b453SJohn Marino if (! (transfer_entries (table, new_table, true)
101495b7b453SJohn Marino && transfer_entries (table, new_table, false)))
101595b7b453SJohn Marino abort ();
101695b7b453SJohn Marino /* table->n_entries already holds its value. */
101795b7b453SJohn Marino free (new_table->bucket);
101895b7b453SJohn Marino return false;
101995b7b453SJohn Marino }
102095b7b453SJohn Marino
1021cf28ed85SJohn Marino /* Insert ENTRY into hash TABLE if there is not already a matching entry.
1022cf28ed85SJohn Marino
1023cf28ed85SJohn Marino Return -1 upon memory allocation failure.
102495b7b453SJohn Marino Return 1 if insertion succeeded.
102595b7b453SJohn Marino Return 0 if there is already a matching entry in the table,
102695b7b453SJohn Marino and in that case, if MATCHED_ENT is non-NULL, set *MATCHED_ENT
102795b7b453SJohn Marino to that entry.
102895b7b453SJohn Marino
102995b7b453SJohn Marino This interface is easier to use than hash_insert when you must
103095b7b453SJohn Marino distinguish between the latter two cases. More importantly,
103195b7b453SJohn Marino hash_insert is unusable for some types of ENTRY values. When using
103295b7b453SJohn Marino hash_insert, the only way to distinguish those cases is to compare
103395b7b453SJohn Marino the return value and ENTRY. That works only when you can have two
103495b7b453SJohn Marino different ENTRY values that point to data that compares "equal". Thus,
1035cf28ed85SJohn Marino when the ENTRY value is a simple scalar, you must use
1036cf28ed85SJohn Marino hash_insert_if_absent. ENTRY must not be NULL. */
103795b7b453SJohn Marino int
hash_insert_if_absent(Hash_table * table,void const * entry,void const ** matched_ent)1038cf28ed85SJohn Marino hash_insert_if_absent (Hash_table *table, void const *entry,
1039cf28ed85SJohn Marino void const **matched_ent)
104095b7b453SJohn Marino {
104195b7b453SJohn Marino void *data;
104295b7b453SJohn Marino struct hash_entry *bucket;
104395b7b453SJohn Marino
104495b7b453SJohn Marino /* The caller cannot insert a NULL entry, since hash_lookup returns NULL
104595b7b453SJohn Marino to indicate "not found", and hash_find_entry uses "bucket->data == NULL"
104695b7b453SJohn Marino to indicate an empty bucket. */
104795b7b453SJohn Marino if (! entry)
104895b7b453SJohn Marino abort ();
104995b7b453SJohn Marino
105095b7b453SJohn Marino /* If there's a matching entry already in the table, return that. */
105195b7b453SJohn Marino if ((data = hash_find_entry (table, entry, &bucket, false)) != NULL)
105295b7b453SJohn Marino {
105395b7b453SJohn Marino if (matched_ent)
105495b7b453SJohn Marino *matched_ent = data;
105595b7b453SJohn Marino return 0;
105695b7b453SJohn Marino }
105795b7b453SJohn Marino
105895b7b453SJohn Marino /* If the growth threshold of the buckets in use has been reached, increase
105995b7b453SJohn Marino the table size and rehash. There's no point in checking the number of
106095b7b453SJohn Marino entries: if the hashing function is ill-conditioned, rehashing is not
106195b7b453SJohn Marino likely to improve it. */
106295b7b453SJohn Marino
106395b7b453SJohn Marino if (table->n_buckets_used
106495b7b453SJohn Marino > table->tuning->growth_threshold * table->n_buckets)
106595b7b453SJohn Marino {
106695b7b453SJohn Marino /* Check more fully, before starting real work. If tuning arguments
106795b7b453SJohn Marino became invalid, the second check will rely on proper defaults. */
106895b7b453SJohn Marino check_tuning (table);
106995b7b453SJohn Marino if (table->n_buckets_used
107095b7b453SJohn Marino > table->tuning->growth_threshold * table->n_buckets)
107195b7b453SJohn Marino {
107295b7b453SJohn Marino const Hash_tuning *tuning = table->tuning;
107395b7b453SJohn Marino float candidate =
107495b7b453SJohn Marino (tuning->is_n_buckets
107595b7b453SJohn Marino ? (table->n_buckets * tuning->growth_factor)
107695b7b453SJohn Marino : (table->n_buckets * tuning->growth_factor
107795b7b453SJohn Marino * tuning->growth_threshold));
107895b7b453SJohn Marino
107995b7b453SJohn Marino if (SIZE_MAX <= candidate)
108095b7b453SJohn Marino return -1;
108195b7b453SJohn Marino
108295b7b453SJohn Marino /* If the rehash fails, arrange to return NULL. */
108395b7b453SJohn Marino if (!hash_rehash (table, candidate))
108495b7b453SJohn Marino return -1;
108595b7b453SJohn Marino
108695b7b453SJohn Marino /* Update the bucket we are interested in. */
108795b7b453SJohn Marino if (hash_find_entry (table, entry, &bucket, false) != NULL)
108895b7b453SJohn Marino abort ();
108995b7b453SJohn Marino }
109095b7b453SJohn Marino }
109195b7b453SJohn Marino
109295b7b453SJohn Marino /* ENTRY is not matched, it should be inserted. */
109395b7b453SJohn Marino
109495b7b453SJohn Marino if (bucket->data)
109595b7b453SJohn Marino {
109695b7b453SJohn Marino struct hash_entry *new_entry = allocate_entry (table);
109795b7b453SJohn Marino
109895b7b453SJohn Marino if (new_entry == NULL)
109995b7b453SJohn Marino return -1;
110095b7b453SJohn Marino
110195b7b453SJohn Marino /* Add ENTRY in the overflow of the bucket. */
110295b7b453SJohn Marino
110395b7b453SJohn Marino new_entry->data = (void *) entry;
110495b7b453SJohn Marino new_entry->next = bucket->next;
110595b7b453SJohn Marino bucket->next = new_entry;
110695b7b453SJohn Marino table->n_entries++;
110795b7b453SJohn Marino return 1;
110895b7b453SJohn Marino }
110995b7b453SJohn Marino
111095b7b453SJohn Marino /* Add ENTRY right in the bucket head. */
111195b7b453SJohn Marino
111295b7b453SJohn Marino bucket->data = (void *) entry;
111395b7b453SJohn Marino table->n_entries++;
111495b7b453SJohn Marino table->n_buckets_used++;
111595b7b453SJohn Marino
111695b7b453SJohn Marino return 1;
111795b7b453SJohn Marino }
111895b7b453SJohn Marino
111995b7b453SJohn Marino /* If ENTRY matches an entry already in the hash table, return the pointer
112095b7b453SJohn Marino to the entry from the table. Otherwise, insert ENTRY and return ENTRY.
112195b7b453SJohn Marino Return NULL if the storage required for insertion cannot be allocated.
112295b7b453SJohn Marino This implementation does not support duplicate entries or insertion of
112395b7b453SJohn Marino NULL. */
112495b7b453SJohn Marino
112595b7b453SJohn Marino void *
hash_insert(Hash_table * table,void const * entry)112695b7b453SJohn Marino hash_insert (Hash_table *table, void const *entry)
112795b7b453SJohn Marino {
112895b7b453SJohn Marino void const *matched_ent;
1129cf28ed85SJohn Marino int err = hash_insert_if_absent (table, entry, &matched_ent);
113095b7b453SJohn Marino return (err == -1
113195b7b453SJohn Marino ? NULL
113295b7b453SJohn Marino : (void *) (err == 0 ? matched_ent : entry));
113395b7b453SJohn Marino }
113495b7b453SJohn Marino
113595b7b453SJohn Marino /* If ENTRY is already in the table, remove it and return the just-deleted
113695b7b453SJohn Marino data (the user may want to deallocate its storage). If ENTRY is not in the
113795b7b453SJohn Marino table, don't modify the table and return NULL. */
113895b7b453SJohn Marino
113995b7b453SJohn Marino void *
hash_delete(Hash_table * table,const void * entry)114095b7b453SJohn Marino hash_delete (Hash_table *table, const void *entry)
114195b7b453SJohn Marino {
114295b7b453SJohn Marino void *data;
114395b7b453SJohn Marino struct hash_entry *bucket;
114495b7b453SJohn Marino
114595b7b453SJohn Marino data = hash_find_entry (table, entry, &bucket, true);
114695b7b453SJohn Marino if (!data)
114795b7b453SJohn Marino return NULL;
114895b7b453SJohn Marino
114995b7b453SJohn Marino table->n_entries--;
115095b7b453SJohn Marino if (!bucket->data)
115195b7b453SJohn Marino {
115295b7b453SJohn Marino table->n_buckets_used--;
115395b7b453SJohn Marino
115495b7b453SJohn Marino /* If the shrink threshold of the buckets in use has been reached,
115595b7b453SJohn Marino rehash into a smaller table. */
115695b7b453SJohn Marino
115795b7b453SJohn Marino if (table->n_buckets_used
115895b7b453SJohn Marino < table->tuning->shrink_threshold * table->n_buckets)
115995b7b453SJohn Marino {
116095b7b453SJohn Marino /* Check more fully, before starting real work. If tuning arguments
116195b7b453SJohn Marino became invalid, the second check will rely on proper defaults. */
116295b7b453SJohn Marino check_tuning (table);
116395b7b453SJohn Marino if (table->n_buckets_used
116495b7b453SJohn Marino < table->tuning->shrink_threshold * table->n_buckets)
116595b7b453SJohn Marino {
116695b7b453SJohn Marino const Hash_tuning *tuning = table->tuning;
116795b7b453SJohn Marino size_t candidate =
116895b7b453SJohn Marino (tuning->is_n_buckets
116995b7b453SJohn Marino ? table->n_buckets * tuning->shrink_factor
117095b7b453SJohn Marino : (table->n_buckets * tuning->shrink_factor
117195b7b453SJohn Marino * tuning->growth_threshold));
117295b7b453SJohn Marino
117395b7b453SJohn Marino if (!hash_rehash (table, candidate))
117495b7b453SJohn Marino {
117595b7b453SJohn Marino /* Failure to allocate memory in an attempt to
117695b7b453SJohn Marino shrink the table is not fatal. But since memory
117795b7b453SJohn Marino is low, we can at least be kind and free any
117895b7b453SJohn Marino spare entries, rather than keeping them tied up
117995b7b453SJohn Marino in the free entry list. */
118095b7b453SJohn Marino #if ! USE_OBSTACK
118195b7b453SJohn Marino struct hash_entry *cursor = table->free_entry_list;
118295b7b453SJohn Marino struct hash_entry *next;
118395b7b453SJohn Marino while (cursor)
118495b7b453SJohn Marino {
118595b7b453SJohn Marino next = cursor->next;
118695b7b453SJohn Marino free (cursor);
118795b7b453SJohn Marino cursor = next;
118895b7b453SJohn Marino }
118995b7b453SJohn Marino table->free_entry_list = NULL;
119095b7b453SJohn Marino #endif
119195b7b453SJohn Marino }
119295b7b453SJohn Marino }
119395b7b453SJohn Marino }
119495b7b453SJohn Marino }
119595b7b453SJohn Marino
119695b7b453SJohn Marino return data;
119795b7b453SJohn Marino }
119895b7b453SJohn Marino
119995b7b453SJohn Marino /* Testing. */
120095b7b453SJohn Marino
120195b7b453SJohn Marino #if TESTING
120295b7b453SJohn Marino
120395b7b453SJohn Marino void
hash_print(const Hash_table * table)120495b7b453SJohn Marino hash_print (const Hash_table *table)
120595b7b453SJohn Marino {
120695b7b453SJohn Marino struct hash_entry *bucket = (struct hash_entry *) table->bucket;
120795b7b453SJohn Marino
120895b7b453SJohn Marino for ( ; bucket < table->bucket_limit; bucket++)
120995b7b453SJohn Marino {
121095b7b453SJohn Marino struct hash_entry *cursor;
121195b7b453SJohn Marino
121295b7b453SJohn Marino if (bucket)
121395b7b453SJohn Marino printf ("%lu:\n", (unsigned long int) (bucket - table->bucket));
121495b7b453SJohn Marino
121595b7b453SJohn Marino for (cursor = bucket; cursor; cursor = cursor->next)
121695b7b453SJohn Marino {
121795b7b453SJohn Marino char const *s = cursor->data;
121895b7b453SJohn Marino /* FIXME */
121995b7b453SJohn Marino if (s)
122095b7b453SJohn Marino printf (" %s\n", s);
122195b7b453SJohn Marino }
122295b7b453SJohn Marino }
122395b7b453SJohn Marino }
122495b7b453SJohn Marino
122595b7b453SJohn Marino #endif /* TESTING */
1226