Blame lib/hash.c

Packit 33f14e
/* hash - hashing table processing.
Packit 33f14e
Packit 33f14e
   Copyright (C) 1998-2004, 2006-2007, 2009-2017 Free Software Foundation, Inc.
Packit 33f14e
Packit 33f14e
   Written by Jim Meyering, 1992.
Packit 33f14e
Packit 33f14e
   This program is free software: you can redistribute it and/or modify
Packit 33f14e
   it under the terms of the GNU General Public License as published by
Packit 33f14e
   the Free Software Foundation; either version 3 of the License, or
Packit 33f14e
   (at your option) any later version.
Packit 33f14e
Packit 33f14e
   This program is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 33f14e
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 33f14e
   GNU General Public License for more details.
Packit 33f14e
Packit 33f14e
   You should have received a copy of the GNU General Public License
Packit 33f14e
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 33f14e
Packit 33f14e
/* A generic hash table package.  */
Packit 33f14e
Packit 33f14e
/* Define USE_OBSTACK to 1 if you want the allocator to use obstacks instead
Packit 33f14e
   of malloc.  If you change USE_OBSTACK, you have to recompile!  */
Packit 33f14e
Packit 33f14e
#include <config.h>
Packit 33f14e
Packit 33f14e
#include "hash.h"
Packit 33f14e
Packit 33f14e
#include "bitrotate.h"
Packit 33f14e
#include "xalloc-oversized.h"
Packit 33f14e
Packit 33f14e
#include <stdint.h>
Packit 33f14e
#include <stdio.h>
Packit 33f14e
#include <stdlib.h>
Packit 33f14e
Packit 33f14e
#if USE_OBSTACK
Packit 33f14e
# include "obstack.h"
Packit 33f14e
# ifndef obstack_chunk_alloc
Packit 33f14e
#  define obstack_chunk_alloc malloc
Packit 33f14e
# endif
Packit 33f14e
# ifndef obstack_chunk_free
Packit 33f14e
#  define obstack_chunk_free free
Packit 33f14e
# endif
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
struct hash_entry
Packit 33f14e
  {
Packit 33f14e
    void *data;
Packit 33f14e
    struct hash_entry *next;
Packit 33f14e
  };
Packit 33f14e
Packit 33f14e
struct hash_table
Packit 33f14e
  {
Packit 33f14e
    /* The array of buckets starts at BUCKET and extends to BUCKET_LIMIT-1,
Packit 33f14e
       for a possibility of N_BUCKETS.  Among those, N_BUCKETS_USED buckets
Packit 33f14e
       are not empty, there are N_ENTRIES active entries in the table.  */
Packit 33f14e
    struct hash_entry *bucket;
Packit 33f14e
    struct hash_entry const *bucket_limit;
Packit 33f14e
    size_t n_buckets;
Packit 33f14e
    size_t n_buckets_used;
Packit 33f14e
    size_t n_entries;
Packit 33f14e
Packit 33f14e
    /* Tuning arguments, kept in a physically separate structure.  */
Packit 33f14e
    const Hash_tuning *tuning;
Packit 33f14e
Packit 33f14e
    /* Three functions are given to 'hash_initialize', see the documentation
Packit 33f14e
       block for this function.  In a word, HASHER randomizes a user entry
Packit 33f14e
       into a number up from 0 up to some maximum minus 1; COMPARATOR returns
Packit 33f14e
       true if two user entries compare equally; and DATA_FREER is the cleanup
Packit 33f14e
       function for a user entry.  */
Packit 33f14e
    Hash_hasher hasher;
Packit 33f14e
    Hash_comparator comparator;
Packit 33f14e
    Hash_data_freer data_freer;
Packit 33f14e
Packit 33f14e
    /* A linked list of freed struct hash_entry structs.  */
Packit 33f14e
    struct hash_entry *free_entry_list;
Packit 33f14e
Packit 33f14e
#if USE_OBSTACK
Packit 33f14e
    /* Whenever obstacks are used, it is possible to allocate all overflowed
Packit 33f14e
       entries into a single stack, so they all can be freed in a single
Packit 33f14e
       operation.  It is not clear if the speedup is worth the trouble.  */
Packit 33f14e
    struct obstack entry_stack;
Packit 33f14e
#endif
Packit 33f14e
  };
Packit 33f14e
Packit 33f14e
/* A hash table contains many internal entries, each holding a pointer to
Packit 33f14e
   some user-provided data (also called a user entry).  An entry indistinctly
Packit 33f14e
   refers to both the internal entry and its associated user entry.  A user
Packit 33f14e
   entry contents may be hashed by a randomization function (the hashing
Packit 33f14e
   function, or just "hasher" for short) into a number (or "slot") between 0
Packit 33f14e
   and the current table size.  At each slot position in the hash table,
Packit 33f14e
   starts a linked chain of entries for which the user data all hash to this
Packit 33f14e
   slot.  A bucket is the collection of all entries hashing to the same slot.
Packit 33f14e
Packit 33f14e
   A good "hasher" function will distribute entries rather evenly in buckets.
Packit 33f14e
   In the ideal case, the length of each bucket is roughly the number of
Packit 33f14e
   entries divided by the table size.  Finding the slot for a data is usually
Packit 33f14e
   done in constant time by the "hasher", and the later finding of a precise
Packit 33f14e
   entry is linear in time with the size of the bucket.  Consequently, a
Packit 33f14e
   larger hash table size (that is, a larger number of buckets) is prone to
Packit 33f14e
   yielding shorter chains, *given* the "hasher" function behaves properly.
Packit 33f14e
Packit 33f14e
   Long buckets slow down the lookup algorithm.  One might use big hash table
Packit 33f14e
   sizes in hope to reduce the average length of buckets, but this might
Packit 33f14e
   become inordinate, as unused slots in the hash table take some space.  The
Packit 33f14e
   best bet is to make sure you are using a good "hasher" function (beware
Packit 33f14e
   that those are not that easy to write! :-), and to use a table size
Packit 33f14e
   larger than the actual number of entries.  */
Packit 33f14e
Packit 33f14e
/* If an insertion makes the ratio of nonempty buckets to table size larger
Packit 33f14e
   than the growth threshold (a number between 0.0 and 1.0), then increase
Packit 33f14e
   the table size by multiplying by the growth factor (a number greater than
Packit 33f14e
   1.0).  The growth threshold defaults to 0.8, and the growth factor
Packit 33f14e
   defaults to 1.414, meaning that the table will have doubled its size
Packit 33f14e
   every second time 80% of the buckets get used.  */
Packit 33f14e
#define DEFAULT_GROWTH_THRESHOLD 0.8f
Packit 33f14e
#define DEFAULT_GROWTH_FACTOR 1.414f
Packit 33f14e
Packit 33f14e
/* If a deletion empties a bucket and causes the ratio of used buckets to
Packit 33f14e
   table size to become smaller than the shrink threshold (a number between
Packit 33f14e
   0.0 and 1.0), then shrink the table by multiplying by the shrink factor (a
Packit 33f14e
   number greater than the shrink threshold but smaller than 1.0).  The shrink
Packit 33f14e
   threshold and factor default to 0.0 and 1.0, meaning that the table never
Packit 33f14e
   shrinks.  */
Packit 33f14e
#define DEFAULT_SHRINK_THRESHOLD 0.0f
Packit 33f14e
#define DEFAULT_SHRINK_FACTOR 1.0f
Packit 33f14e
Packit 33f14e
/* Use this to initialize or reset a TUNING structure to
Packit 33f14e
   some sensible values. */
Packit 33f14e
static const Hash_tuning default_tuning =
Packit 33f14e
  {
Packit 33f14e
    DEFAULT_SHRINK_THRESHOLD,
Packit 33f14e
    DEFAULT_SHRINK_FACTOR,
Packit 33f14e
    DEFAULT_GROWTH_THRESHOLD,
Packit 33f14e
    DEFAULT_GROWTH_FACTOR,
Packit 33f14e
    false
Packit 33f14e
  };
Packit 33f14e
Packit 33f14e
/* Information and lookup.  */
Packit 33f14e
Packit 33f14e
/* The following few functions provide information about the overall hash
Packit 33f14e
   table organization: the number of entries, number of buckets and maximum
Packit 33f14e
   length of buckets.  */
Packit 33f14e
Packit 33f14e
/* Return the number of buckets in the hash table.  The table size, the total
Packit 33f14e
   number of buckets (used plus unused), or the maximum number of slots, are
Packit 33f14e
   the same quantity.  */
Packit 33f14e
Packit 33f14e
size_t
Packit 33f14e
hash_get_n_buckets (const Hash_table *table)
Packit 33f14e
{
Packit 33f14e
  return table->n_buckets;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Return the number of slots in use (non-empty buckets).  */
Packit 33f14e
Packit 33f14e
size_t
Packit 33f14e
hash_get_n_buckets_used (const Hash_table *table)
Packit 33f14e
{
Packit 33f14e
  return table->n_buckets_used;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Return the number of active entries.  */
Packit 33f14e
Packit 33f14e
size_t
Packit 33f14e
hash_get_n_entries (const Hash_table *table)
Packit 33f14e
{
Packit 33f14e
  return table->n_entries;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Return the length of the longest chain (bucket).  */
Packit 33f14e
Packit 33f14e
size_t
Packit 33f14e
hash_get_max_bucket_length (const Hash_table *table)
Packit 33f14e
{
Packit 33f14e
  struct hash_entry const *bucket;
Packit 33f14e
  size_t max_bucket_length = 0;
Packit 33f14e
Packit 33f14e
  for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
Packit 33f14e
    {
Packit 33f14e
      if (bucket->data)
Packit 33f14e
        {
Packit 33f14e
          struct hash_entry const *cursor = bucket;
Packit 33f14e
          size_t bucket_length = 1;
Packit 33f14e
Packit 33f14e
          while (cursor = cursor->next, cursor)
Packit 33f14e
            bucket_length++;
Packit 33f14e
Packit 33f14e
          if (bucket_length > max_bucket_length)
Packit 33f14e
            max_bucket_length = bucket_length;
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return max_bucket_length;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Do a mild validation of a hash table, by traversing it and checking two
Packit 33f14e
   statistics.  */
Packit 33f14e
Packit 33f14e
bool
Packit 33f14e
hash_table_ok (const Hash_table *table)
Packit 33f14e
{
Packit 33f14e
  struct hash_entry const *bucket;
Packit 33f14e
  size_t n_buckets_used = 0;
Packit 33f14e
  size_t n_entries = 0;
Packit 33f14e
Packit 33f14e
  for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
Packit 33f14e
    {
Packit 33f14e
      if (bucket->data)
Packit 33f14e
        {
Packit 33f14e
          struct hash_entry const *cursor = bucket;
Packit 33f14e
Packit 33f14e
          /* Count bucket head.  */
Packit 33f14e
          n_buckets_used++;
Packit 33f14e
          n_entries++;
Packit 33f14e
Packit 33f14e
          /* Count bucket overflow.  */
Packit 33f14e
          while (cursor = cursor->next, cursor)
Packit 33f14e
            n_entries++;
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  if (n_buckets_used == table->n_buckets_used && n_entries == table->n_entries)
Packit 33f14e
    return true;
Packit 33f14e
Packit 33f14e
  return false;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
void
Packit 33f14e
hash_print_statistics (const Hash_table *table, FILE *stream)
Packit 33f14e
{
Packit 33f14e
  size_t n_entries = hash_get_n_entries (table);
Packit 33f14e
  size_t n_buckets = hash_get_n_buckets (table);
Packit 33f14e
  size_t n_buckets_used = hash_get_n_buckets_used (table);
Packit 33f14e
  size_t max_bucket_length = hash_get_max_bucket_length (table);
Packit 33f14e
Packit 33f14e
  fprintf (stream, "# entries:         %lu\n", (unsigned long int) n_entries);
Packit 33f14e
  fprintf (stream, "# buckets:         %lu\n", (unsigned long int) n_buckets);
Packit 33f14e
  fprintf (stream, "# buckets used:    %lu (%.2f%%)\n",
Packit 33f14e
           (unsigned long int) n_buckets_used,
Packit 33f14e
           (100.0 * n_buckets_used) / n_buckets);
Packit 33f14e
  fprintf (stream, "max bucket length: %lu\n",
Packit 33f14e
           (unsigned long int) max_bucket_length);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Hash KEY and return a pointer to the selected bucket.
Packit 33f14e
   If TABLE->hasher misbehaves, abort.  */
Packit 33f14e
static struct hash_entry *
Packit 33f14e
safe_hasher (const Hash_table *table, const void *key)
Packit 33f14e
{
Packit 33f14e
  size_t n = table->hasher (key, table->n_buckets);
Packit 33f14e
  if (! (n < table->n_buckets))
Packit 33f14e
    abort ();
Packit 33f14e
  return table->bucket + n;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* If ENTRY matches an entry already in the hash table, return the
Packit 33f14e
   entry from the table.  Otherwise, return NULL.  */
Packit 33f14e
Packit 33f14e
void *
Packit 33f14e
hash_lookup (const Hash_table *table, const void *entry)
Packit 33f14e
{
Packit 33f14e
  struct hash_entry const *bucket = safe_hasher (table, entry);
Packit 33f14e
  struct hash_entry const *cursor;
Packit 33f14e
Packit 33f14e
  if (bucket->data == NULL)
Packit 33f14e
    return NULL;
Packit 33f14e
Packit 33f14e
  for (cursor = bucket; cursor; cursor = cursor->next)
Packit 33f14e
    if (entry == cursor->data || table->comparator (entry, cursor->data))
Packit 33f14e
      return cursor->data;
Packit 33f14e
Packit 33f14e
  return NULL;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Walking.  */
Packit 33f14e
Packit 33f14e
/* The functions in this page traverse the hash table and process the
Packit 33f14e
   contained entries.  For the traversal to work properly, the hash table
Packit 33f14e
   should not be resized nor modified while any particular entry is being
Packit 33f14e
   processed.  In particular, entries should not be added, and an entry
Packit 33f14e
   may be removed only if there is no shrink threshold and the entry being
Packit 33f14e
   removed has already been passed to hash_get_next.  */
Packit 33f14e
Packit 33f14e
/* Return the first data in the table, or NULL if the table is empty.  */
Packit 33f14e
Packit 33f14e
void *
Packit 33f14e
hash_get_first (const Hash_table *table)
Packit 33f14e
{
Packit 33f14e
  struct hash_entry const *bucket;
Packit 33f14e
Packit 33f14e
  if (table->n_entries == 0)
Packit 33f14e
    return NULL;
Packit 33f14e
Packit 33f14e
  for (bucket = table->bucket; ; bucket++)
Packit 33f14e
    if (! (bucket < table->bucket_limit))
Packit 33f14e
      abort ();
Packit 33f14e
    else if (bucket->data)
Packit 33f14e
      return bucket->data;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Return the user data for the entry following ENTRY, where ENTRY has been
Packit 33f14e
   returned by a previous call to either 'hash_get_first' or 'hash_get_next'.
Packit 33f14e
   Return NULL if there are no more entries.  */
Packit 33f14e
Packit 33f14e
void *
Packit 33f14e
hash_get_next (const Hash_table *table, const void *entry)
Packit 33f14e
{
Packit 33f14e
  struct hash_entry const *bucket = safe_hasher (table, entry);
Packit 33f14e
  struct hash_entry const *cursor;
Packit 33f14e
Packit 33f14e
  /* Find next entry in the same bucket.  */
Packit 33f14e
  cursor = bucket;
Packit 33f14e
  do
Packit 33f14e
    {
Packit 33f14e
      if (cursor->data == entry && cursor->next)
Packit 33f14e
        return cursor->next->data;
Packit 33f14e
      cursor = cursor->next;
Packit 33f14e
    }
Packit 33f14e
  while (cursor != NULL);
Packit 33f14e
Packit 33f14e
  /* Find first entry in any subsequent bucket.  */
Packit 33f14e
  while (++bucket < table->bucket_limit)
Packit 33f14e
    if (bucket->data)
Packit 33f14e
      return bucket->data;
Packit 33f14e
Packit 33f14e
  /* None found.  */
Packit 33f14e
  return NULL;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Fill BUFFER with pointers to active user entries in the hash table, then
Packit 33f14e
   return the number of pointers copied.  Do not copy more than BUFFER_SIZE
Packit 33f14e
   pointers.  */
Packit 33f14e
Packit 33f14e
size_t
Packit 33f14e
hash_get_entries (const Hash_table *table, void **buffer,
Packit 33f14e
                  size_t buffer_size)
Packit 33f14e
{
Packit 33f14e
  size_t counter = 0;
Packit 33f14e
  struct hash_entry const *bucket;
Packit 33f14e
  struct hash_entry const *cursor;
Packit 33f14e
Packit 33f14e
  for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
Packit 33f14e
    {
Packit 33f14e
      if (bucket->data)
Packit 33f14e
        {
Packit 33f14e
          for (cursor = bucket; cursor; cursor = cursor->next)
Packit 33f14e
            {
Packit 33f14e
              if (counter >= buffer_size)
Packit 33f14e
                return counter;
Packit 33f14e
              buffer[counter++] = cursor->data;
Packit 33f14e
            }
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return counter;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Call a PROCESSOR function for each entry of a hash table, and return the
Packit 33f14e
   number of entries for which the processor function returned success.  A
Packit 33f14e
   pointer to some PROCESSOR_DATA which will be made available to each call to
Packit 33f14e
   the processor function.  The PROCESSOR accepts two arguments: the first is
Packit 33f14e
   the user entry being walked into, the second is the value of PROCESSOR_DATA
Packit 33f14e
   as received.  The walking continue for as long as the PROCESSOR function
Packit 33f14e
   returns nonzero.  When it returns zero, the walking is interrupted.  */
Packit 33f14e
Packit 33f14e
size_t
Packit 33f14e
hash_do_for_each (const Hash_table *table, Hash_processor processor,
Packit 33f14e
                  void *processor_data)
Packit 33f14e
{
Packit 33f14e
  size_t counter = 0;
Packit 33f14e
  struct hash_entry const *bucket;
Packit 33f14e
  struct hash_entry const *cursor;
Packit 33f14e
Packit 33f14e
  for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
Packit 33f14e
    {
Packit 33f14e
      if (bucket->data)
Packit 33f14e
        {
Packit 33f14e
          for (cursor = bucket; cursor; cursor = cursor->next)
Packit 33f14e
            {
Packit 33f14e
              if (! processor (cursor->data, processor_data))
Packit 33f14e
                return counter;
Packit 33f14e
              counter++;
Packit 33f14e
            }
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return counter;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Allocation and clean-up.  */
Packit 33f14e
Packit 33f14e
/* Return a hash index for a NUL-terminated STRING between 0 and N_BUCKETS-1.
Packit 33f14e
   This is a convenience routine for constructing other hashing functions.  */
Packit 33f14e
Packit 33f14e
#if USE_DIFF_HASH
Packit 33f14e
Packit 33f14e
/* About hashings, Paul Eggert writes to me (FP), on 1994-01-01: "Please see
Packit 33f14e
   B. J. McKenzie, R. Harries & T. Bell, Selecting a hashing algorithm,
Packit 33f14e
   Software--practice & experience 20, 2 (Feb 1990), 209-224.  Good hash
Packit 33f14e
   algorithms tend to be domain-specific, so what's good for [diffutils'] io.c
Packit 33f14e
   may not be good for your application."  */
Packit 33f14e
Packit 33f14e
size_t
Packit 33f14e
hash_string (const char *string, size_t n_buckets)
Packit 33f14e
{
Packit 33f14e
# define HASH_ONE_CHAR(Value, Byte) \
Packit 33f14e
  ((Byte) + rotl_sz (Value, 7))
Packit 33f14e
Packit 33f14e
  size_t value = 0;
Packit 33f14e
  unsigned char ch;
Packit 33f14e
Packit 33f14e
  for (; (ch = *string); string++)
Packit 33f14e
    value = HASH_ONE_CHAR (value, ch);
Packit 33f14e
  return value % n_buckets;
Packit 33f14e
Packit 33f14e
# undef HASH_ONE_CHAR
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#else /* not USE_DIFF_HASH */
Packit 33f14e
Packit 33f14e
/* This one comes from 'recode', and performs a bit better than the above as
Packit 33f14e
   per a few experiments.  It is inspired from a hashing routine found in the
Packit 33f14e
   very old Cyber 'snoop', itself written in typical Greg Mansfield style.
Packit 33f14e
   (By the way, what happened to this excellent man?  Is he still alive?)  */
Packit 33f14e
Packit 33f14e
size_t
Packit 33f14e
hash_string (const char *string, size_t n_buckets)
Packit 33f14e
{
Packit 33f14e
  size_t value = 0;
Packit 33f14e
  unsigned char ch;
Packit 33f14e
Packit 33f14e
  for (; (ch = *string); string++)
Packit 33f14e
    value = (value * 31 + ch) % n_buckets;
Packit 33f14e
  return value;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#endif /* not USE_DIFF_HASH */
Packit 33f14e
Packit 33f14e
/* Return true if CANDIDATE is a prime number.  CANDIDATE should be an odd
Packit 33f14e
   number at least equal to 11.  */
Packit 33f14e
Packit 33f14e
static bool _GL_ATTRIBUTE_CONST
Packit 33f14e
is_prime (size_t candidate)
Packit 33f14e
{
Packit 33f14e
  size_t divisor = 3;
Packit 33f14e
  size_t square = divisor * divisor;
Packit 33f14e
Packit 33f14e
  while (square < candidate && (candidate % divisor))
Packit 33f14e
    {
Packit 33f14e
      divisor++;
Packit 33f14e
      square += 4 * divisor;
Packit 33f14e
      divisor++;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return (candidate % divisor ? true : false);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Round a given CANDIDATE number up to the nearest prime, and return that
Packit 33f14e
   prime.  Primes lower than 10 are merely skipped.  */
Packit 33f14e
Packit 33f14e
static size_t _GL_ATTRIBUTE_CONST
Packit 33f14e
next_prime (size_t candidate)
Packit 33f14e
{
Packit 33f14e
  /* Skip small primes.  */
Packit 33f14e
  if (candidate < 10)
Packit 33f14e
    candidate = 10;
Packit 33f14e
Packit 33f14e
  /* Make it definitely odd.  */
Packit 33f14e
  candidate |= 1;
Packit 33f14e
Packit 33f14e
  while (SIZE_MAX != candidate && !is_prime (candidate))
Packit 33f14e
    candidate += 2;
Packit 33f14e
Packit 33f14e
  return candidate;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
void
Packit 33f14e
hash_reset_tuning (Hash_tuning *tuning)
Packit 33f14e
{
Packit 33f14e
  *tuning = default_tuning;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* If the user passes a NULL hasher, we hash the raw pointer.  */
Packit 33f14e
static size_t
Packit 33f14e
raw_hasher (const void *data, size_t n)
Packit 33f14e
{
Packit 33f14e
  /* When hashing unique pointers, it is often the case that they were
Packit 33f14e
     generated by malloc and thus have the property that the low-order
Packit 33f14e
     bits are 0.  As this tends to give poorer performance with small
Packit 33f14e
     tables, we rotate the pointer value before performing division,
Packit 33f14e
     in an attempt to improve hash quality.  */
Packit 33f14e
  size_t val = rotr_sz ((size_t) data, 3);
Packit 33f14e
  return val % n;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* If the user passes a NULL comparator, we use pointer comparison.  */
Packit 33f14e
static bool
Packit 33f14e
raw_comparator (const void *a, const void *b)
Packit 33f14e
{
Packit 33f14e
  return a == b;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
Packit 33f14e
/* For the given hash TABLE, check the user supplied tuning structure for
Packit 33f14e
   reasonable values, and return true if there is no gross error with it.
Packit 33f14e
   Otherwise, definitively reset the TUNING field to some acceptable default
Packit 33f14e
   in the hash table (that is, the user loses the right of further modifying
Packit 33f14e
   tuning arguments), and return false.  */
Packit 33f14e
Packit 33f14e
static bool
Packit 33f14e
check_tuning (Hash_table *table)
Packit 33f14e
{
Packit 33f14e
  const Hash_tuning *tuning = table->tuning;
Packit 33f14e
  float epsilon;
Packit 33f14e
  if (tuning == &default_tuning)
Packit 33f14e
    return true;
Packit 33f14e
Packit 33f14e
  /* Be a bit stricter than mathematics would require, so that
Packit 33f14e
     rounding errors in size calculations do not cause allocations to
Packit 33f14e
     fail to grow or shrink as they should.  The smallest allocation
Packit 33f14e
     is 11 (due to next_prime's algorithm), so an epsilon of 0.1
Packit 33f14e
     should be good enough.  */
Packit 33f14e
  epsilon = 0.1f;
Packit 33f14e
Packit 33f14e
  if (epsilon < tuning->growth_threshold
Packit 33f14e
      && tuning->growth_threshold < 1 - epsilon
Packit 33f14e
      && 1 + epsilon < tuning->growth_factor
Packit 33f14e
      && 0 <= tuning->shrink_threshold
Packit 33f14e
      && tuning->shrink_threshold + epsilon < tuning->shrink_factor
Packit 33f14e
      && tuning->shrink_factor <= 1
Packit 33f14e
      && tuning->shrink_threshold + epsilon < tuning->growth_threshold)
Packit 33f14e
    return true;
Packit 33f14e
Packit 33f14e
  table->tuning = &default_tuning;
Packit 33f14e
  return false;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Compute the size of the bucket array for the given CANDIDATE and
Packit 33f14e
   TUNING, or return 0 if there is no possible way to allocate that
Packit 33f14e
   many entries.  */
Packit 33f14e
Packit 33f14e
static size_t _GL_ATTRIBUTE_PURE
Packit 33f14e
compute_bucket_size (size_t candidate, const Hash_tuning *tuning)
Packit 33f14e
{
Packit 33f14e
  if (!tuning->is_n_buckets)
Packit 33f14e
    {
Packit 33f14e
      float new_candidate = candidate / tuning->growth_threshold;
Packit 33f14e
      if (SIZE_MAX <= new_candidate)
Packit 33f14e
        return 0;
Packit 33f14e
      candidate = new_candidate;
Packit 33f14e
    }
Packit 33f14e
  candidate = next_prime (candidate);
Packit 33f14e
  if (xalloc_oversized (candidate, sizeof (struct hash_entry *)))
Packit 33f14e
    return 0;
Packit 33f14e
  return candidate;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Allocate and return a new hash table, or NULL upon failure.  The initial
Packit 33f14e
   number of buckets is automatically selected so as to _guarantee_ that you
Packit 33f14e
   may insert at least CANDIDATE different user entries before any growth of
Packit 33f14e
   the hash table size occurs.  So, if have a reasonably tight a-priori upper
Packit 33f14e
   bound on the number of entries you intend to insert in the hash table, you
Packit 33f14e
   may save some table memory and insertion time, by specifying it here.  If
Packit 33f14e
   the IS_N_BUCKETS field of the TUNING structure is true, the CANDIDATE
Packit 33f14e
   argument has its meaning changed to the wanted number of buckets.
Packit 33f14e
Packit 33f14e
   TUNING points to a structure of user-supplied values, in case some fine
Packit 33f14e
   tuning is wanted over the default behavior of the hasher.  If TUNING is
Packit 33f14e
   NULL, the default tuning parameters are used instead.  If TUNING is
Packit 33f14e
   provided but the values requested are out of bounds or might cause
Packit 33f14e
   rounding errors, return NULL.
Packit 33f14e
Packit 33f14e
   The user-supplied HASHER function, when not NULL, accepts two
Packit 33f14e
   arguments ENTRY and TABLE_SIZE.  It computes, by hashing ENTRY contents, a
Packit 33f14e
   slot number for that entry which should be in the range 0..TABLE_SIZE-1.
Packit 33f14e
   This slot number is then returned.
Packit 33f14e
Packit 33f14e
   The user-supplied COMPARATOR function, when not NULL, accepts two
Packit 33f14e
   arguments pointing to user data, it then returns true for a pair of entries
Packit 33f14e
   that compare equal, or false otherwise.  This function is internally called
Packit 33f14e
   on entries which are already known to hash to the same bucket index,
Packit 33f14e
   but which are distinct pointers.
Packit 33f14e
Packit 33f14e
   The user-supplied DATA_FREER function, when not NULL, may be later called
Packit 33f14e
   with the user data as an argument, just before the entry containing the
Packit 33f14e
   data gets freed.  This happens from within 'hash_free' or 'hash_clear'.
Packit 33f14e
   You should specify this function only if you want these functions to free
Packit 33f14e
   all of your 'data' data.  This is typically the case when your data is
Packit 33f14e
   simply an auxiliary struct that you have malloc'd to aggregate several
Packit 33f14e
   values.  */
Packit 33f14e
Packit 33f14e
Hash_table *
Packit 33f14e
hash_initialize (size_t candidate, const Hash_tuning *tuning,
Packit 33f14e
                 Hash_hasher hasher, Hash_comparator comparator,
Packit 33f14e
                 Hash_data_freer data_freer)
Packit 33f14e
{
Packit 33f14e
  Hash_table *table;
Packit 33f14e
Packit 33f14e
  if (hasher == NULL)
Packit 33f14e
    hasher = raw_hasher;
Packit 33f14e
  if (comparator == NULL)
Packit 33f14e
    comparator = raw_comparator;
Packit 33f14e
Packit 33f14e
  table = malloc (sizeof *table);
Packit 33f14e
  if (table == NULL)
Packit 33f14e
    return NULL;
Packit 33f14e
Packit 33f14e
  if (!tuning)
Packit 33f14e
    tuning = &default_tuning;
Packit 33f14e
  table->tuning = tuning;
Packit 33f14e
  if (!check_tuning (table))
Packit 33f14e
    {
Packit 33f14e
      /* Fail if the tuning options are invalid.  This is the only occasion
Packit 33f14e
         when the user gets some feedback about it.  Once the table is created,
Packit 33f14e
         if the user provides invalid tuning options, we silently revert to
Packit 33f14e
         using the defaults, and ignore further request to change the tuning
Packit 33f14e
         options.  */
Packit 33f14e
      goto fail;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  table->n_buckets = compute_bucket_size (candidate, tuning);
Packit 33f14e
  if (!table->n_buckets)
Packit 33f14e
    goto fail;
Packit 33f14e
Packit 33f14e
  table->bucket = calloc (table->n_buckets, sizeof *table->bucket);
Packit 33f14e
  if (table->bucket == NULL)
Packit 33f14e
    goto fail;
Packit 33f14e
  table->bucket_limit = table->bucket + table->n_buckets;
Packit 33f14e
  table->n_buckets_used = 0;
Packit 33f14e
  table->n_entries = 0;
Packit 33f14e
Packit 33f14e
  table->hasher = hasher;
Packit 33f14e
  table->comparator = comparator;
Packit 33f14e
  table->data_freer = data_freer;
Packit 33f14e
Packit 33f14e
  table->free_entry_list = NULL;
Packit 33f14e
#if USE_OBSTACK
Packit 33f14e
  obstack_init (&table->entry_stack);
Packit 33f14e
#endif
Packit 33f14e
  return table;
Packit 33f14e
Packit 33f14e
 fail:
Packit 33f14e
  free (table);
Packit 33f14e
  return NULL;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Make all buckets empty, placing any chained entries on the free list.
Packit 33f14e
   Apply the user-specified function data_freer (if any) to the datas of any
Packit 33f14e
   affected entries.  */
Packit 33f14e
Packit 33f14e
void
Packit 33f14e
hash_clear (Hash_table *table)
Packit 33f14e
{
Packit 33f14e
  struct hash_entry *bucket;
Packit 33f14e
Packit 33f14e
  for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
Packit 33f14e
    {
Packit 33f14e
      if (bucket->data)
Packit 33f14e
        {
Packit 33f14e
          struct hash_entry *cursor;
Packit 33f14e
          struct hash_entry *next;
Packit 33f14e
Packit 33f14e
          /* Free the bucket overflow.  */
Packit 33f14e
          for (cursor = bucket->next; cursor; cursor = next)
Packit 33f14e
            {
Packit 33f14e
              if (table->data_freer)
Packit 33f14e
                table->data_freer (cursor->data);
Packit 33f14e
              cursor->data = NULL;
Packit 33f14e
Packit 33f14e
              next = cursor->next;
Packit 33f14e
              /* Relinking is done one entry at a time, as it is to be expected
Packit 33f14e
                 that overflows are either rare or short.  */
Packit 33f14e
              cursor->next = table->free_entry_list;
Packit 33f14e
              table->free_entry_list = cursor;
Packit 33f14e
            }
Packit 33f14e
Packit 33f14e
          /* Free the bucket head.  */
Packit 33f14e
          if (table->data_freer)
Packit 33f14e
            table->data_freer (bucket->data);
Packit 33f14e
          bucket->data = NULL;
Packit 33f14e
          bucket->next = NULL;
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  table->n_buckets_used = 0;
Packit 33f14e
  table->n_entries = 0;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Reclaim all storage associated with a hash table.  If a data_freer
Packit 33f14e
   function has been supplied by the user when the hash table was created,
Packit 33f14e
   this function applies it to the data of each entry before freeing that
Packit 33f14e
   entry.  */
Packit 33f14e
Packit 33f14e
void
Packit 33f14e
hash_free (Hash_table *table)
Packit 33f14e
{
Packit 33f14e
  struct hash_entry *bucket;
Packit 33f14e
  struct hash_entry *cursor;
Packit 33f14e
  struct hash_entry *next;
Packit 33f14e
Packit 33f14e
  /* Call the user data_freer function.  */
Packit 33f14e
  if (table->data_freer && table->n_entries)
Packit 33f14e
    {
Packit 33f14e
      for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
Packit 33f14e
        {
Packit 33f14e
          if (bucket->data)
Packit 33f14e
            {
Packit 33f14e
              for (cursor = bucket; cursor; cursor = cursor->next)
Packit 33f14e
                table->data_freer (cursor->data);
Packit 33f14e
            }
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
#if USE_OBSTACK
Packit 33f14e
Packit 33f14e
  obstack_free (&table->entry_stack, NULL);
Packit 33f14e
Packit 33f14e
#else
Packit 33f14e
Packit 33f14e
  /* Free all bucket overflowed entries.  */
Packit 33f14e
  for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
Packit 33f14e
    {
Packit 33f14e
      for (cursor = bucket->next; cursor; cursor = next)
Packit 33f14e
        {
Packit 33f14e
          next = cursor->next;
Packit 33f14e
          free (cursor);
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* Also reclaim the internal list of previously freed entries.  */
Packit 33f14e
  for (cursor = table->free_entry_list; cursor; cursor = next)
Packit 33f14e
    {
Packit 33f14e
      next = cursor->next;
Packit 33f14e
      free (cursor);
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
  /* Free the remainder of the hash table structure.  */
Packit 33f14e
  free (table->bucket);
Packit 33f14e
  free (table);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Insertion and deletion.  */
Packit 33f14e
Packit 33f14e
/* Get a new hash entry for a bucket overflow, possibly by recycling a
Packit 33f14e
   previously freed one.  If this is not possible, allocate a new one.  */
Packit 33f14e
Packit 33f14e
static struct hash_entry *
Packit 33f14e
allocate_entry (Hash_table *table)
Packit 33f14e
{
Packit 33f14e
  struct hash_entry *new;
Packit 33f14e
Packit 33f14e
  if (table->free_entry_list)
Packit 33f14e
    {
Packit 33f14e
      new = table->free_entry_list;
Packit 33f14e
      table->free_entry_list = new->next;
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
#if USE_OBSTACK
Packit 33f14e
      new = obstack_alloc (&table->entry_stack, sizeof *new);
Packit 33f14e
#else
Packit 33f14e
      new = malloc (sizeof *new);
Packit 33f14e
#endif
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return new;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Free a hash entry which was part of some bucket overflow,
Packit 33f14e
   saving it for later recycling.  */
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
free_entry (Hash_table *table, struct hash_entry *entry)
Packit 33f14e
{
Packit 33f14e
  entry->data = NULL;
Packit 33f14e
  entry->next = table->free_entry_list;
Packit 33f14e
  table->free_entry_list = entry;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* This private function is used to help with insertion and deletion.  When
Packit 33f14e
   ENTRY matches an entry in the table, return a pointer to the corresponding
Packit 33f14e
   user data and set *BUCKET_HEAD to the head of the selected bucket.
Packit 33f14e
   Otherwise, return NULL.  When DELETE is true and ENTRY matches an entry in
Packit 33f14e
   the table, unlink the matching entry.  */
Packit 33f14e
Packit 33f14e
static void *
Packit 33f14e
hash_find_entry (Hash_table *table, const void *entry,
Packit 33f14e
                 struct hash_entry **bucket_head, bool delete)
Packit 33f14e
{
Packit 33f14e
  struct hash_entry *bucket = safe_hasher (table, entry);
Packit 33f14e
  struct hash_entry *cursor;
Packit 33f14e
Packit 33f14e
  *bucket_head = bucket;
Packit 33f14e
Packit 33f14e
  /* Test for empty bucket.  */
Packit 33f14e
  if (bucket->data == NULL)
Packit 33f14e
    return NULL;
Packit 33f14e
Packit 33f14e
  /* See if the entry is the first in the bucket.  */
Packit 33f14e
  if (entry == bucket->data || table->comparator (entry, bucket->data))
Packit 33f14e
    {
Packit 33f14e
      void *data = bucket->data;
Packit 33f14e
Packit 33f14e
      if (delete)
Packit 33f14e
        {
Packit 33f14e
          if (bucket->next)
Packit 33f14e
            {
Packit 33f14e
              struct hash_entry *next = bucket->next;
Packit 33f14e
Packit 33f14e
              /* Bump the first overflow entry into the bucket head, then save
Packit 33f14e
                 the previous first overflow entry for later recycling.  */
Packit 33f14e
              *bucket = *next;
Packit 33f14e
              free_entry (table, next);
Packit 33f14e
            }
Packit 33f14e
          else
Packit 33f14e
            {
Packit 33f14e
              bucket->data = NULL;
Packit 33f14e
            }
Packit 33f14e
        }
Packit 33f14e
Packit 33f14e
      return data;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* Scan the bucket overflow.  */
Packit 33f14e
  for (cursor = bucket; cursor->next; cursor = cursor->next)
Packit 33f14e
    {
Packit 33f14e
      if (entry == cursor->next->data
Packit 33f14e
          || table->comparator (entry, cursor->next->data))
Packit 33f14e
        {
Packit 33f14e
          void *data = cursor->next->data;
Packit 33f14e
Packit 33f14e
          if (delete)
Packit 33f14e
            {
Packit 33f14e
              struct hash_entry *next = cursor->next;
Packit 33f14e
Packit 33f14e
              /* Unlink the entry to delete, then save the freed entry for later
Packit 33f14e
                 recycling.  */
Packit 33f14e
              cursor->next = next->next;
Packit 33f14e
              free_entry (table, next);
Packit 33f14e
            }
Packit 33f14e
Packit 33f14e
          return data;
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* No entry found.  */
Packit 33f14e
  return NULL;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Internal helper, to move entries from SRC to DST.  Both tables must
Packit 33f14e
   share the same free entry list.  If SAFE, only move overflow
Packit 33f14e
   entries, saving bucket heads for later, so that no allocations will
Packit 33f14e
   occur.  Return false if the free entry list is exhausted and an
Packit 33f14e
   allocation fails.  */
Packit 33f14e
Packit 33f14e
static bool
Packit 33f14e
transfer_entries (Hash_table *dst, Hash_table *src, bool safe)
Packit 33f14e
{
Packit 33f14e
  struct hash_entry *bucket;
Packit 33f14e
  struct hash_entry *cursor;
Packit 33f14e
  struct hash_entry *next;
Packit 33f14e
  for (bucket = src->bucket; bucket < src->bucket_limit; bucket++)
Packit 33f14e
    if (bucket->data)
Packit 33f14e
      {
Packit 33f14e
        void *data;
Packit 33f14e
        struct hash_entry *new_bucket;
Packit 33f14e
Packit 33f14e
        /* Within each bucket, transfer overflow entries first and
Packit 33f14e
           then the bucket head, to minimize memory pressure.  After
Packit 33f14e
           all, the only time we might allocate is when moving the
Packit 33f14e
           bucket head, but moving overflow entries first may create
Packit 33f14e
           free entries that can be recycled by the time we finally
Packit 33f14e
           get to the bucket head.  */
Packit 33f14e
        for (cursor = bucket->next; cursor; cursor = next)
Packit 33f14e
          {
Packit 33f14e
            data = cursor->data;
Packit 33f14e
            new_bucket = safe_hasher (dst, data);
Packit 33f14e
Packit 33f14e
            next = cursor->next;
Packit 33f14e
Packit 33f14e
            if (new_bucket->data)
Packit 33f14e
              {
Packit 33f14e
                /* Merely relink an existing entry, when moving from a
Packit 33f14e
                   bucket overflow into a bucket overflow.  */
Packit 33f14e
                cursor->next = new_bucket->next;
Packit 33f14e
                new_bucket->next = cursor;
Packit 33f14e
              }
Packit 33f14e
            else
Packit 33f14e
              {
Packit 33f14e
                /* Free an existing entry, when moving from a bucket
Packit 33f14e
                   overflow into a bucket header.  */
Packit 33f14e
                new_bucket->data = data;
Packit 33f14e
                dst->n_buckets_used++;
Packit 33f14e
                free_entry (dst, cursor);
Packit 33f14e
              }
Packit 33f14e
          }
Packit 33f14e
        /* Now move the bucket head.  Be sure that if we fail due to
Packit 33f14e
           allocation failure that the src table is in a consistent
Packit 33f14e
           state.  */
Packit 33f14e
        data = bucket->data;
Packit 33f14e
        bucket->next = NULL;
Packit 33f14e
        if (safe)
Packit 33f14e
          continue;
Packit 33f14e
        new_bucket = safe_hasher (dst, data);
Packit 33f14e
Packit 33f14e
        if (new_bucket->data)
Packit 33f14e
          {
Packit 33f14e
            /* Allocate or recycle an entry, when moving from a bucket
Packit 33f14e
               header into a bucket overflow.  */
Packit 33f14e
            struct hash_entry *new_entry = allocate_entry (dst);
Packit 33f14e
Packit 33f14e
            if (new_entry == NULL)
Packit 33f14e
              return false;
Packit 33f14e
Packit 33f14e
            new_entry->data = data;
Packit 33f14e
            new_entry->next = new_bucket->next;
Packit 33f14e
            new_bucket->next = new_entry;
Packit 33f14e
          }
Packit 33f14e
        else
Packit 33f14e
          {
Packit 33f14e
            /* Move from one bucket header to another.  */
Packit 33f14e
            new_bucket->data = data;
Packit 33f14e
            dst->n_buckets_used++;
Packit 33f14e
          }
Packit 33f14e
        bucket->data = NULL;
Packit 33f14e
        src->n_buckets_used--;
Packit 33f14e
      }
Packit 33f14e
  return true;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* For an already existing hash table, change the number of buckets through
Packit 33f14e
   specifying CANDIDATE.  The contents of the hash table are preserved.  The
Packit 33f14e
   new number of buckets is automatically selected so as to _guarantee_ that
Packit 33f14e
   the table may receive at least CANDIDATE different user entries, including
Packit 33f14e
   those already in the table, before any other growth of the hash table size
Packit 33f14e
   occurs.  If TUNING->IS_N_BUCKETS is true, then CANDIDATE specifies the
Packit 33f14e
   exact number of buckets desired.  Return true iff the rehash succeeded.  */
Packit 33f14e
Packit 33f14e
bool
Packit 33f14e
hash_rehash (Hash_table *table, size_t candidate)
Packit 33f14e
{
Packit 33f14e
  Hash_table storage;
Packit 33f14e
  Hash_table *new_table;
Packit 33f14e
  size_t new_size = compute_bucket_size (candidate, table->tuning);
Packit 33f14e
Packit 33f14e
  if (!new_size)
Packit 33f14e
    return false;
Packit 33f14e
  if (new_size == table->n_buckets)
Packit 33f14e
    return true;
Packit 33f14e
  new_table = &storage;
Packit 33f14e
  new_table->bucket = calloc (new_size, sizeof *new_table->bucket);
Packit 33f14e
  if (new_table->bucket == NULL)
Packit 33f14e
    return false;
Packit 33f14e
  new_table->n_buckets = new_size;
Packit 33f14e
  new_table->bucket_limit = new_table->bucket + new_size;
Packit 33f14e
  new_table->n_buckets_used = 0;
Packit 33f14e
  new_table->n_entries = 0;
Packit 33f14e
  new_table->tuning = table->tuning;
Packit 33f14e
  new_table->hasher = table->hasher;
Packit 33f14e
  new_table->comparator = table->comparator;
Packit 33f14e
  new_table->data_freer = table->data_freer;
Packit 33f14e
Packit 33f14e
  /* In order for the transfer to successfully complete, we need
Packit 33f14e
     additional overflow entries when distinct buckets in the old
Packit 33f14e
     table collide into a common bucket in the new table.  The worst
Packit 33f14e
     case possible is a hasher that gives a good spread with the old
Packit 33f14e
     size, but returns a constant with the new size; if we were to
Packit 33f14e
     guarantee table->n_buckets_used-1 free entries in advance, then
Packit 33f14e
     the transfer would be guaranteed to not allocate memory.
Packit 33f14e
     However, for large tables, a guarantee of no further allocation
Packit 33f14e
     introduces a lot of extra memory pressure, all for an unlikely
Packit 33f14e
     corner case (most rehashes reduce, rather than increase, the
Packit 33f14e
     number of overflow entries needed).  So, we instead ensure that
Packit 33f14e
     the transfer process can be reversed if we hit a memory
Packit 33f14e
     allocation failure mid-transfer.  */
Packit 33f14e
Packit 33f14e
  /* Merely reuse the extra old space into the new table.  */
Packit 33f14e
#if USE_OBSTACK
Packit 33f14e
  new_table->entry_stack = table->entry_stack;
Packit 33f14e
#endif
Packit 33f14e
  new_table->free_entry_list = table->free_entry_list;
Packit 33f14e
Packit 33f14e
  if (transfer_entries (new_table, table, false))
Packit 33f14e
    {
Packit 33f14e
      /* Entries transferred successfully; tie up the loose ends.  */
Packit 33f14e
      free (table->bucket);
Packit 33f14e
      table->bucket = new_table->bucket;
Packit 33f14e
      table->bucket_limit = new_table->bucket_limit;
Packit 33f14e
      table->n_buckets = new_table->n_buckets;
Packit 33f14e
      table->n_buckets_used = new_table->n_buckets_used;
Packit 33f14e
      table->free_entry_list = new_table->free_entry_list;
Packit 33f14e
      /* table->n_entries and table->entry_stack already hold their value.  */
Packit 33f14e
      return true;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* We've allocated new_table->bucket (and possibly some entries),
Packit 33f14e
     exhausted the free list, and moved some but not all entries into
Packit 33f14e
     new_table.  We must undo the partial move before returning
Packit 33f14e
     failure.  The only way to get into this situation is if new_table
Packit 33f14e
     uses fewer buckets than the old table, so we will reclaim some
Packit 33f14e
     free entries as overflows in the new table are put back into
Packit 33f14e
     distinct buckets in the old table.
Packit 33f14e
Packit 33f14e
     There are some pathological cases where a single pass through the
Packit 33f14e
     table requires more intermediate overflow entries than using two
Packit 33f14e
     passes.  Two passes give worse cache performance and takes
Packit 33f14e
     longer, but at this point, we're already out of memory, so slow
Packit 33f14e
     and safe is better than failure.  */
Packit 33f14e
  table->free_entry_list = new_table->free_entry_list;
Packit 33f14e
  if (! (transfer_entries (table, new_table, true)
Packit 33f14e
         && transfer_entries (table, new_table, false)))
Packit 33f14e
    abort ();
Packit 33f14e
  /* table->n_entries already holds its value.  */
Packit 33f14e
  free (new_table->bucket);
Packit 33f14e
  return false;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Insert ENTRY into hash TABLE if there is not already a matching entry.
Packit 33f14e
Packit 33f14e
   Return -1 upon memory allocation failure.
Packit 33f14e
   Return 1 if insertion succeeded.
Packit 33f14e
   Return 0 if there is already a matching entry in the table,
Packit 33f14e
   and in that case, if MATCHED_ENT is non-NULL, set *MATCHED_ENT
Packit 33f14e
   to that entry.
Packit 33f14e
Packit 33f14e
   This interface is easier to use than hash_insert when you must
Packit 33f14e
   distinguish between the latter two cases.  More importantly,
Packit 33f14e
   hash_insert is unusable for some types of ENTRY values.  When using
Packit 33f14e
   hash_insert, the only way to distinguish those cases is to compare
Packit 33f14e
   the return value and ENTRY.  That works only when you can have two
Packit 33f14e
   different ENTRY values that point to data that compares "equal".  Thus,
Packit 33f14e
   when the ENTRY value is a simple scalar, you must use
Packit 33f14e
   hash_insert_if_absent.  ENTRY must not be NULL.  */
Packit 33f14e
int
Packit 33f14e
hash_insert_if_absent (Hash_table *table, void const *entry,
Packit 33f14e
                       void const **matched_ent)
Packit 33f14e
{
Packit 33f14e
  void *data;
Packit 33f14e
  struct hash_entry *bucket;
Packit 33f14e
Packit 33f14e
  /* The caller cannot insert a NULL entry, since hash_lookup returns NULL
Packit 33f14e
     to indicate "not found", and hash_find_entry uses "bucket->data == NULL"
Packit 33f14e
     to indicate an empty bucket.  */
Packit 33f14e
  if (! entry)
Packit 33f14e
    abort ();
Packit 33f14e
Packit 33f14e
  /* If there's a matching entry already in the table, return that.  */
Packit 33f14e
  if ((data = hash_find_entry (table, entry, &bucket, false)) != NULL)
Packit 33f14e
    {
Packit 33f14e
      if (matched_ent)
Packit 33f14e
        *matched_ent = data;
Packit 33f14e
      return 0;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* If the growth threshold of the buckets in use has been reached, increase
Packit 33f14e
     the table size and rehash.  There's no point in checking the number of
Packit 33f14e
     entries:  if the hashing function is ill-conditioned, rehashing is not
Packit 33f14e
     likely to improve it.  */
Packit 33f14e
Packit 33f14e
  if (table->n_buckets_used
Packit 33f14e
      > table->tuning->growth_threshold * table->n_buckets)
Packit 33f14e
    {
Packit 33f14e
      /* Check more fully, before starting real work.  If tuning arguments
Packit 33f14e
         became invalid, the second check will rely on proper defaults.  */
Packit 33f14e
      check_tuning (table);
Packit 33f14e
      if (table->n_buckets_used
Packit 33f14e
          > table->tuning->growth_threshold * table->n_buckets)
Packit 33f14e
        {
Packit 33f14e
          const Hash_tuning *tuning = table->tuning;
Packit 33f14e
          float candidate =
Packit 33f14e
            (tuning->is_n_buckets
Packit 33f14e
             ? (table->n_buckets * tuning->growth_factor)
Packit 33f14e
             : (table->n_buckets * tuning->growth_factor
Packit 33f14e
                * tuning->growth_threshold));
Packit 33f14e
Packit 33f14e
          if (SIZE_MAX <= candidate)
Packit 33f14e
            return -1;
Packit 33f14e
Packit 33f14e
          /* If the rehash fails, arrange to return NULL.  */
Packit 33f14e
          if (!hash_rehash (table, candidate))
Packit 33f14e
            return -1;
Packit 33f14e
Packit 33f14e
          /* Update the bucket we are interested in.  */
Packit 33f14e
          if (hash_find_entry (table, entry, &bucket, false) != NULL)
Packit 33f14e
            abort ();
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* ENTRY is not matched, it should be inserted.  */
Packit 33f14e
Packit 33f14e
  if (bucket->data)
Packit 33f14e
    {
Packit 33f14e
      struct hash_entry *new_entry = allocate_entry (table);
Packit 33f14e
Packit 33f14e
      if (new_entry == NULL)
Packit 33f14e
        return -1;
Packit 33f14e
Packit 33f14e
      /* Add ENTRY in the overflow of the bucket.  */
Packit 33f14e
Packit 33f14e
      new_entry->data = (void *) entry;
Packit 33f14e
      new_entry->next = bucket->next;
Packit 33f14e
      bucket->next = new_entry;
Packit 33f14e
      table->n_entries++;
Packit 33f14e
      return 1;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* Add ENTRY right in the bucket head.  */
Packit 33f14e
Packit 33f14e
  bucket->data = (void *) entry;
Packit 33f14e
  table->n_entries++;
Packit 33f14e
  table->n_buckets_used++;
Packit 33f14e
Packit 33f14e
  return 1;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* If ENTRY matches an entry already in the hash table, return the pointer
Packit 33f14e
   to the entry from the table.  Otherwise, insert ENTRY and return ENTRY.
Packit 33f14e
   Return NULL if the storage required for insertion cannot be allocated.
Packit 33f14e
   This implementation does not support duplicate entries or insertion of
Packit 33f14e
   NULL.  */
Packit 33f14e
Packit 33f14e
void *
Packit 33f14e
hash_insert (Hash_table *table, void const *entry)
Packit 33f14e
{
Packit 33f14e
  void const *matched_ent;
Packit 33f14e
  int err = hash_insert_if_absent (table, entry, &matched_ent);
Packit 33f14e
  return (err == -1
Packit 33f14e
          ? NULL
Packit 33f14e
          : (void *) (err == 0 ? matched_ent : entry));
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* If ENTRY is already in the table, remove it and return the just-deleted
Packit 33f14e
   data (the user may want to deallocate its storage).  If ENTRY is not in the
Packit 33f14e
   table, don't modify the table and return NULL.  */
Packit 33f14e
Packit 33f14e
void *
Packit 33f14e
hash_delete (Hash_table *table, const void *entry)
Packit 33f14e
{
Packit 33f14e
  void *data;
Packit 33f14e
  struct hash_entry *bucket;
Packit 33f14e
Packit 33f14e
  data = hash_find_entry (table, entry, &bucket, true);
Packit 33f14e
  if (!data)
Packit 33f14e
    return NULL;
Packit 33f14e
Packit 33f14e
  table->n_entries--;
Packit 33f14e
  if (!bucket->data)
Packit 33f14e
    {
Packit 33f14e
      table->n_buckets_used--;
Packit 33f14e
Packit 33f14e
      /* If the shrink threshold of the buckets in use has been reached,
Packit 33f14e
         rehash into a smaller table.  */
Packit 33f14e
Packit 33f14e
      if (table->n_buckets_used
Packit 33f14e
          < table->tuning->shrink_threshold * table->n_buckets)
Packit 33f14e
        {
Packit 33f14e
          /* Check more fully, before starting real work.  If tuning arguments
Packit 33f14e
             became invalid, the second check will rely on proper defaults.  */
Packit 33f14e
          check_tuning (table);
Packit 33f14e
          if (table->n_buckets_used
Packit 33f14e
              < table->tuning->shrink_threshold * table->n_buckets)
Packit 33f14e
            {
Packit 33f14e
              const Hash_tuning *tuning = table->tuning;
Packit 33f14e
              size_t candidate =
Packit 33f14e
                (tuning->is_n_buckets
Packit 33f14e
                 ? table->n_buckets * tuning->shrink_factor
Packit 33f14e
                 : (table->n_buckets * tuning->shrink_factor
Packit 33f14e
                    * tuning->growth_threshold));
Packit 33f14e
Packit 33f14e
              if (!hash_rehash (table, candidate))
Packit 33f14e
                {
Packit 33f14e
                  /* Failure to allocate memory in an attempt to
Packit 33f14e
                     shrink the table is not fatal.  But since memory
Packit 33f14e
                     is low, we can at least be kind and free any
Packit 33f14e
                     spare entries, rather than keeping them tied up
Packit 33f14e
                     in the free entry list.  */
Packit 33f14e
#if ! USE_OBSTACK
Packit 33f14e
                  struct hash_entry *cursor = table->free_entry_list;
Packit 33f14e
                  struct hash_entry *next;
Packit 33f14e
                  while (cursor)
Packit 33f14e
                    {
Packit 33f14e
                      next = cursor->next;
Packit 33f14e
                      free (cursor);
Packit 33f14e
                      cursor = next;
Packit 33f14e
                    }
Packit 33f14e
                  table->free_entry_list = NULL;
Packit 33f14e
#endif
Packit 33f14e
                }
Packit 33f14e
            }
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  return data;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Testing.  */
Packit 33f14e
Packit 33f14e
#if TESTING
Packit 33f14e
Packit 33f14e
void
Packit 33f14e
hash_print (const Hash_table *table)
Packit 33f14e
{
Packit 33f14e
  struct hash_entry *bucket = (struct hash_entry *) table->bucket;
Packit 33f14e
Packit 33f14e
  for ( ; bucket < table->bucket_limit; bucket++)
Packit 33f14e
    {
Packit 33f14e
      struct hash_entry *cursor;
Packit 33f14e
Packit 33f14e
      if (bucket)
Packit 33f14e
        printf ("%lu:\n", (unsigned long int) (bucket - table->bucket));
Packit 33f14e
Packit 33f14e
      for (cursor = bucket; cursor; cursor = cursor->next)
Packit 33f14e
        {
Packit 33f14e
          char const *s = cursor->data;
Packit 33f14e
          /* FIXME */
Packit 33f14e
          if (s)
Packit 33f14e
            printf ("  %s\n", s);
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#endif /* TESTING */