|
Packit |
032894 |
/* Copyright (C) 2000-2010 Red Hat, Inc.
|
|
Packit |
032894 |
This file is part of elfutils.
|
|
Packit |
032894 |
Written by Ulrich Drepper <drepper@redhat.com>, 2000.
|
|
Packit |
032894 |
|
|
Packit |
032894 |
This file is free software; you can redistribute it and/or modify
|
|
Packit |
032894 |
it under the terms of either
|
|
Packit |
032894 |
|
|
Packit |
032894 |
* the GNU Lesser General Public License as published by the Free
|
|
Packit |
032894 |
Software Foundation; either version 3 of the License, or (at
|
|
Packit |
032894 |
your option) any later version
|
|
Packit |
032894 |
|
|
Packit |
032894 |
or
|
|
Packit |
032894 |
|
|
Packit |
032894 |
* the GNU General Public License as published by the Free
|
|
Packit |
032894 |
Software Foundation; either version 2 of the License, or (at
|
|
Packit |
032894 |
your option) any later version
|
|
Packit |
032894 |
|
|
Packit |
032894 |
or both in parallel, as here.
|
|
Packit |
032894 |
|
|
Packit |
032894 |
elfutils is distributed in the hope that it will be useful, but
|
|
Packit |
032894 |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
032894 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
032894 |
General Public License for more details.
|
|
Packit |
032894 |
|
|
Packit |
032894 |
You should have received copies of the GNU General Public License and
|
|
Packit |
032894 |
the GNU Lesser General Public License along with this program. If
|
|
Packit |
032894 |
not, see <http://www.gnu.org/licenses/>. */
|
|
Packit |
032894 |
|
|
Packit |
032894 |
#include <assert.h>
|
|
Packit |
032894 |
#include <stdlib.h>
|
|
Packit |
032894 |
#include <system.h>
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Before including this file the following macros must be defined:
|
|
Packit |
032894 |
|
|
Packit |
032894 |
NAME name of the hash table structure.
|
|
Packit |
032894 |
TYPE data type of the hash table entries
|
|
Packit |
032894 |
COMPARE comparison function taking two pointers to TYPE objects
|
|
Packit |
032894 |
|
|
Packit |
032894 |
The following macros if present select features:
|
|
Packit |
032894 |
|
|
Packit |
032894 |
ITERATE iterating over the table entries is possible
|
|
Packit |
032894 |
REVERSE iterate in reverse order of insert
|
|
Packit |
032894 |
*/
|
|
Packit |
032894 |
|
|
Packit |
032894 |
|
|
Packit |
032894 |
static size_t
|
|
Packit |
032894 |
lookup (NAME *htab, HASHTYPE hval, TYPE val __attribute__ ((unused)))
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
/* First hash function: simply take the modul but prevent zero. Small values
|
|
Packit |
032894 |
can skip the division, which helps performance when this is common. */
|
|
Packit |
032894 |
size_t idx = 1 + (hval < htab->size ? hval : hval % htab->size);
|
|
Packit |
032894 |
|
|
Packit |
032894 |
if (htab->table[idx].hashval != 0)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
HASHTYPE hash;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
if (htab->table[idx].hashval == hval
|
|
Packit |
032894 |
&& COMPARE (htab->table[idx].data, val) == 0)
|
|
Packit |
032894 |
return idx;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Second hash function as suggested in [Knuth]. */
|
|
Packit |
032894 |
hash = 1 + hval % (htab->size - 2);
|
|
Packit |
032894 |
|
|
Packit |
032894 |
do
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
if (idx <= hash)
|
|
Packit |
032894 |
idx = htab->size + idx - hash;
|
|
Packit |
032894 |
else
|
|
Packit |
032894 |
idx -= hash;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* If entry is found use it. */
|
|
Packit |
032894 |
if (htab->table[idx].hashval == hval
|
|
Packit |
032894 |
&& COMPARE (htab->table[idx].data, val) == 0)
|
|
Packit |
032894 |
return idx;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
while (htab->table[idx].hashval);
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
return idx;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
|
|
Packit |
032894 |
static void
|
|
Packit |
032894 |
insert_entry_2 (NAME *htab, HASHTYPE hval, size_t idx, TYPE data)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
#ifdef ITERATE
|
|
Packit |
032894 |
if (htab->table[idx].hashval == 0)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
# ifdef REVERSE
|
|
Packit |
032894 |
htab->table[idx].next = htab->first;
|
|
Packit |
032894 |
htab->first = &htab->table[idx];
|
|
Packit |
032894 |
# else
|
|
Packit |
032894 |
/* Add the new value to the list. */
|
|
Packit |
032894 |
if (htab->first == NULL)
|
|
Packit |
032894 |
htab->first = htab->table[idx].next = &htab->table[idx];
|
|
Packit |
032894 |
else
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
htab->table[idx].next = htab->first->next;
|
|
Packit |
032894 |
htab->first = htab->first->next = &htab->table[idx];
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
# endif
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
#endif
|
|
Packit |
032894 |
|
|
Packit |
032894 |
htab->table[idx].hashval = hval;
|
|
Packit |
032894 |
htab->table[idx].data = data;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
++htab->filled;
|
|
Packit |
032894 |
if (100 * htab->filled > 90 * htab->size)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
/* Table is filled more than 90%. Resize the table. */
|
|
Packit |
032894 |
#ifdef ITERATE
|
|
Packit |
032894 |
__typeof__ (htab->first) first;
|
|
Packit |
032894 |
# ifndef REVERSE
|
|
Packit |
032894 |
__typeof__ (htab->first) runp;
|
|
Packit |
032894 |
# endif
|
|
Packit |
032894 |
#else
|
|
Packit |
032894 |
size_t old_size = htab->size;
|
|
Packit |
032894 |
#endif
|
|
Packit |
032894 |
#define _TABLE(name) \
|
|
Packit |
032894 |
name##_ent *table = htab->table
|
|
Packit |
032894 |
#define TABLE(name) _TABLE (name)
|
|
Packit |
032894 |
TABLE(NAME);
|
|
Packit |
032894 |
|
|
Packit |
032894 |
htab->size = next_prime (htab->size * 2);
|
|
Packit |
032894 |
htab->filled = 0;
|
|
Packit |
032894 |
#ifdef ITERATE
|
|
Packit |
032894 |
first = htab->first;
|
|
Packit |
032894 |
htab->first = NULL;
|
|
Packit |
032894 |
#endif
|
|
Packit |
032894 |
htab->table = calloc ((1 + htab->size), sizeof (htab->table[0]));
|
|
Packit |
032894 |
if (htab->table == NULL)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
/* We cannot enlarge the table. Live with what we got. This
|
|
Packit |
032894 |
might lead to an infinite loop at some point, though. */
|
|
Packit |
032894 |
htab->table = table;
|
|
Packit |
032894 |
return;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Add the old entries to the new table. When iteration is
|
|
Packit |
032894 |
supported we maintain the order. */
|
|
Packit |
032894 |
#ifdef ITERATE
|
|
Packit |
032894 |
# ifdef REVERSE
|
|
Packit |
032894 |
while (first != NULL)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
insert_entry_2 (htab, first->hashval,
|
|
Packit |
032894 |
lookup (htab, first->hashval, first->data),
|
|
Packit |
032894 |
first->data);
|
|
Packit |
032894 |
|
|
Packit |
032894 |
first = first->next;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
# else
|
|
Packit |
032894 |
assert (first != NULL);
|
|
Packit |
032894 |
runp = first = first->next;
|
|
Packit |
032894 |
do
|
|
Packit |
032894 |
insert_entry_2 (htab, runp->hashval,
|
|
Packit |
032894 |
lookup (htab, runp->hashval, runp->data), runp->data);
|
|
Packit |
032894 |
while ((runp = runp->next) != first);
|
|
Packit |
032894 |
# endif
|
|
Packit |
032894 |
#else
|
|
Packit |
032894 |
for (idx = 1; idx <= old_size; ++idx)
|
|
Packit |
032894 |
if (table[idx].hashval != 0)
|
|
Packit |
032894 |
insert_entry_2 (htab, table[idx].hashval,
|
|
Packit |
032894 |
lookup (htab, table[idx].hashval, table[idx].data),
|
|
Packit |
032894 |
table[idx].data);
|
|
Packit |
032894 |
#endif
|
|
Packit |
032894 |
|
|
Packit |
032894 |
free (table);
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
|
|
Packit |
032894 |
int
|
|
Packit |
032894 |
#define INIT(name) _INIT (name)
|
|
Packit |
032894 |
#define _INIT(name) \
|
|
Packit |
032894 |
name##_init
|
|
Packit |
032894 |
INIT(NAME) (NAME *htab, size_t init_size)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
/* We need the size to be a prime. */
|
|
Packit |
032894 |
init_size = next_prime (init_size);
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Initialize the data structure. */
|
|
Packit |
032894 |
htab->size = init_size;
|
|
Packit |
032894 |
htab->filled = 0;
|
|
Packit |
032894 |
#ifdef ITERATE
|
|
Packit |
032894 |
htab->first = NULL;
|
|
Packit |
032894 |
#endif
|
|
Packit |
032894 |
htab->table = (void *) calloc ((init_size + 1), sizeof (htab->table[0]));
|
|
Packit |
032894 |
if (htab->table == NULL)
|
|
Packit |
032894 |
return -1;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
return 0;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
|
|
Packit |
032894 |
int
|
|
Packit |
032894 |
#define FREE(name) _FREE (name)
|
|
Packit |
032894 |
#define _FREE(name) \
|
|
Packit |
032894 |
name##_free
|
|
Packit |
032894 |
FREE(NAME) (NAME *htab)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
free (htab->table);
|
|
Packit |
032894 |
return 0;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
|
|
Packit |
032894 |
int
|
|
Packit |
032894 |
#define INSERT(name) _INSERT (name)
|
|
Packit |
032894 |
#define _INSERT(name) \
|
|
Packit |
032894 |
name##_insert
|
|
Packit |
032894 |
INSERT(NAME) (NAME *htab, HASHTYPE hval, TYPE data)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
size_t idx;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Make the hash value nonzero. */
|
|
Packit |
032894 |
hval = hval ?: 1;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
idx = lookup (htab, hval, data);
|
|
Packit |
032894 |
|
|
Packit |
032894 |
if (htab->table[idx].hashval != 0)
|
|
Packit |
032894 |
/* We don't want to overwrite the old value. */
|
|
Packit |
032894 |
return -1;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* An empty bucket has been found. */
|
|
Packit |
032894 |
insert_entry_2 (htab, hval, idx, data);
|
|
Packit |
032894 |
return 0;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
|
|
Packit |
032894 |
#ifdef OVERWRITE
|
|
Packit |
032894 |
int
|
|
Packit |
032894 |
#define INSERT(name) _INSERT (name)
|
|
Packit |
032894 |
#define _INSERT(name) \
|
|
Packit |
032894 |
name##_overwrite
|
|
Packit |
032894 |
INSERT(NAME) (NAME *htab, HASHTYPE hval, TYPE data)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
size_t idx;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Make the hash value nonzero. */
|
|
Packit |
032894 |
hval = hval ?: 1;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
idx = lookup (htab, hval, data);
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* The correct bucket has been found. */
|
|
Packit |
032894 |
insert_entry_2 (htab, hval, idx, data);
|
|
Packit |
032894 |
return 0;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
#endif
|
|
Packit |
032894 |
|
|
Packit |
032894 |
|
|
Packit |
032894 |
TYPE
|
|
Packit |
032894 |
#define FIND(name) _FIND (name)
|
|
Packit |
032894 |
#define _FIND(name) \
|
|
Packit |
032894 |
name##_find
|
|
Packit |
032894 |
FIND(NAME) (NAME *htab, HASHTYPE hval, TYPE val)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
size_t idx;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Make the hash value nonzero. */
|
|
Packit |
032894 |
hval = hval ?: 1;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
idx = lookup (htab, hval, val);
|
|
Packit |
032894 |
|
|
Packit |
032894 |
if (htab->table[idx].hashval == 0)
|
|
Packit |
032894 |
return NULL;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
return htab->table[idx].data;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
|
|
Packit |
032894 |
#ifdef ITERATE
|
|
Packit |
032894 |
# define ITERATEFCT(name) _ITERATEFCT (name)
|
|
Packit |
032894 |
# define _ITERATEFCT(name) \
|
|
Packit |
032894 |
name##_iterate
|
|
Packit |
032894 |
TYPE
|
|
Packit |
032894 |
ITERATEFCT(NAME) (NAME *htab, void **ptr)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
void *p = *ptr;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
# define TYPENAME(name) _TYPENAME (name)
|
|
Packit |
032894 |
# define _TYPENAME(name) name##_ent
|
|
Packit |
032894 |
|
|
Packit |
032894 |
# ifdef REVERSE
|
|
Packit |
032894 |
if (p == NULL)
|
|
Packit |
032894 |
p = htab->first;
|
|
Packit |
032894 |
else
|
|
Packit |
032894 |
p = ((TYPENAME(NAME) *) p)->next;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
if (p == NULL)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
*ptr = NULL;
|
|
Packit |
032894 |
return NULL;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
# else
|
|
Packit |
032894 |
if (p == NULL)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
if (htab->first == NULL)
|
|
Packit |
032894 |
return NULL;
|
|
Packit |
032894 |
p = htab->first->next;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
else
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
if (p == htab->first)
|
|
Packit |
032894 |
return NULL;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
p = ((TYPENAME(NAME) *) p)->next;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
# endif
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Prepare the next element. If possible this will pull the data
|
|
Packit |
032894 |
into the cache, for reading. */
|
|
Packit |
032894 |
__builtin_prefetch (((TYPENAME(NAME) *) p)->next, 0, 2);
|
|
Packit |
032894 |
|
|
Packit |
032894 |
return ((TYPENAME(NAME) *) (*ptr = p))->data;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
#endif
|