| /* Fully-inline hash table, used mainly for managing TLS descriptors. | 
 |    Copyright (C) 1999-2016 Free Software Foundation, Inc. | 
 |    This file is part of the GNU C Library. | 
 |    Contributed by Alexandre Oliva  <aoliva@redhat.com> | 
 |  | 
 |    This file is derived from a 2003's version of libiberty's | 
 |    hashtab.c, contributed by Vladimir Makarov (vmakarov@cygnus.com), | 
 |    but with most adaptation points and support for deleting elements | 
 |    removed. | 
 |  | 
 |    The GNU C Library is free software; you can redistribute it and/or | 
 |    modify it under the terms of the GNU Lesser General Public | 
 |    License as published by the Free Software Foundation; either | 
 |    version 2.1 of the License, or (at your option) any later version. | 
 |  | 
 |    The GNU C Library is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |    Lesser General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU Lesser General Public | 
 |    License along with the GNU C Library; if not, see | 
 |    <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #ifndef INLINE_HASHTAB_H | 
 | # define INLINE_HASHTAB_H 1 | 
 |  | 
 | extern void weak_function free (void *ptr); | 
 |  | 
 | struct hashtab | 
 | { | 
 |   /* Table itself.  */ | 
 |   void **entries; | 
 |  | 
 |   /* Current size (in entries) of the hash table */ | 
 |   size_t size; | 
 |  | 
 |   /* Current number of elements.  */ | 
 |   size_t n_elements; | 
 |  | 
 |   /* Free function for the entries array.  This may vary depending on | 
 |      how early the array was allocated.  If it is NULL, then the array | 
 |      can't be freed.  */ | 
 |   void (*free) (void *ptr); | 
 | }; | 
 |  | 
 | inline static struct hashtab * | 
 | htab_create (void) | 
 | { | 
 |   struct hashtab *ht = malloc (sizeof (struct hashtab)); | 
 |  | 
 |   if (! ht) | 
 |     return NULL; | 
 |   ht->size = 3; | 
 |   ht->entries = malloc (sizeof (void *) * ht->size); | 
 |   ht->free = free; | 
 |   if (! ht->entries) | 
 |     { | 
 |       if (ht->free) | 
 | 	ht->free (ht); | 
 |       return NULL; | 
 |     } | 
 |  | 
 |   ht->n_elements = 0; | 
 |  | 
 |   memset (ht->entries, 0, sizeof (void *) * ht->size); | 
 |  | 
 |   return ht; | 
 | } | 
 |  | 
 | /* This is only called from _dl_unmap, so it's safe to call | 
 |    free().  */ | 
 | inline static void | 
 | htab_delete (struct hashtab *htab) | 
 | { | 
 |   int i; | 
 |  | 
 |   for (i = htab->size - 1; i >= 0; i--) | 
 |     free (htab->entries[i]); | 
 |  | 
 |   if (htab->free) | 
 |     htab->free (htab->entries); | 
 |   free (htab); | 
 | } | 
 |  | 
 | /* Similar to htab_find_slot, but without several unwanted side effects: | 
 |     - Does not call htab->eq_f when it finds an existing entry. | 
 |     - Does not change the count of elements/searches/collisions in the | 
 |       hash table. | 
 |    This function also assumes there are no deleted entries in the table. | 
 |    HASH is the hash value for the element to be inserted.  */ | 
 |  | 
 | inline static void ** | 
 | find_empty_slot_for_expand (struct hashtab *htab, int hash) | 
 | { | 
 |   size_t size = htab->size; | 
 |   unsigned int index = hash % size; | 
 |   void **slot = htab->entries + index; | 
 |   int hash2; | 
 |  | 
 |   if (! *slot) | 
 |     return slot; | 
 |  | 
 |   hash2 = 1 + hash % (size - 2); | 
 |   for (;;) | 
 |     { | 
 |       index += hash2; | 
 |       if (index >= size) | 
 | 	index -= size; | 
 |  | 
 |       slot = htab->entries + index; | 
 |       if (! *slot) | 
 | 	return slot; | 
 |     } | 
 | } | 
 |  | 
 | /* The following function changes size of memory allocated for the | 
 |    entries and repeatedly inserts the table elements.  The occupancy | 
 |    of the table after the call will be about 50%.  Naturally the hash | 
 |    table must already exist.  Remember also that the place of the | 
 |    table entries is changed.  If memory allocation failures are allowed, | 
 |    this function will return zero, indicating that the table could not be | 
 |    expanded.  If all goes well, it will return a non-zero value.  */ | 
 |  | 
 | inline static int | 
 | htab_expand (struct hashtab *htab, int (*hash_fn) (void *)) | 
 | { | 
 |   void **oentries; | 
 |   void **olimit; | 
 |   void **p; | 
 |   void **nentries; | 
 |   size_t nsize; | 
 |  | 
 |   oentries = htab->entries; | 
 |   olimit = oentries + htab->size; | 
 |  | 
 |   /* Resize only when table after removal of unused elements is either | 
 |      too full or too empty.  */ | 
 |   if (htab->n_elements * 2 > htab->size) | 
 |     nsize = _dl_higher_prime_number (htab->n_elements * 2); | 
 |   else | 
 |     nsize = htab->size; | 
 |  | 
 |   nentries = calloc (sizeof (void *), nsize); | 
 |   if (nentries == NULL) | 
 |     return 0; | 
 |   htab->entries = nentries; | 
 |   htab->size = nsize; | 
 |  | 
 |   p = oentries; | 
 |   do | 
 |     { | 
 |       if (*p) | 
 | 	*find_empty_slot_for_expand (htab, hash_fn (*p)) | 
 | 	  = *p; | 
 |  | 
 |       p++; | 
 |     } | 
 |   while (p < olimit); | 
 |  | 
 |   /* Without recording the free corresponding to the malloc used to | 
 |      allocate the table, we couldn't tell whether this was allocated | 
 |      by the malloc() built into ld.so or the one in the main | 
 |      executable or libc.  Calling free() for something that was | 
 |      allocated by the early malloc(), rather than the final run-time | 
 |      malloc() could do Very Bad Things (TM).  We will waste memory | 
 |      allocated early as long as there's no corresponding free(), but | 
 |      this isn't so much memory as to be significant.  */ | 
 |  | 
 |   if (htab->free) | 
 |     htab->free (oentries); | 
 |  | 
 |   /* Use the free() corresponding to the malloc() above to free this | 
 |      up.  */ | 
 |   htab->free = free; | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* This function searches for a hash table slot containing an entry | 
 |    equal to the given element.  To delete an entry, call this with | 
 |    INSERT = 0, then call htab_clear_slot on the slot returned (possibly | 
 |    after doing some checks).  To insert an entry, call this with | 
 |    INSERT = 1, then write the value you want into the returned slot. | 
 |    When inserting an entry, NULL may be returned if memory allocation | 
 |    fails.  */ | 
 |  | 
 | inline static void ** | 
 | htab_find_slot (struct hashtab *htab, void *ptr, int insert, | 
 | 		int (*hash_fn)(void *), int (*eq_fn)(void *, void *)) | 
 | { | 
 |   unsigned int index; | 
 |   int hash, hash2; | 
 |   size_t size; | 
 |   void **entry; | 
 |  | 
 |   if (htab->size * 3 <= htab->n_elements * 4 | 
 |       && htab_expand (htab, hash_fn) == 0) | 
 |     return NULL; | 
 |  | 
 |   hash = hash_fn (ptr); | 
 |  | 
 |   size = htab->size; | 
 |   index = hash % size; | 
 |  | 
 |   entry = &htab->entries[index]; | 
 |   if (!*entry) | 
 |     goto empty_entry; | 
 |   else if (eq_fn (*entry, ptr)) | 
 |     return entry; | 
 |  | 
 |   hash2 = 1 + hash % (size - 2); | 
 |   for (;;) | 
 |     { | 
 |       index += hash2; | 
 |       if (index >= size) | 
 | 	index -= size; | 
 |  | 
 |       entry = &htab->entries[index]; | 
 |       if (!*entry) | 
 | 	goto empty_entry; | 
 |       else if (eq_fn (*entry, ptr)) | 
 | 	return entry; | 
 |     } | 
 |  | 
 |  empty_entry: | 
 |   if (!insert) | 
 |     return NULL; | 
 |  | 
 |   htab->n_elements++; | 
 |   return entry; | 
 | } | 
 |  | 
 | #endif /* INLINE_HASHTAB_H */ |