mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-11-25 11:38:27 +08:00
457 lines
13 KiB
C
457 lines
13 KiB
C
/* An expandable hash tables datatype.
|
|
Copyright (C) 1999-2022 Free Software Foundation, Inc.
|
|
Contributed by Vladimir Makarov <vmakarov@cygnus.com>.
|
|
|
|
This file is part of the GNU Offloading and Multi Processing Library
|
|
(libgomp).
|
|
|
|
Libgomp is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
more details.
|
|
|
|
Under Section 7 of GPL version 3, you are granted additional
|
|
permissions described in the GCC Runtime Library Exception, version
|
|
3.1, as published by the Free Software Foundation.
|
|
|
|
You should have received a copy of the GNU General Public License and
|
|
a copy of the GCC Runtime Library Exception along with this program;
|
|
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
/* The hash table code copied from include/hashtab.[hc] and adjusted,
|
|
so that the hash table entries are in the flexible array at the end
|
|
of the control structure, no callbacks are used and the elements in the
|
|
table are of the hash_entry_type type.
|
|
Before including this file, define hash_entry_type type and
|
|
htab_alloc and htab_free functions. After including it, define
|
|
htab_hash and htab_eq inline functions. */
|
|
|
|
/* This package implements basic hash table functionality. It is possible
|
|
to search for an entry, create an entry and destroy an entry.
|
|
|
|
Elements in the table are generic pointers.
|
|
|
|
The size of the table is not fixed; if the occupancy of the table
|
|
grows too high the hash table will be expanded.
|
|
|
|
The abstract data implementation is based on generalized Algorithm D
|
|
from Knuth's book "The art of computer programming". Hash table is
|
|
expanded by creation of new hash table and transferring elements from
|
|
the old table to the new table. */
|
|
|
|
/* The type for a hash code. */
|
|
typedef unsigned int hashval_t;
|
|
|
|
static inline hashval_t htab_hash (hash_entry_type);
|
|
static inline bool htab_eq (hash_entry_type, hash_entry_type);
|
|
|
|
/* This macro defines reserved value for empty table entry. */
|
|
|
|
#define HTAB_EMPTY_ENTRY ((hash_entry_type) 0)
|
|
|
|
/* This macro defines reserved value for table entry which contained
|
|
a deleted element. */
|
|
|
|
#define HTAB_DELETED_ENTRY ((hash_entry_type) 1)
|
|
|
|
/* Hash tables are of the following type. The structure
|
|
(implementation) of this type is not needed for using the hash
|
|
tables. All work with hash table should be executed only through
|
|
functions mentioned below. The size of this structure is subject to
|
|
change. */
|
|
|
|
struct htab {
|
|
/* Current size (in entries) of the hash table. */
|
|
size_t size;
|
|
|
|
/* Current number of elements including also deleted elements. */
|
|
size_t n_elements;
|
|
|
|
/* Current number of deleted elements in the table. */
|
|
size_t n_deleted;
|
|
|
|
/* Current size (in entries) of the hash table, as an index into the
|
|
table of primes. */
|
|
unsigned int size_prime_index;
|
|
|
|
/* Table itself. */
|
|
hash_entry_type entries[];
|
|
};
|
|
|
|
typedef struct htab *htab_t;
|
|
|
|
/* An enum saying whether we insert into the hash table or not. */
|
|
enum insert_option {NO_INSERT, INSERT};
|
|
|
|
/* Table of primes and multiplicative inverses.
|
|
|
|
Note that these are not minimally reduced inverses. Unlike when generating
|
|
code to divide by a constant, we want to be able to use the same algorithm
|
|
all the time. All of these inverses (are implied to) have bit 32 set.
|
|
|
|
For the record, the function that computed the table is in
|
|
libiberty/hashtab.c. */
|
|
|
|
struct prime_ent
|
|
{
|
|
hashval_t prime;
|
|
hashval_t inv;
|
|
hashval_t inv_m2; /* inverse of prime-2 */
|
|
hashval_t shift;
|
|
};
|
|
|
|
static struct prime_ent const prime_tab[] = {
|
|
{ 7, 0x24924925, 0x9999999b, 2 },
|
|
{ 13, 0x3b13b13c, 0x745d1747, 3 },
|
|
{ 31, 0x08421085, 0x1a7b9612, 4 },
|
|
{ 61, 0x0c9714fc, 0x15b1e5f8, 5 },
|
|
{ 127, 0x02040811, 0x0624dd30, 6 },
|
|
{ 251, 0x05197f7e, 0x073260a5, 7 },
|
|
{ 509, 0x01824366, 0x02864fc8, 8 },
|
|
{ 1021, 0x00c0906d, 0x014191f7, 9 },
|
|
{ 2039, 0x0121456f, 0x0161e69e, 10 },
|
|
{ 4093, 0x00300902, 0x00501908, 11 },
|
|
{ 8191, 0x00080041, 0x00180241, 12 },
|
|
{ 16381, 0x000c0091, 0x00140191, 13 },
|
|
{ 32749, 0x002605a5, 0x002a06e6, 14 },
|
|
{ 65521, 0x000f00e2, 0x00110122, 15 },
|
|
{ 131071, 0x00008001, 0x00018003, 16 },
|
|
{ 262139, 0x00014002, 0x0001c004, 17 },
|
|
{ 524287, 0x00002001, 0x00006001, 18 },
|
|
{ 1048573, 0x00003001, 0x00005001, 19 },
|
|
{ 2097143, 0x00004801, 0x00005801, 20 },
|
|
{ 4194301, 0x00000c01, 0x00001401, 21 },
|
|
{ 8388593, 0x00001e01, 0x00002201, 22 },
|
|
{ 16777213, 0x00000301, 0x00000501, 23 },
|
|
{ 33554393, 0x00001381, 0x00001481, 24 },
|
|
{ 67108859, 0x00000141, 0x000001c1, 25 },
|
|
{ 134217689, 0x000004e1, 0x00000521, 26 },
|
|
{ 268435399, 0x00000391, 0x000003b1, 27 },
|
|
{ 536870909, 0x00000019, 0x00000029, 28 },
|
|
{ 1073741789, 0x0000008d, 0x00000095, 29 },
|
|
{ 2147483647, 0x00000003, 0x00000007, 30 },
|
|
/* Avoid "decimal constant so large it is unsigned" for 4294967291. */
|
|
{ 0xfffffffb, 0x00000006, 0x00000008, 31 }
|
|
};
|
|
|
|
/* The following function returns an index into the above table of the
|
|
nearest prime number which is greater than N, and near a power of two. */
|
|
|
|
static unsigned int
|
|
higher_prime_index (unsigned long n)
|
|
{
|
|
unsigned int low = 0;
|
|
unsigned int high = sizeof(prime_tab) / sizeof(prime_tab[0]);
|
|
|
|
while (low != high)
|
|
{
|
|
unsigned int mid = low + (high - low) / 2;
|
|
if (n > prime_tab[mid].prime)
|
|
low = mid + 1;
|
|
else
|
|
high = mid;
|
|
}
|
|
|
|
/* If we've run out of primes, abort. */
|
|
if (n > prime_tab[low].prime)
|
|
abort ();
|
|
|
|
return low;
|
|
}
|
|
|
|
/* Return the current size of given hash table. */
|
|
|
|
static inline size_t
|
|
htab_size (htab_t htab)
|
|
{
|
|
return htab->size;
|
|
}
|
|
|
|
/* Return the current number of elements in given hash table. */
|
|
|
|
static inline size_t
|
|
htab_elements (htab_t htab)
|
|
{
|
|
return htab->n_elements - htab->n_deleted;
|
|
}
|
|
|
|
/* Return X % Y. */
|
|
|
|
static inline hashval_t
|
|
htab_mod_1 (hashval_t x, hashval_t y, hashval_t inv, int shift)
|
|
{
|
|
/* The multiplicative inverses computed above are for 32-bit types, and
|
|
requires that we be able to compute a highpart multiply. */
|
|
if (sizeof (hashval_t) * __CHAR_BIT__ <= 32)
|
|
{
|
|
hashval_t t1, t2, t3, t4, q, r;
|
|
|
|
t1 = ((unsigned long long)x * inv) >> 32;
|
|
t2 = x - t1;
|
|
t3 = t2 >> 1;
|
|
t4 = t1 + t3;
|
|
q = t4 >> shift;
|
|
r = x - (q * y);
|
|
|
|
return r;
|
|
}
|
|
|
|
/* Otherwise just use the native division routines. */
|
|
return x % y;
|
|
}
|
|
|
|
/* Compute the primary hash for HASH given HTAB's current size. */
|
|
|
|
static inline hashval_t
|
|
htab_mod (hashval_t hash, htab_t htab)
|
|
{
|
|
const struct prime_ent *p = &prime_tab[htab->size_prime_index];
|
|
return htab_mod_1 (hash, p->prime, p->inv, p->shift);
|
|
}
|
|
|
|
/* Compute the secondary hash for HASH given HTAB's current size. */
|
|
|
|
static inline hashval_t
|
|
htab_mod_m2 (hashval_t hash, htab_t htab)
|
|
{
|
|
const struct prime_ent *p = &prime_tab[htab->size_prime_index];
|
|
return 1 + htab_mod_1 (hash, p->prime - 2, p->inv_m2, p->shift);
|
|
}
|
|
|
|
static inline htab_t
|
|
htab_clear (htab_t htab)
|
|
{
|
|
htab->n_elements = 0;
|
|
htab->n_deleted = 0;
|
|
memset (htab->entries, 0, htab->size * sizeof (hash_entry_type));
|
|
return htab;
|
|
}
|
|
|
|
/* Create hash table of size SIZE. */
|
|
|
|
static htab_t
|
|
htab_create (size_t size)
|
|
{
|
|
htab_t result;
|
|
unsigned int size_prime_index;
|
|
|
|
size_prime_index = higher_prime_index (size);
|
|
size = prime_tab[size_prime_index].prime;
|
|
|
|
result = (htab_t) htab_alloc (sizeof (struct htab)
|
|
+ size * sizeof (hash_entry_type));
|
|
result->size = size;
|
|
result->size_prime_index = size_prime_index;
|
|
return htab_clear (result);
|
|
}
|
|
|
|
/* Similar to htab_find_slot, but without several unwanted side effects:
|
|
- Does not call htab_eq when it finds an existing entry.
|
|
- Does not change the count of elements in the hash table.
|
|
This function also assumes there are no deleted entries in the table.
|
|
HASH is the hash value for the element to be inserted. */
|
|
|
|
static hash_entry_type *
|
|
find_empty_slot_for_expand (htab_t htab, hashval_t hash)
|
|
{
|
|
hashval_t index = htab_mod (hash, htab);
|
|
size_t size = htab_size (htab);
|
|
hash_entry_type *slot = htab->entries + index;
|
|
hashval_t hash2;
|
|
|
|
if (*slot == HTAB_EMPTY_ENTRY)
|
|
return slot;
|
|
else if (*slot == HTAB_DELETED_ENTRY)
|
|
abort ();
|
|
|
|
hash2 = htab_mod_m2 (hash, htab);
|
|
for (;;)
|
|
{
|
|
index += hash2;
|
|
if (index >= size)
|
|
index -= size;
|
|
|
|
slot = htab->entries + index;
|
|
if (*slot == HTAB_EMPTY_ENTRY)
|
|
return slot;
|
|
else if (*slot == HTAB_DELETED_ENTRY)
|
|
abort ();
|
|
}
|
|
}
|
|
|
|
/* The following function changes size of memory allocated for the
|
|
entries and repeatedly inserts the table elements. The occupancy
|
|
of the table after the call will be about 50%. Naturally the hash
|
|
table must already exist. Remember also that the place of the
|
|
table entries is changed. */
|
|
|
|
static htab_t
|
|
htab_expand (htab_t htab)
|
|
{
|
|
htab_t nhtab;
|
|
hash_entry_type *olimit;
|
|
hash_entry_type *p;
|
|
size_t osize, elts;
|
|
|
|
osize = htab->size;
|
|
olimit = htab->entries + osize;
|
|
elts = htab_elements (htab);
|
|
|
|
/* Resize only when table after removal of unused elements is either
|
|
too full or too empty. */
|
|
if (elts * 2 > osize || (elts * 8 < osize && osize > 32))
|
|
nhtab = htab_create (elts * 2);
|
|
else
|
|
nhtab = htab_create (osize - 1);
|
|
nhtab->n_elements = htab->n_elements - htab->n_deleted;
|
|
|
|
p = htab->entries;
|
|
do
|
|
{
|
|
hash_entry_type x = *p;
|
|
|
|
if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
|
|
*find_empty_slot_for_expand (nhtab, htab_hash (x)) = x;
|
|
|
|
p++;
|
|
}
|
|
while (p < olimit);
|
|
|
|
htab_free (htab);
|
|
return nhtab;
|
|
}
|
|
|
|
/* This function searches for a hash table entry equal to the given
|
|
element. It cannot be used to insert or delete an element. */
|
|
|
|
static hash_entry_type
|
|
htab_find (htab_t htab, const hash_entry_type element)
|
|
{
|
|
hashval_t index, hash2, hash = htab_hash (element);
|
|
size_t size;
|
|
hash_entry_type entry;
|
|
|
|
size = htab_size (htab);
|
|
index = htab_mod (hash, htab);
|
|
|
|
entry = htab->entries[index];
|
|
if (entry == HTAB_EMPTY_ENTRY
|
|
|| (entry != HTAB_DELETED_ENTRY && htab_eq (entry, element)))
|
|
return entry;
|
|
|
|
hash2 = htab_mod_m2 (hash, htab);
|
|
for (;;)
|
|
{
|
|
index += hash2;
|
|
if (index >= size)
|
|
index -= size;
|
|
|
|
entry = htab->entries[index];
|
|
if (entry == HTAB_EMPTY_ENTRY
|
|
|| (entry != HTAB_DELETED_ENTRY && htab_eq (entry, element)))
|
|
return entry;
|
|
}
|
|
}
|
|
|
|
/* This function searches for a hash table slot containing an entry
|
|
equal to the given element. To delete an entry, call this with
|
|
insert=NO_INSERT, then call htab_clear_slot on the slot returned
|
|
(possibly after doing some checks). To insert an entry, call this
|
|
with insert=INSERT, then write the value you want into the returned
|
|
slot. */
|
|
|
|
static hash_entry_type *
|
|
htab_find_slot (htab_t *htabp, const hash_entry_type element,
|
|
enum insert_option insert)
|
|
{
|
|
hash_entry_type *first_deleted_slot;
|
|
hashval_t index, hash2, hash = htab_hash (element);
|
|
size_t size;
|
|
hash_entry_type entry;
|
|
htab_t htab = *htabp;
|
|
|
|
size = htab_size (htab);
|
|
if (insert == INSERT && size * 3 <= htab->n_elements * 4)
|
|
{
|
|
htab = *htabp = htab_expand (htab);
|
|
size = htab_size (htab);
|
|
}
|
|
|
|
index = htab_mod (hash, htab);
|
|
|
|
first_deleted_slot = NULL;
|
|
|
|
entry = htab->entries[index];
|
|
if (entry == HTAB_EMPTY_ENTRY)
|
|
goto empty_entry;
|
|
else if (entry == HTAB_DELETED_ENTRY)
|
|
first_deleted_slot = &htab->entries[index];
|
|
else if (htab_eq (entry, element))
|
|
return &htab->entries[index];
|
|
|
|
hash2 = htab_mod_m2 (hash, htab);
|
|
for (;;)
|
|
{
|
|
index += hash2;
|
|
if (index >= size)
|
|
index -= size;
|
|
|
|
entry = htab->entries[index];
|
|
if (entry == HTAB_EMPTY_ENTRY)
|
|
goto empty_entry;
|
|
else if (entry == HTAB_DELETED_ENTRY)
|
|
{
|
|
if (!first_deleted_slot)
|
|
first_deleted_slot = &htab->entries[index];
|
|
}
|
|
else if (htab_eq (entry, element))
|
|
return &htab->entries[index];
|
|
}
|
|
|
|
empty_entry:
|
|
if (insert == NO_INSERT)
|
|
return NULL;
|
|
|
|
if (first_deleted_slot)
|
|
{
|
|
htab->n_deleted--;
|
|
*first_deleted_slot = HTAB_EMPTY_ENTRY;
|
|
return first_deleted_slot;
|
|
}
|
|
|
|
htab->n_elements++;
|
|
return &htab->entries[index];
|
|
}
|
|
|
|
/* This function clears a specified slot in a hash table. It is
|
|
useful when you've already done the lookup and don't want to do it
|
|
again. */
|
|
|
|
static inline void
|
|
htab_clear_slot (htab_t htab, hash_entry_type *slot)
|
|
{
|
|
if (slot < htab->entries || slot >= htab->entries + htab_size (htab)
|
|
|| *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
|
|
abort ();
|
|
|
|
*slot = HTAB_DELETED_ENTRY;
|
|
htab->n_deleted++;
|
|
}
|
|
|
|
/* Returns a hash code for pointer P. Simplified version of evahash */
|
|
|
|
static inline hashval_t
|
|
hash_pointer (const void *p)
|
|
{
|
|
uintptr_t v = (uintptr_t) p;
|
|
if (sizeof (v) > sizeof (hashval_t))
|
|
v ^= v >> (sizeof (uintptr_t) / 2 * __CHAR_BIT__);
|
|
return v;
|
|
}
|