/* An expandable hash tables datatype.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
- Free Software Foundation, Inc.
+ Copyright (C) 1999-2019 Free Software Foundation, Inc.
Contributed by Vladimir Makarov (vmakarov@cygnus.com).
This file is part of the libiberty library.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* This package implements basic hash table functionality. It is possible
to search for an entry, create an entry and destroy an entry.
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#define CHAR_BIT 8
#endif
-/* This macro defines reserved value for empty table entry. */
-
-#define EMPTY_ENTRY ((PTR) 0)
-
-/* This macro defines reserved value for table entry which contained
- a deleted element. */
-
-#define DELETED_ENTRY ((PTR) 1)
-
static unsigned int higher_prime_index (unsigned long);
static hashval_t htab_mod_1 (hashval_t, hashval_t, hashval_t, int);
static hashval_t htab_mod (hashval_t, htab_t);
return low;
}
-/* Returns a hash code for P. */
-
-static hashval_t
-hash_pointer (const PTR p)
-{
- return (hashval_t) ((long)p >> 3);
-}
-
/* Returns non-zero if P1 and P2 are equal. */
static int
return p1 == p2;
}
-/* Return the current size of given hash table. */
-inline size_t
-htab_size (htab_t htab)
+/* The parens around the function names in the next two definitions
+ are essential in order to prevent macro expansions of the name.
+ The bodies, however, are expanded as expected, so they are not
+ recursive definitions. */
+
+/* Return the current size of given hash table. */
+
+#define htab_size(htab) ((htab)->size)
+
+size_t
+(htab_size) (htab_t htab)
{
- return htab->size;
+ return htab_size (htab);
}
/* Return the current number of elements in given hash table. */
-inline size_t
-htab_elements (htab_t htab)
+#define htab_elements(htab) ((htab)->n_elements - (htab)->n_deleted)
+
+size_t
+(htab_elements) (htab_t htab)
{
- return htab->n_elements - htab->n_deleted;
+ return htab_elements (htab);
}
/* Return X % Y. */
/* This function creates table with length slightly longer than given
source length. Created hash table is initiated as empty (all the
- hash table entries are EMPTY_ENTRY). The function returns the
+ hash table entries are HTAB_EMPTY_ENTRY). The function returns the
created hash table, or NULL if memory allocation fails. */
htab_t
htab_create_alloc (size_t size, htab_hash hash_f, htab_eq eq_f,
htab_del del_f, htab_alloc alloc_f, htab_free free_f)
+{
+ return htab_create_typed_alloc (size, hash_f, eq_f, del_f, alloc_f, alloc_f,
+ free_f);
+}
+
+/* As above, but uses the variants of ALLOC_F and FREE_F which accept
+ an extra argument. */
+
+htab_t
+htab_create_alloc_ex (size_t size, htab_hash hash_f, htab_eq eq_f,
+ htab_del del_f, void *alloc_arg,
+ htab_alloc_with_arg alloc_f,
+ htab_free_with_arg free_f)
{
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) (*alloc_f) (1, sizeof (struct htab));
+ result = (htab_t) (*alloc_f) (alloc_arg, 1, sizeof (struct htab));
if (result == NULL)
return NULL;
- result->entries = (PTR *) (*alloc_f) (size, sizeof (PTR));
+ result->entries = (PTR *) (*alloc_f) (alloc_arg, size, sizeof (PTR));
if (result->entries == NULL)
{
if (free_f != NULL)
- (*free_f) (result);
+ (*free_f) (alloc_arg, result);
return NULL;
}
result->size = size;
result->hash_f = hash_f;
result->eq_f = eq_f;
result->del_f = del_f;
- result->alloc_f = alloc_f;
- result->free_f = free_f;
+ result->alloc_arg = alloc_arg;
+ result->alloc_with_arg_f = alloc_f;
+ result->free_with_arg_f = free_f;
return result;
}
-/* As above, but use the variants of alloc_f and free_f which accept
- an extra argument. */
+/*
+
+@deftypefn Supplemental htab_t htab_create_typed_alloc (size_t @var{size}, @
+htab_hash @var{hash_f}, htab_eq @var{eq_f}, htab_del @var{del_f}, @
+htab_alloc @var{alloc_tab_f}, htab_alloc @var{alloc_f}, @
+htab_free @var{free_f})
+
+This function creates a hash table that uses two different allocators
+@var{alloc_tab_f} and @var{alloc_f} to use for allocating the table itself
+and its entries respectively. This is useful when variables of different
+types need to be allocated with different allocators.
+
+The created hash table is slightly larger than @var{size} and it is
+initially empty (all the hash table entries are @code{HTAB_EMPTY_ENTRY}).
+The function returns the created hash table, or @code{NULL} if memory
+allocation fails.
+
+@end deftypefn
+
+*/
htab_t
-htab_create_alloc_ex (size, hash_f, eq_f, del_f, alloc_arg, alloc_f,
- free_f)
- size_t size;
- htab_hash hash_f;
- htab_eq eq_f;
- htab_del del_f;
- PTR alloc_arg;
- htab_alloc_with_arg alloc_f;
- htab_free_with_arg free_f;
+htab_create_typed_alloc (size_t size, htab_hash hash_f, htab_eq eq_f,
+ htab_del del_f, htab_alloc alloc_tab_f,
+ htab_alloc alloc_f, htab_free free_f)
{
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) (*alloc_f) (alloc_arg, 1, sizeof (struct htab));
+ result = (htab_t) (*alloc_tab_f) (1, sizeof (struct htab));
if (result == NULL)
return NULL;
- result->entries = (PTR *) (*alloc_f) (alloc_arg, size, sizeof (PTR));
+ result->entries = (PTR *) (*alloc_f) (size, sizeof (PTR));
if (result->entries == NULL)
{
if (free_f != NULL)
- (*free_f) (alloc_arg, result);
+ (*free_f) (result);
return NULL;
}
result->size = size;
result->hash_f = hash_f;
result->eq_f = eq_f;
result->del_f = del_f;
- result->alloc_arg = alloc_arg;
- result->alloc_with_arg_f = alloc_f;
- result->free_with_arg_f = free_f;
+ result->alloc_f = alloc_f;
+ result->free_f = free_f;
return result;
}
+
/* Update the function pointers and allocation parameter in the htab_t. */
void
if (htab->del_f)
for (i = size - 1; i >= 0; i--)
- if (entries[i] != EMPTY_ENTRY && entries[i] != DELETED_ENTRY)
+ if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
(*htab->del_f) (entries[i]);
if (htab->free_f != NULL)
if (htab->del_f)
for (i = size - 1; i >= 0; i--)
- if (entries[i] != EMPTY_ENTRY && entries[i] != DELETED_ENTRY)
+ if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
(*htab->del_f) (entries[i]);
- memset (entries, 0, size * sizeof (PTR));
+ /* Instead of clearing megabyte, downsize the table. */
+ if (size > 1024*1024 / sizeof (PTR))
+ {
+ int nindex = higher_prime_index (1024 / sizeof (PTR));
+ int nsize = prime_tab[nindex].prime;
+
+ if (htab->free_f != NULL)
+ (*htab->free_f) (htab->entries);
+ else if (htab->free_with_arg_f != NULL)
+ (*htab->free_with_arg_f) (htab->alloc_arg, htab->entries);
+ if (htab->alloc_with_arg_f != NULL)
+ htab->entries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize,
+ sizeof (PTR *));
+ else
+ htab->entries = (PTR *) (*htab->alloc_f) (nsize, sizeof (PTR *));
+ htab->size = nsize;
+ htab->size_prime_index = nindex;
+ }
+ else
+ memset (entries, 0, size * sizeof (PTR));
+ htab->n_deleted = 0;
+ htab->n_elements = 0;
}
/* Similar to htab_find_slot, but without several unwanted side effects:
PTR *slot = htab->entries + index;
hashval_t hash2;
- if (*slot == EMPTY_ENTRY)
+ if (*slot == HTAB_EMPTY_ENTRY)
return slot;
- else if (*slot == DELETED_ENTRY)
+ else if (*slot == HTAB_DELETED_ENTRY)
abort ();
hash2 = htab_mod_m2 (hash, htab);
index -= size;
slot = htab->entries + index;
- if (*slot == EMPTY_ENTRY)
+ if (*slot == HTAB_EMPTY_ENTRY)
return slot;
- else if (*slot == DELETED_ENTRY)
+ else if (*slot == HTAB_DELETED_ENTRY)
abort ();
}
}
{
PTR x = *p;
- if (x != EMPTY_ENTRY && x != DELETED_ENTRY)
+ if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
{
PTR *q = find_empty_slot_for_expand (htab, (*htab->hash_f) (x));
index = htab_mod (hash, htab);
entry = htab->entries[index];
- if (entry == EMPTY_ENTRY
- || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element)))
+ if (entry == HTAB_EMPTY_ENTRY
+ || (entry != HTAB_DELETED_ENTRY && (*htab->eq_f) (entry, element)))
return entry;
hash2 = htab_mod_m2 (hash, htab);
index -= size;
entry = htab->entries[index];
- if (entry == EMPTY_ENTRY
- || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element)))
+ if (entry == HTAB_EMPTY_ENTRY
+ || (entry != HTAB_DELETED_ENTRY && (*htab->eq_f) (entry, element)))
return entry;
}
}
first_deleted_slot = NULL;
entry = htab->entries[index];
- if (entry == EMPTY_ENTRY)
+ if (entry == HTAB_EMPTY_ENTRY)
goto empty_entry;
- else if (entry == DELETED_ENTRY)
+ else if (entry == HTAB_DELETED_ENTRY)
first_deleted_slot = &htab->entries[index];
else if ((*htab->eq_f) (entry, element))
return &htab->entries[index];
index -= size;
entry = htab->entries[index];
- if (entry == EMPTY_ENTRY)
+ if (entry == HTAB_EMPTY_ENTRY)
goto empty_entry;
- else if (entry == DELETED_ENTRY)
+ else if (entry == HTAB_DELETED_ENTRY)
{
if (!first_deleted_slot)
first_deleted_slot = &htab->entries[index];
if (first_deleted_slot)
{
htab->n_deleted--;
- *first_deleted_slot = EMPTY_ENTRY;
+ *first_deleted_slot = HTAB_EMPTY_ENTRY;
return first_deleted_slot;
}
PTR *slot;
slot = htab_find_slot_with_hash (htab, element, hash, NO_INSERT);
- if (*slot == EMPTY_ENTRY)
+ if (slot == NULL)
return;
if (htab->del_f)
(*htab->del_f) (*slot);
- *slot = DELETED_ENTRY;
+ *slot = HTAB_DELETED_ENTRY;
htab->n_deleted++;
}
htab_clear_slot (htab_t htab, PTR *slot)
{
if (slot < htab->entries || slot >= htab->entries + htab_size (htab)
- || *slot == EMPTY_ENTRY || *slot == DELETED_ENTRY)
+ || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
abort ();
if (htab->del_f)
(*htab->del_f) (*slot);
- *slot = DELETED_ENTRY;
+ *slot = HTAB_DELETED_ENTRY;
htab->n_deleted++;
}
{
PTR *slot;
PTR *limit;
-
+
slot = htab->entries;
limit = slot + htab_size (htab);
{
PTR x = *slot;
- if (x != EMPTY_ENTRY && x != DELETED_ENTRY)
+ if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
if (!(*callback) (slot, info))
break;
}
void
htab_traverse (htab_t htab, htab_trav callback, PTR info)
{
- if (htab_elements (htab) * 8 < htab_size (htab))
+ size_t size = htab_size (htab);
+ if (htab_elements (htab) * 8 < size && size > 32)
htab_expand (htab);
htab_traverse_noresize (htab, callback, info);
c += length;
switch(len) /* all the case statements fall through */
{
- case 11: c+=((hashval_t)k[10]<<24);
- case 10: c+=((hashval_t)k[9]<<16);
- case 9 : c+=((hashval_t)k[8]<<8);
+ case 11: c+=((hashval_t)k[10]<<24); /* fall through */
+ case 10: c+=((hashval_t)k[9]<<16); /* fall through */
+ case 9 : c+=((hashval_t)k[8]<<8); /* fall through */
/* the first byte of c is reserved for the length */
- case 8 : b+=((hashval_t)k[7]<<24);
- case 7 : b+=((hashval_t)k[6]<<16);
- case 6 : b+=((hashval_t)k[5]<<8);
- case 5 : b+=k[4];
- case 4 : a+=((hashval_t)k[3]<<24);
- case 3 : a+=((hashval_t)k[2]<<16);
- case 2 : a+=((hashval_t)k[1]<<8);
+ case 8 : b+=((hashval_t)k[7]<<24); /* fall through */
+ case 7 : b+=((hashval_t)k[6]<<16); /* fall through */
+ case 6 : b+=((hashval_t)k[5]<<8); /* fall through */
+ case 5 : b+=k[4]; /* fall through */
+ case 4 : a+=((hashval_t)k[3]<<24); /* fall through */
+ case 3 : a+=((hashval_t)k[2]<<16); /* fall through */
+ case 2 : a+=((hashval_t)k[1]<<8); /* fall through */
case 1 : a+=k[0];
/* case 0: nothing left to add */
}
/*-------------------------------------------- report the result */
return c;
}
+
+/* Returns a hash code for pointer P. Simplified version of evahash */
+
+static hashval_t
+hash_pointer (const PTR p)
+{
+ intptr_t v = (intptr_t) p;
+ unsigned a, b, c;
+
+ a = b = 0x9e3779b9;
+ a += v >> (sizeof (intptr_t) * CHAR_BIT / 2);
+ b += v & (((intptr_t) 1 << (sizeof (intptr_t) * CHAR_BIT / 2)) - 1);
+ c = 0x42135234;
+ mix (a, b, c);
+ return c;
+}