Blame lib/hash.c

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