Blame gl/hash.c

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