LCOV - code coverage report
Current view: top level - lib - dynamicsizehash.c (source / functions) Hit Total Coverage
Test: elfutils-0.178 Lines: 47 72 65.3 %
Date: 2019-11-26 23:55:16 Functions: 5 7 71.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13