(linenum→info "unix/slp.c:2238")

glibc/2.7/misc/hsearch_r.c

    1: /* Copyright (C) 1993,1995-1997,2002,2005,2007 Free Software Foundation, Inc.
    2:    This file is part of the GNU C Library.
    3:    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1993.
    4: 
    5:    The GNU C Library is free software; you can redistribute it and/or
    6:    modify it under the terms of the GNU Lesser General Public
    7:    License as published by the Free Software Foundation; either
    8:    version 2.1 of the License, or (at your option) any later version.
    9: 
   10:    The GNU C Library is distributed in the hope that it will be useful,
   11:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13:    Lesser General Public License for more details.
   14: 
   15:    You should have received a copy of the GNU Lesser General Public
   16:    License along with the GNU C Library; if not, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: #include <errno.h>
   21: #include <malloc.h>
   22: #include <string.h>
   23: 
   24: #include <search.h>
   25: 
   26: /* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
   27:    [Knuth]            The Art of Computer Programming, part 3 (6.4)  */
   28: 
   29: 
   30: /* The reentrant version has no static variables to maintain the state.
   31:    Instead the interface of all functions is extended to take an argument
   32:    which describes the current status.  */
   33: typedef struct _ENTRY
   34: {
   35:   unsigned int used;
   36:   ENTRY entry;
   37: }
   38: _ENTRY;
   39: 
   40: 
   41: /* For the used double hash method the table size has to be a prime. To
   42:    correct the user given table size we need a prime test.  This trivial
   43:    algorithm is adequate because
   44:    a)  the code is (most probably) called a few times per program run and
   45:    b)  the number is small because the table must fit in the core  */
   46: static int
   47: isprime (unsigned int number)
   48: {
   49:   /* no even number will be passed */
   50:   unsigned int div = 3;
   51: 
   52:   while (div * div < number && number % div != 0)
   53:     div += 2;
   54: 
   55:   return number % div != 0;
   56: }
   57: 
   58: 
   59: /* Before using the hash table we must allocate memory for it.
   60:    Test for an existing table are done. We allocate one element
   61:    more as the found prime number says. This is done for more effective
   62:    indexing as explained in the comment for the hsearch function.
   63:    The contents of the table is zeroed, especially the field used
   64:    becomes zero.  */
   65: int
   66: hcreate_r (nel, htab)
   67:      size_t nel;
   68:      struct hsearch_data *htab;
   69: {
   70:   /* Test for correct arguments.  */
   71:   if (htab == NULL)
   72:     {
   73:       __set_errno (EINVAL);
   74:       return 0;
   75:     }
   76: 
   77:   /* There is still another table active. Return with error. */
   78:   if (htab->table != NULL)
   79:     return 0;
   80: 
   81:   /* Change nel to the first prime number not smaller as nel. */
   82:   nel |= 1;      /* make odd */
   83:   while (!isprime (nel))
   84:     nel += 2;
   85: 
   86:   htab->size = nel;
   87:   htab->filled = 0;
   88: 
   89:   /* allocate memory and zero out */
   90:   htab->table = (_ENTRY *) calloc (htab->size + 1, sizeof (_ENTRY));
   91:   if (htab->table == NULL)
   92:     return 0;
   93: 
   94:   /* everything went alright */
   95:   return 1;
   96: }
   97: libc_hidden_def (hcreate_r)
   98: 
   99: 
  100: /* After using the hash table it has to be destroyed. The used memory can
  101:    be freed and the local static variable can be marked as not used.  */
  102: void
  103: hdestroy_r (htab)
  104:      struct hsearch_data *htab;
  105: {
  106:   /* Test for correct arguments.  */
  107:   if (htab == NULL)
  108:     {
  109:       __set_errno (EINVAL);
  110:       return;
  111:     }
  112: 
  113:   /* Free used memory.  */
  114:   free (htab->table);
  115: 
  116:   /* the sign for an existing table is an value != NULL in htable */
  117:   htab->table = NULL;
  118: }
  119: libc_hidden_def (hdestroy_r)
  120: 
  121: 
  122: /* This is the search function. It uses double hashing with open addressing.
  123:    The argument item.key has to be a pointer to an zero terminated, most
  124:    probably strings of chars. The function for generating a number of the
  125:    strings is simple but fast. It can be replaced by a more complex function
  126:    like ajw (see [Aho,Sethi,Ullman]) if the needs are shown.
  127: 
  128:    We use an trick to speed up the lookup. The table is created by hcreate
  129:    with one more element available. This enables us to use the index zero
  130:    special. This index will never be used because we store the first hash
  131:    index in the field used where zero means not used. Every other value
  132:    means used. The used field can be used as a first fast comparison for
  133:    equality of the stored and the parameter value. This helps to prevent
  134:    unnecessary expensive calls of strcmp.  */
  135: int
  136: hsearch_r (item, action, retval, htab)
  137:      ENTRY item;
  138:      ACTION action;
  139:      ENTRY **retval;
  140:      struct hsearch_data *htab;
  141: {
  142:   unsigned int hval;
  143:   unsigned int count;
  144:   unsigned int len = strlen (item.key);
  145:   unsigned int idx;
  146: 
  147:   /* Compute an value for the given string. Perhaps use a better method. */
  148:   hval = len;
  149:   count = len;
  150:   while (count-- > 0)
  151:     {
  152:       hval <<= 4;
  153:       hval += item.key[count];
  154:     }
  155: 
  156:   /* First hash function: simply take the modul but prevent zero. */
  157:   hval %= htab->size;
  158:   if (hval == 0)
  159:     ++hval;
  160: 
  161:   /* The first index tried. */
  162:   idx = hval;
  163: 
  164:   if (htab->table[idx].used)
  165:     {
  166:       /* Further action might be required according to the action value. */
  167:       unsigned hval2;
  168: 
  169:       if (htab->table[idx].used == hval
  170:           && strcmp (item.key, htab->table[idx].entry.key) == 0)
  171:         {
  172:           *retval = &htab->table[idx].entry;
  173:           return 1;
  174:         }
  175: 
  176:       /* Second hash function, as suggested in [Knuth] */
  177:       hval2 = 1 + hval % (htab->size - 2);
  178: 
  179:       do
  180:         {
  181:           /* Because SIZE is prime this guarantees to step through all
  182:              available indeces.  */
  183:           if (idx <= hval2)
  184:             idx = htab->size + idx - hval2;
  185:           else
  186:             idx -= hval2;
  187: 
  188:           /* If we visited all entries leave the loop unsuccessfully.  */
  189:           if (idx == hval)
  190:             break;
  191: 
  192:             /* If entry is found use it. */
  193:           if (htab->table[idx].used == hval
  194:               && strcmp (item.key, htab->table[idx].entry.key) == 0)
  195:             {
  196:               *retval = &htab->table[idx].entry;
  197:               return 1;
  198:             }
  199:         }
  200:       while (htab->table[idx].used);
  201:     }
  202: 
  203:   /* An empty bucket has been found. */
  204:   if (action == ENTER)
  205:     {
  206:       /* If table is full and another entry should be entered return
  207:          with error.  */
  208:       if (htab->filled == htab->size)
  209:         {
  210:           __set_errno (ENOMEM);
  211:           *retval = NULL;
  212:           return 0;
  213:         }
  214: 
  215:       htab->table[idx].used  = hval;
  216:       htab->table[idx].entry = item;
  217: 
  218:       ++htab->filled;
  219: 
  220:       *retval = &htab->table[idx].entry;
  221:       return 1;
  222:     }
  223: 
  224:   __set_errno (ESRCH);
  225:   *retval = NULL;
  226:   return 0;
  227: }
  228: libc_hidden_def (hsearch_r)
Syntax (Markdown)