Correctly determine whether pow is available in libc on AIX 7 with xlc.
[gnulib.git] / lib / hash.c
index 59f1ff0..15630be 100644 (file)
@@ -1,7 +1,6 @@
 /* hash - hashing table processing.
 
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2007,
-   2009 Free Software Foundation, Inc.
+   Copyright (C) 1998-2004, 2006-2007, 2009-2010 Free Software Foundation, Inc.
 
    Written by Jim Meyering, 1992.
 
 #include <config.h>
 
 #include "hash.h"
+
+#include "bitrotate.h"
 #include "xalloc.h"
 
-#include <limits.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 # endif
 #endif
 
-#ifndef SIZE_MAX
-# define SIZE_MAX ((size_t) -1)
-#endif
-
 struct hash_entry
   {
     void *data;
@@ -182,16 +179,16 @@ hash_get_max_bucket_length (const Hash_table *table)
   for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
     {
       if (bucket->data)
-       {
-         struct hash_entry const *cursor = bucket;
-         size_t bucket_length = 1;
+        {
+          struct hash_entry const *cursor = bucket;
+          size_t bucket_length = 1;
 
-         while (cursor = cursor->next, cursor)
-           bucket_length++;
+          while (cursor = cursor->next, cursor)
+            bucket_length++;
 
-         if (bucket_length > max_bucket_length)
-           max_bucket_length = bucket_length;
-       }
+          if (bucket_length > max_bucket_length)
+            max_bucket_length = bucket_length;
+        }
     }
 
   return max_bucket_length;
@@ -210,17 +207,17 @@ hash_table_ok (const Hash_table *table)
   for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
     {
       if (bucket->data)
-       {
-         struct hash_entry const *cursor = bucket;
+        {
+          struct hash_entry const *cursor = bucket;
 
-         /* Count bucket head.  */
-         n_buckets_used++;
-         n_entries++;
+          /* Count bucket head.  */
+          n_buckets_used++;
+          n_entries++;
 
-         /* Count bucket overflow.  */
-         while (cursor = cursor->next, cursor)
-           n_entries++;
-       }
+          /* Count bucket overflow.  */
+          while (cursor = cursor->next, cursor)
+            n_entries++;
+        }
     }
 
   if (n_buckets_used == table->n_buckets_used && n_entries == table->n_entries)
@@ -240,10 +237,10 @@ hash_print_statistics (const Hash_table *table, FILE *stream)
   fprintf (stream, "# entries:         %lu\n", (unsigned long int) n_entries);
   fprintf (stream, "# buckets:         %lu\n", (unsigned long int) n_buckets);
   fprintf (stream, "# buckets used:    %lu (%.2f%%)\n",
-          (unsigned long int) n_buckets_used,
-          (100.0 * n_buckets_used) / n_buckets);
+           (unsigned long int) n_buckets_used,
+           (100.0 * n_buckets_used) / n_buckets);
   fprintf (stream, "max bucket length: %lu\n",
-          (unsigned long int) max_bucket_length);
+           (unsigned long int) max_bucket_length);
 }
 
 /* If ENTRY matches an entry already in the hash table, return the
@@ -329,7 +326,7 @@ hash_get_next (const Hash_table *table, const void *entry)
 
 size_t
 hash_get_entries (const Hash_table *table, void **buffer,
-                 size_t buffer_size)
+                  size_t buffer_size)
 {
   size_t counter = 0;
   struct hash_entry const *bucket;
@@ -338,14 +335,14 @@ hash_get_entries (const Hash_table *table, void **buffer,
   for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
     {
       if (bucket->data)
-       {
-         for (cursor = bucket; cursor; cursor = cursor->next)
-           {
-             if (counter >= buffer_size)
-               return counter;
-             buffer[counter++] = cursor->data;
-           }
-       }
+        {
+          for (cursor = bucket; cursor; cursor = cursor->next)
+            {
+              if (counter >= buffer_size)
+                return counter;
+              buffer[counter++] = cursor->data;
+            }
+        }
     }
 
   return counter;
@@ -361,7 +358,7 @@ hash_get_entries (const Hash_table *table, void **buffer,
 
 size_t
 hash_do_for_each (const Hash_table *table, Hash_processor processor,
-                 void *processor_data)
+                  void *processor_data)
 {
   size_t counter = 0;
   struct hash_entry const *bucket;
@@ -370,14 +367,14 @@ hash_do_for_each (const Hash_table *table, Hash_processor processor,
   for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
     {
       if (bucket->data)
-       {
-         for (cursor = bucket; cursor; cursor = cursor->next)
-           {
-             if (! processor (cursor->data, processor_data))
-               return counter;
-             counter++;
-           }
-       }
+        {
+          for (cursor = bucket; cursor; cursor = cursor->next)
+            {
+              if (! processor (cursor->data, processor_data))
+                return counter;
+              counter++;
+            }
+        }
     }
 
   return counter;
@@ -399,10 +396,8 @@ hash_do_for_each (const Hash_table *table, Hash_processor processor,
 size_t
 hash_string (const char *string, size_t n_buckets)
 {
-# define ROTATE_LEFT(Value, Shift) \
-  ((Value) << (Shift) | (Value) >> ((sizeof (size_t) * CHAR_BIT) - (Shift)))
 # define HASH_ONE_CHAR(Value, Byte) \
-  ((Byte) + ROTATE_LEFT (Value, 7))
+  ((Byte) + rotl_sz (Value, 7))
 
   size_t value = 0;
   unsigned char ch;
@@ -411,7 +406,6 @@ hash_string (const char *string, size_t n_buckets)
     value = HASH_ONE_CHAR (value, ch);
   return value % n_buckets;
 
-# undef ROTATE_LEFT
 # undef HASH_ONE_CHAR
 }
 
@@ -467,7 +461,7 @@ next_prime (size_t candidate)
   /* Make it definitely odd.  */
   candidate |= 1;
 
-  while (!is_prime (candidate))
+  while (SIZE_MAX != candidate && !is_prime (candidate))
     candidate += 2;
 
   return candidate;
@@ -488,8 +482,7 @@ raw_hasher (const void *data, size_t n)
      bits are 0.  As this tends to give poorer performance with small
      tables, we rotate the pointer value before performing division,
      in an attempt to improve hash quality.  */
-  size_t val = (size_t) data;
-  val = ((val >> 3) | (val << (CHAR_BIT * sizeof val - 3))) & SIZE_MAX;
+  size_t val = rotr_sz ((size_t) data, 3);
   return val % n;
 }
 
@@ -511,6 +504,7 @@ static bool
 check_tuning (Hash_table *table)
 {
   const Hash_tuning *tuning = table->tuning;
+  float epsilon;
   if (tuning == &default_tuning)
     return true;
 
@@ -519,7 +513,7 @@ check_tuning (Hash_table *table)
      fail to grow or shrink as they should.  The smallest allocation
      is 11 (due to next_prime's algorithm), so an epsilon of 0.1
      should be good enough.  */
-  float epsilon = 0.1f;
+  epsilon = 0.1f;
 
   if (epsilon < tuning->growth_threshold
       && tuning->growth_threshold < 1 - epsilon
@@ -534,6 +528,26 @@ check_tuning (Hash_table *table)
   return false;
 }
 
+/* Compute the size of the bucket array for the given CANDIDATE and
+   TUNING, or return 0 if there is no possible way to allocate that
+   many entries.  */
+
+static size_t
+compute_bucket_size (size_t candidate, const Hash_tuning *tuning)
+{
+  if (!tuning->is_n_buckets)
+    {
+      float new_candidate = candidate / tuning->growth_threshold;
+      if (SIZE_MAX <= new_candidate)
+        return 0;
+      candidate = new_candidate;
+    }
+  candidate = next_prime (candidate);
+  if (xalloc_oversized (candidate, sizeof (struct hash_entry *)))
+    return 0;
+  return candidate;
+}
+
 /* Allocate and return a new hash table, or NULL upon failure.  The initial
    number of buckets is automatically selected so as to _guarantee_ that you
    may insert at least CANDIDATE different user entries before any growth of
@@ -570,8 +584,8 @@ check_tuning (Hash_table *table)
 
 Hash_table *
 hash_initialize (size_t candidate, const Hash_tuning *tuning,
-                Hash_hasher hasher, Hash_comparator comparator,
-                Hash_data_freer data_freer)
+                 Hash_hasher hasher, Hash_comparator comparator,
+                 Hash_data_freer data_freer)
 {
   Hash_table *table;
 
@@ -590,25 +604,15 @@ hash_initialize (size_t candidate, const Hash_tuning *tuning,
   if (!check_tuning (table))
     {
       /* Fail if the tuning options are invalid.  This is the only occasion
-        when the user gets some feedback about it.  Once the table is created,
-        if the user provides invalid tuning options, we silently revert to
-        using the defaults, and ignore further request to change the tuning
-        options.  */
+         when the user gets some feedback about it.  Once the table is created,
+         if the user provides invalid tuning options, we silently revert to
+         using the defaults, and ignore further request to change the tuning
+         options.  */
       goto fail;
     }
 
-  if (!tuning->is_n_buckets)
-    {
-      float new_candidate = candidate / tuning->growth_threshold;
-      if (SIZE_MAX <= new_candidate)
-       goto fail;
-      candidate = new_candidate;
-    }
-
-  if (xalloc_oversized (candidate, sizeof *table->bucket))
-    goto fail;
-  table->n_buckets = next_prime (candidate);
-  if (xalloc_oversized (table->n_buckets, sizeof *table->bucket))
+  table->n_buckets = compute_bucket_size (candidate, tuning);
+  if (!table->n_buckets)
     goto fail;
 
   table->bucket = calloc (table->n_buckets, sizeof *table->bucket);
@@ -645,30 +649,30 @@ hash_clear (Hash_table *table)
   for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
     {
       if (bucket->data)
-       {
-         struct hash_entry *cursor;
-         struct hash_entry *next;
-
-         /* Free the bucket overflow.  */
-         for (cursor = bucket->next; cursor; cursor = next)
-           {
-             if (table->data_freer)
-               table->data_freer (cursor->data);
-             cursor->data = NULL;
-
-             next = cursor->next;
-             /* Relinking is done one entry at a time, as it is to be expected
-                that overflows are either rare or short.  */
-             cursor->next = table->free_entry_list;
-             table->free_entry_list = cursor;
-           }
-
-         /* Free the bucket head.  */
-         if (table->data_freer)
-           table->data_freer (bucket->data);
-         bucket->data = NULL;
-         bucket->next = NULL;
-       }
+        {
+          struct hash_entry *cursor;
+          struct hash_entry *next;
+
+          /* Free the bucket overflow.  */
+          for (cursor = bucket->next; cursor; cursor = next)
+            {
+              if (table->data_freer)
+                table->data_freer (cursor->data);
+              cursor->data = NULL;
+
+              next = cursor->next;
+              /* Relinking is done one entry at a time, as it is to be expected
+                 that overflows are either rare or short.  */
+              cursor->next = table->free_entry_list;
+              table->free_entry_list = cursor;
+            }
+
+          /* Free the bucket head.  */
+          if (table->data_freer)
+            table->data_freer (bucket->data);
+          bucket->data = NULL;
+          bucket->next = NULL;
+        }
     }
 
   table->n_buckets_used = 0;
@@ -691,13 +695,13 @@ hash_free (Hash_table *table)
   if (table->data_freer && table->n_entries)
     {
       for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
-       {
-         if (bucket->data)
-           {
-             for (cursor = bucket; cursor; cursor = cursor->next)
-               table->data_freer (cursor->data);
-           }
-       }
+        {
+          if (bucket->data)
+            {
+              for (cursor = bucket; cursor; cursor = cursor->next)
+                table->data_freer (cursor->data);
+            }
+        }
     }
 
 #if USE_OBSTACK
@@ -710,10 +714,10 @@ hash_free (Hash_table *table)
   for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
     {
       for (cursor = bucket->next; cursor; cursor = next)
-       {
-         next = cursor->next;
-         free (cursor);
-       }
+        {
+          next = cursor->next;
+          free (cursor);
+        }
     }
 
   /* Also reclaim the internal list of previously freed entries.  */
@@ -776,7 +780,7 @@ free_entry (Hash_table *table, struct hash_entry *entry)
 
 static void *
 hash_find_entry (Hash_table *table, const void *entry,
-                struct hash_entry **bucket_head, bool delete)
+                 struct hash_entry **bucket_head, bool delete)
 {
   struct hash_entry *bucket
     = table->bucket + table->hasher (entry, table->n_buckets);
@@ -797,21 +801,21 @@ hash_find_entry (Hash_table *table, const void *entry,
       void *data = bucket->data;
 
       if (delete)
-       {
-         if (bucket->next)
-           {
-             struct hash_entry *next = bucket->next;
-
-             /* Bump the first overflow entry into the bucket head, then save
-                the previous first overflow entry for later recycling.  */
-             *bucket = *next;
-             free_entry (table, next);
-           }
-         else
-           {
-             bucket->data = NULL;
-           }
-       }
+        {
+          if (bucket->next)
+            {
+              struct hash_entry *next = bucket->next;
+
+              /* Bump the first overflow entry into the bucket head, then save
+                 the previous first overflow entry for later recycling.  */
+              *bucket = *next;
+              free_entry (table, next);
+            }
+          else
+            {
+              bucket->data = NULL;
+            }
+        }
 
       return data;
     }
@@ -820,28 +824,115 @@ hash_find_entry (Hash_table *table, const void *entry,
   for (cursor = bucket; cursor->next; cursor = cursor->next)
     {
       if (entry == cursor->next->data
-         || table->comparator (entry, cursor->next->data))
-       {
-         void *data = cursor->next->data;
-
-         if (delete)
-           {
-             struct hash_entry *next = cursor->next;
-
-             /* Unlink the entry to delete, then save the freed entry for later
-                recycling.  */
-             cursor->next = next->next;
-             free_entry (table, next);
-           }
-
-         return data;
-       }
+          || table->comparator (entry, cursor->next->data))
+        {
+          void *data = cursor->next->data;
+
+          if (delete)
+            {
+              struct hash_entry *next = cursor->next;
+
+              /* Unlink the entry to delete, then save the freed entry for later
+                 recycling.  */
+              cursor->next = next->next;
+              free_entry (table, next);
+            }
+
+          return data;
+        }
     }
 
   /* No entry found.  */
   return NULL;
 }
 
+/* Internal helper, to move entries from SRC to DST.  Both tables must
+   share the same free entry list.  If SAFE, only move overflow
+   entries, saving bucket heads for later, so that no allocations will
+   occur.  Return false if the free entry list is exhausted and an
+   allocation fails.  */
+
+static bool
+transfer_entries (Hash_table *dst, Hash_table *src, bool safe)
+{
+  struct hash_entry *bucket;
+  struct hash_entry *cursor;
+  struct hash_entry *next;
+  for (bucket = src->bucket; bucket < src->bucket_limit; bucket++)
+    if (bucket->data)
+      {
+        void *data;
+        struct hash_entry *new_bucket;
+
+        /* Within each bucket, transfer overflow entries first and
+           then the bucket head, to minimize memory pressure.  After
+           all, the only time we might allocate is when moving the
+           bucket head, but moving overflow entries first may create
+           free entries that can be recycled by the time we finally
+           get to the bucket head.  */
+        for (cursor = bucket->next; cursor; cursor = next)
+          {
+            data = cursor->data;
+            new_bucket = (dst->bucket + dst->hasher (data, dst->n_buckets));
+
+            if (! (new_bucket < dst->bucket_limit))
+              abort ();
+
+            next = cursor->next;
+
+            if (new_bucket->data)
+              {
+                /* Merely relink an existing entry, when moving from a
+                   bucket overflow into a bucket overflow.  */
+                cursor->next = new_bucket->next;
+                new_bucket->next = cursor;
+              }
+            else
+              {
+                /* Free an existing entry, when moving from a bucket
+                   overflow into a bucket header.  */
+                new_bucket->data = data;
+                dst->n_buckets_used++;
+                free_entry (dst, cursor);
+              }
+          }
+        /* Now move the bucket head.  Be sure that if we fail due to
+           allocation failure that the src table is in a consistent
+           state.  */
+        data = bucket->data;
+        bucket->next = NULL;
+        if (safe)
+          continue;
+        new_bucket = (dst->bucket + dst->hasher (data, dst->n_buckets));
+
+        if (! (new_bucket < dst->bucket_limit))
+          abort ();
+
+        if (new_bucket->data)
+          {
+            /* Allocate or recycle an entry, when moving from a bucket
+               header into a bucket overflow.  */
+            struct hash_entry *new_entry = allocate_entry (dst);
+
+            if (new_entry == NULL)
+              return false;
+
+            new_entry->data = data;
+            new_entry->next = new_bucket->next;
+            new_bucket->next = new_entry;
+          }
+        else
+          {
+            /* Move from one bucket header to another.  */
+            new_bucket->data = data;
+            dst->n_buckets_used++;
+          }
+        bucket->data = NULL;
+        src->n_buckets_used--;
+      }
+  return true;
+}
+
 /* For an already existing hash table, change the number of buckets through
    specifying CANDIDATE.  The contents of the hash table are preserved.  The
    new number of buckets is automatically selected so as to _guarantee_ that
@@ -853,107 +944,115 @@ hash_find_entry (Hash_table *table, const void *entry,
 bool
 hash_rehash (Hash_table *table, size_t candidate)
 {
+  Hash_table storage;
   Hash_table *new_table;
-  struct hash_entry *bucket;
-  struct hash_entry *cursor;
-  struct hash_entry *next;
+  size_t new_size = compute_bucket_size (candidate, table->tuning);
 
-  new_table = hash_initialize (candidate, table->tuning, table->hasher,
-                              table->comparator, table->data_freer);
-  if (new_table == NULL)
+  if (!new_size)
     return false;
+  if (new_size == table->n_buckets)
+    return true;
+  new_table = &storage;
+  new_table->bucket = calloc (new_size, sizeof *new_table->bucket);
+  if (new_table->bucket == NULL)
+    return false;
+  new_table->n_buckets = new_size;
+  new_table->bucket_limit = new_table->bucket + new_size;
+  new_table->n_buckets_used = 0;
+  new_table->n_entries = 0;
+  new_table->tuning = table->tuning;
+  new_table->hasher = table->hasher;
+  new_table->comparator = table->comparator;
+  new_table->data_freer = table->data_freer;
+
+  /* In order for the transfer to successfully complete, we need
+     additional overflow entries when distinct buckets in the old
+     table collide into a common bucket in the new table.  The worst
+     case possible is a hasher that gives a good spread with the old
+     size, but returns a constant with the new size; if we were to
+     guarantee table->n_buckets_used-1 free entries in advance, then
+     the transfer would be guaranteed to not allocate memory.
+     However, for large tables, a guarantee of no further allocation
+     introduces a lot of extra memory pressure, all for an unlikely
+     corner case (most rehashes reduce, rather than increase, the
+     number of overflow entries needed).  So, we instead ensure that
+     the transfer process can be reversed if we hit a memory
+     allocation failure mid-transfer.  */
 
   /* Merely reuse the extra old space into the new table.  */
 #if USE_OBSTACK
-  obstack_free (&new_table->entry_stack, NULL);
   new_table->entry_stack = table->entry_stack;
 #endif
   new_table->free_entry_list = table->free_entry_list;
 
-  for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
-    if (bucket->data)
-      for (cursor = bucket; cursor; cursor = next)
-       {
-         void *data = cursor->data;
-         struct hash_entry *new_bucket
-           = (new_table->bucket
-              + new_table->hasher (data, new_table->n_buckets));
-
-         if (! (new_bucket < new_table->bucket_limit))
-           abort ();
-
-         next = cursor->next;
-
-         if (new_bucket->data)
-           {
-             if (cursor == bucket)
-               {
-                 /* Allocate or recycle an entry, when moving from a bucket
-                    header into a bucket overflow.  */
-                 struct hash_entry *new_entry = allocate_entry (new_table);
-
-                 if (new_entry == NULL)
-                   return false;
-
-                 new_entry->data = data;
-                 new_entry->next = new_bucket->next;
-                 new_bucket->next = new_entry;
-               }
-             else
-               {
-                 /* Merely relink an existing entry, when moving from a
-                    bucket overflow into a bucket overflow.  */
-                 cursor->next = new_bucket->next;
-                 new_bucket->next = cursor;
-               }
-           }
-         else
-           {
-             /* Free an existing entry, when moving from a bucket
-                overflow into a bucket header.  Also take care of the
-                simple case of moving from a bucket header into a bucket
-                header.  */
-             new_bucket->data = data;
-             new_table->n_buckets_used++;
-             if (cursor != bucket)
-               free_entry (new_table, cursor);
-           }
-       }
+  if (transfer_entries (new_table, table, false))
+    {
+      /* Entries transferred successfully; tie up the loose ends.  */
+      free (table->bucket);
+      table->bucket = new_table->bucket;
+      table->bucket_limit = new_table->bucket_limit;
+      table->n_buckets = new_table->n_buckets;
+      table->n_buckets_used = new_table->n_buckets_used;
+      table->free_entry_list = new_table->free_entry_list;
+      /* table->n_entries and table->entry_stack already hold their value.  */
+      return true;
+    }
 
-  free (table->bucket);
-  table->bucket = new_table->bucket;
-  table->bucket_limit = new_table->bucket_limit;
-  table->n_buckets = new_table->n_buckets;
-  table->n_buckets_used = new_table->n_buckets_used;
+  /* We've allocated new_table->bucket (and possibly some entries),
+     exhausted the free list, and moved some but not all entries into
+     new_table.  We must undo the partial move before returning
+     failure.  The only way to get into this situation is if new_table
+     uses fewer buckets than the old table, so we will reclaim some
+     free entries as overflows in the new table are put back into
+     distinct buckets in the old table.
+
+     There are some pathological cases where a single pass through the
+     table requires more intermediate overflow entries than using two
+     passes.  Two passes give worse cache performance and takes
+     longer, but at this point, we're already out of memory, so slow
+     and safe is better than failure.  */
   table->free_entry_list = new_table->free_entry_list;
+  if (! (transfer_entries (table, new_table, true)
+         && transfer_entries (table, new_table, false)))
+    abort ();
   /* table->n_entries already holds its value.  */
-#if USE_OBSTACK
-  table->entry_stack = new_table->entry_stack;
-#endif
-  free (new_table);
-
-  return true;
+  free (new_table->bucket);
+  return false;
 }
 
-/* If ENTRY matches an entry already in the hash table, return the pointer
-   to the entry from the table.  Otherwise, insert ENTRY and return ENTRY.
-   Return NULL if the storage required for insertion cannot be allocated.
-   This implementation does not support duplicate entries or insertion of
-   NULL.  */
-
-void *
-hash_insert (Hash_table *table, const void *entry)
+/* Return -1 upon memory allocation failure.
+   Return 1 if insertion succeeded.
+   Return 0 if there is already a matching entry in the table,
+   and in that case, if MATCHED_ENT is non-NULL, set *MATCHED_ENT
+   to that entry.
+
+   This interface is easier to use than hash_insert when you must
+   distinguish between the latter two cases.  More importantly,
+   hash_insert is unusable for some types of ENTRY values.  When using
+   hash_insert, the only way to distinguish those cases is to compare
+   the return value and ENTRY.  That works only when you can have two
+   different ENTRY values that point to data that compares "equal".  Thus,
+   when the ENTRY value is a simple scalar, you must use hash_insert0.
+   ENTRY must not be NULL.  */
+int
+hash_insert0 (Hash_table *table, void const *entry, void const **matched_ent)
 {
   void *data;
   struct hash_entry *bucket;
 
-  /* The caller cannot insert a NULL entry.  */
+  /* The caller cannot insert a NULL entry, since hash_lookup returns NULL
+     to indicate "not found", and hash_find_entry uses "bucket->data == NULL"
+     to indicate an empty bucket.  */
   if (! entry)
     abort ();
 
   /* If there's a matching entry already in the table, return that.  */
   if ((data = hash_find_entry (table, entry, &bucket, false)) != NULL)
-    return data;
+    {
+      if (matched_ent)
+        *matched_ent = data;
+      return 0;
+    }
 
   /* If the growth threshold of the buckets in use has been reached, increase
      the table size and rehash.  There's no point in checking the number of
@@ -964,29 +1063,29 @@ hash_insert (Hash_table *table, const void *entry)
       > table->tuning->growth_threshold * table->n_buckets)
     {
       /* Check more fully, before starting real work.  If tuning arguments
-        became invalid, the second check will rely on proper defaults.  */
+         became invalid, the second check will rely on proper defaults.  */
       check_tuning (table);
       if (table->n_buckets_used
-         > table->tuning->growth_threshold * table->n_buckets)
-       {
-         const Hash_tuning *tuning = table->tuning;
-         float candidate =
-           (tuning->is_n_buckets
-            ? (table->n_buckets * tuning->growth_factor)
-            : (table->n_buckets * tuning->growth_factor
-               * tuning->growth_threshold));
-
-         if (SIZE_MAX <= candidate)
-           return NULL;
-
-         /* If the rehash fails, arrange to return NULL.  */
-         if (!hash_rehash (table, candidate))
-           return NULL;
-
-         /* Update the bucket we are interested in.  */
-         if (hash_find_entry (table, entry, &bucket, false) != NULL)
-           abort ();
-       }
+          > table->tuning->growth_threshold * table->n_buckets)
+        {
+          const Hash_tuning *tuning = table->tuning;
+          float candidate =
+            (tuning->is_n_buckets
+             ? (table->n_buckets * tuning->growth_factor)
+             : (table->n_buckets * tuning->growth_factor
+                * tuning->growth_threshold));
+
+          if (SIZE_MAX <= candidate)
+            return -1;
+
+          /* If the rehash fails, arrange to return NULL.  */
+          if (!hash_rehash (table, candidate))
+            return -1;
+
+          /* Update the bucket we are interested in.  */
+          if (hash_find_entry (table, entry, &bucket, false) != NULL)
+            abort ();
+        }
     }
 
   /* ENTRY is not matched, it should be inserted.  */
@@ -996,7 +1095,7 @@ hash_insert (Hash_table *table, const void *entry)
       struct hash_entry *new_entry = allocate_entry (table);
 
       if (new_entry == NULL)
-       return NULL;
+        return -1;
 
       /* Add ENTRY in the overflow of the bucket.  */
 
@@ -1004,7 +1103,7 @@ hash_insert (Hash_table *table, const void *entry)
       new_entry->next = bucket->next;
       bucket->next = new_entry;
       table->n_entries++;
-      return (void *) entry;
+      return 1;
     }
 
   /* Add ENTRY right in the bucket head.  */
@@ -1013,7 +1112,23 @@ hash_insert (Hash_table *table, const void *entry)
   table->n_entries++;
   table->n_buckets_used++;
 
-  return (void *) entry;
+  return 1;
+}
+
+/* If ENTRY matches an entry already in the hash table, return the pointer
+   to the entry from the table.  Otherwise, insert ENTRY and return ENTRY.
+   Return NULL if the storage required for insertion cannot be allocated.
+   This implementation does not support duplicate entries or insertion of
+   NULL.  */
+
+void *
+hash_insert (Hash_table *table, void const *entry)
+{
+  void const *matched_ent;
+  int err = hash_insert0 (table, entry, &matched_ent);
+  return (err == -1
+          ? NULL
+          : (void *) (err == 0 ? matched_ent : entry));
 }
 
 /* If ENTRY is already in the table, remove it and return the just-deleted
@@ -1036,27 +1151,45 @@ hash_delete (Hash_table *table, const void *entry)
       table->n_buckets_used--;
 
       /* If the shrink threshold of the buckets in use has been reached,
-        rehash into a smaller table.  */
+         rehash into a smaller table.  */
 
       if (table->n_buckets_used
-         < table->tuning->shrink_threshold * table->n_buckets)
-       {
-         /* Check more fully, before starting real work.  If tuning arguments
-            became invalid, the second check will rely on proper defaults.  */
-         check_tuning (table);
-         if (table->n_buckets_used
-             < table->tuning->shrink_threshold * table->n_buckets)
-           {
-             const Hash_tuning *tuning = table->tuning;
-             size_t candidate =
-               (tuning->is_n_buckets
-                ? table->n_buckets * tuning->shrink_factor
-                : (table->n_buckets * tuning->shrink_factor
-                   * tuning->growth_threshold));
-
-             hash_rehash (table, candidate);
-           }
-       }
+          < table->tuning->shrink_threshold * table->n_buckets)
+        {
+          /* Check more fully, before starting real work.  If tuning arguments
+             became invalid, the second check will rely on proper defaults.  */
+          check_tuning (table);
+          if (table->n_buckets_used
+              < table->tuning->shrink_threshold * table->n_buckets)
+            {
+              const Hash_tuning *tuning = table->tuning;
+              size_t candidate =
+                (tuning->is_n_buckets
+                 ? table->n_buckets * tuning->shrink_factor
+                 : (table->n_buckets * tuning->shrink_factor
+                    * tuning->growth_threshold));
+
+              if (!hash_rehash (table, candidate))
+                {
+                  /* Failure to allocate memory in an attempt to
+                     shrink the table is not fatal.  But since memory
+                     is low, we can at least be kind and free any
+                     spare entries, rather than keeping them tied up
+                     in the free entry list.  */
+#if ! USE_OBSTACK
+                  struct hash_entry *cursor = table->free_entry_list;
+                  struct hash_entry *next;
+                  while (cursor)
+                    {
+                      next = cursor->next;
+                      free (cursor);
+                      cursor = next;
+                    }
+                  table->free_entry_list = NULL;
+#endif
+                }
+            }
+        }
     }
 
   return data;
@@ -1069,22 +1202,22 @@ hash_delete (Hash_table *table, const void *entry)
 void
 hash_print (const Hash_table *table)
 {
-  struct hash_entry const *bucket;
+  struct hash_entry *bucket = (struct hash_entry *) table->bucket;
 
-  for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+  for ( ; bucket < table->bucket_limit; bucket++)
     {
       struct hash_entry *cursor;
 
       if (bucket)
-       printf ("%lu:\n", (unsigned long int) (bucket - table->bucket));
+        printf ("%lu:\n", (unsigned long int) (bucket - table->bucket));
 
       for (cursor = bucket; cursor; cursor = cursor->next)
-       {
-         char const *s = cursor->data;
-         /* FIXME */
-         if (s)
-           printf ("  %s\n", s);
-       }
+        {
+          char const *s = cursor->data;
+          /* FIXME */
+          if (s)
+            printf ("  %s\n", s);
+        }
     }
 }