Blame lib/dynamicsizehash.c

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