Home | History | Annotate | Download | only in lib
      1 /* Copyright (C) 2000, 2001, 2002 Red Hat, Inc.
      2    Written by Ulrich Drepper <drepper (at) redhat.com>, 2000.
      3 
      4    This program is Open Source software; you can redistribute it and/or
      5    modify it under the terms of the Open Software License version 1.0 as
      6    published by the Open Source Initiative.
      7 
      8    You should have received a copy of the Open Software License along
      9    with this program; if not, you may obtain a copy of the Open Software
     10    License version 1.0 from http://www.opensource.org/licenses/osl.php or
     11    by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
     12    3001 King Ranch Road, Ukiah, CA 95482.   */
     13 
     14 #include <assert.h>
     15 #include <stdlib.h>
     16 #include <system.h>
     17 
     18 /* Before including this file the following macros must be defined:
     19 
     20    NAME      name of the hash table structure.
     21    TYPE      data type of the hash table entries
     22    COMPARE   comparison function taking two pointers to TYPE objects
     23 
     24    The following macros if present select features:
     25 
     26    ITERATE   iterating over the table entries is possible
     27    REVERSE   iterate in reverse order of insert
     28  */
     29 
     30 
     31 static size_t
     32 lookup (htab, hval, val)
     33      NAME *htab;
     34      unsigned long int hval;
     35      TYPE val;
     36 {
     37   /* First hash function: simply take the modul but prevent zero.  */
     38   size_t idx = 1 + hval % htab->size;
     39 
     40   if (htab->table[idx].hashval != 0)
     41     {
     42       unsigned long int hash;
     43 
     44       if (htab->table[idx].hashval == hval
     45 	  && COMPARE (htab->table[idx].data, val) == 0)
     46 	return idx;
     47 
     48       /* Second hash function as suggested in [Knuth].  */
     49       hash = 1 + hval % (htab->size - 2);
     50 
     51       do
     52 	{
     53 	  if (idx <= hash)
     54 	    idx = htab->size + idx - hash;
     55 	  else
     56 	    idx -= hash;
     57 
     58 	  /* If entry is found use it.  */
     59 	  if (htab->table[idx].hashval == hval
     60 	      && COMPARE (htab->table[idx].data, val) == 0)
     61 	    return idx;
     62 	}
     63       while (htab->table[idx].hashval);
     64     }
     65   return idx;
     66 }
     67 
     68 
     69 static void
     70 insert_entry_2 (NAME *htab, unsigned long int hval, size_t idx, TYPE data)
     71 {
     72 #ifdef ITERATE
     73   if (htab->table[idx].hashval == 0)
     74     {
     75 # ifdef REVERSE
     76       htab->table[idx].next = htab->first;
     77       htab->first = &htab->table[idx];
     78 # else
     79       /* Add the new value to the list.  */
     80       if (htab->first == NULL)
     81 	htab->first = htab->table[idx].next = &htab->table[idx];
     82       else
     83 	{
     84 	  htab->table[idx].next = htab->first->next;
     85 	  htab->first = htab->first->next = &htab->table[idx];
     86 	}
     87 # endif
     88     }
     89 #endif
     90 
     91   htab->table[idx].hashval = hval;
     92   htab->table[idx].data = data;
     93 
     94   ++htab->filled;
     95   if (100 * htab->filled > 90 * htab->size)
     96     {
     97       /* Table is filled more than 90%.  Resize the table.  */
     98 #ifdef ITERATE
     99       __typeof__ (htab->first) first;
    100 # ifndef REVERSE
    101       __typeof__ (htab->first) runp;
    102 # endif
    103 #else
    104       unsigned long int old_size = htab->size;
    105 #endif
    106 #define _TABLE(name) \
    107       name##_ent *table = htab->table
    108 #define TABLE(name) _TABLE (name)
    109       TABLE(NAME);
    110 
    111       htab->size = next_prime (htab->size * 2);
    112       htab->filled = 0;
    113 #ifdef ITERATE
    114       first = htab->first;
    115       htab->first = NULL;
    116 #endif
    117       htab->table = calloc ((1 + htab->size), sizeof (htab->table[0]));
    118       if (htab->table == NULL)
    119 	{
    120 	  /* We cannot enlarge the table.  Live with what we got.  This
    121 	     might lead to an infinite loop at some point, though.  */
    122 	  htab->table = table;
    123 	  return;
    124 	}
    125 
    126       /* Add the old entries to the new table.  When iteration is
    127 	 supported we maintain the order.  */
    128 #ifdef ITERATE
    129 # ifdef REVERSE
    130       while (first != NULL)
    131 	{
    132 	  insert_entry_2 (htab, first->hashval,
    133 			  lookup (htab, first->hashval, first->data),
    134 			  first->data);
    135 
    136 	  first = first->next;
    137 	}
    138 # else
    139       assert (first != NULL);
    140       runp = first = first->next;
    141       do
    142 	insert_entry_2 (htab, runp->hashval,
    143 			lookup (htab, runp->hashval, runp->data), runp->data);
    144       while ((runp = runp->next) != first);
    145 # endif
    146 #else
    147       for (idx = 1; idx <= old_size; ++idx)
    148 	if (table[idx].hashval != 0)
    149 	  insert_entry_2 (htab, table[idx].hashval,
    150 			  lookup (htab, table[idx].hashval, table[idx].data),
    151 			  table[idx].data);
    152 #endif
    153 
    154       free (table);
    155     }
    156 }
    157 
    158 
    159 int
    160 #define INIT(name) _INIT (name)
    161 #define _INIT(name) \
    162   name##_init
    163 INIT(NAME) (htab, init_size)
    164      NAME *htab;
    165      unsigned long int init_size;
    166 {
    167   /* We need the size to be a prime.  */
    168   init_size = next_prime (init_size);
    169 
    170   /* Initialize the data structure.  */
    171   htab->size = init_size;
    172   htab->filled = 0;
    173 #ifdef ITERATE
    174   htab->first = NULL;
    175 #endif
    176   htab->table = (void *) calloc ((init_size + 1), sizeof (htab->table[0]));
    177   if (htab->table == NULL)
    178     return -1;
    179 
    180   return 0;
    181 }
    182 
    183 
    184 int
    185 #define FREE(name) _FREE (name)
    186 #define _FREE(name) \
    187   name##_free
    188 FREE(NAME) (htab)
    189      NAME *htab;
    190 {
    191   free (htab->table);
    192   return 0;
    193 }
    194 
    195 
    196 int
    197 #define INSERT(name) _INSERT (name)
    198 #define _INSERT(name) \
    199   name##_insert
    200 INSERT(NAME) (htab, hval, data)
    201      NAME *htab;
    202      unsigned long int hval;
    203      TYPE data;
    204 {
    205   size_t idx;
    206 
    207   /* Make the hash value nonzero.  */
    208   hval = hval ?: 1;
    209 
    210   idx = lookup (htab, hval, data);
    211 
    212   if (htab->table[idx].hashval != 0)
    213     /* We don't want to overwrite the old value.  */
    214     return -1;
    215 
    216   /* An empty bucket has been found.  */
    217   insert_entry_2 (htab, hval, idx, data);
    218   return 0;
    219 }
    220 
    221 
    222 #ifdef OVERWRITE
    223 int
    224 #define INSERT(name) _INSERT (name)
    225 #define _INSERT(name) \
    226   name##_overwrite
    227 INSERT(NAME) (htab, hval, data)
    228      NAME *htab;
    229      unsigned long int hval;
    230      TYPE data;
    231 {
    232   size_t idx;
    233 
    234   /* Make the hash value nonzero.  */
    235   hval = hval ?: 1;
    236 
    237   idx = lookup (htab, hval, data);
    238 
    239   /* The correct bucket has been found.  */
    240   insert_entry_2 (htab, hval, idx, data);
    241   return 0;
    242 }
    243 #endif
    244 
    245 
    246 TYPE
    247 #define FIND(name) _FIND (name)
    248 #define _FIND(name) \
    249   name##_find
    250 FIND(NAME) (htab, hval, val)
    251      NAME *htab;
    252      unsigned long int hval;
    253      TYPE val;
    254 {
    255   size_t idx;
    256 
    257   /* Make the hash value nonzero.  */
    258   hval = hval ?: 1;
    259 
    260   idx = lookup (htab, hval, val);
    261 
    262   if (htab->table[idx].hashval == 0)
    263     return NULL;
    264 
    265   return htab->table[idx].data;
    266 }
    267 
    268 
    269 #ifdef ITERATE
    270 # define ITERATEFCT(name) _ITERATEFCT (name)
    271 # define _ITERATEFCT(name) \
    272   name##_iterate
    273 TYPE
    274 ITERATEFCT(NAME) (htab, ptr)
    275      NAME *htab;
    276      void **ptr;
    277 {
    278   void *p = *ptr;
    279 
    280 # define TYPENAME(name) _TYPENAME (name)
    281 # define _TYPENAME(name) name##_ent
    282 
    283 # ifdef REVERSE
    284   if (p == NULL)
    285     p = htab->first;
    286   else
    287     p = ((TYPENAME(NAME) *) p)->next;
    288 
    289   if (p == NULL)
    290     {
    291       *ptr = NULL;
    292       return NULL;
    293     }
    294 # else
    295   if (p == NULL)
    296     {
    297       if (htab->first == NULL)
    298 	return NULL;
    299       p = htab->first->next;
    300     }
    301   else
    302     {
    303       if (p == htab->first)
    304 	return NULL;
    305 
    306       p = ((TYPENAME(NAME) *) p)->next;
    307     }
    308 # endif
    309 
    310   /* Prepare the next element.  If possible this will pull the data
    311      into the cache, for reading.  */
    312   __builtin_prefetch (((TYPENAME(NAME) *) p)->next, 0, 2);
    313 
    314   return ((TYPENAME(NAME) *) (*ptr = p))->data;
    315 }
    316 #endif
    317