Annotation of gcc/objc/hash.c, revision 1.1.1.1

1.1       root        1: /* Hash tables for Objective C method dispatch.
                      2:    Copyright (C) 1992 Free Software Foundation, Inc.
                      3: 
                      4: This file is part of GNU CC.
                      5: 
                      6: GNU CC is free software; you can redistribute it and/or modify
                      7: it under the terms of the GNU General Public License as published by
                      8: the Free Software Foundation; either version 2, or (at your option)
                      9: any later version.
                     10: 
                     11: GNU CC is distributed in the hope that it will be useful,
                     12: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14: GNU General Public License for more details.
                     15: 
                     16: You should have received a copy of the GNU General Public License
                     17: along with GNU CC; see the file COPYING.  If not, write to
                     18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     19: 
                     20: /* As a special exception, if you link this library with files
                     21:    compiled with GCC to produce an executable, this does not cause
                     22:    the resulting executable to be covered by the GNU General Public License.
                     23:    This exception does not however invalidate any other reasons why
                     24:    the executable file might be covered by the GNU General Public License.  */
                     25: 
                     26: #include "tconfig.h"
                     27: #include "gstddef.h"
                     28: #include "gstdarg.h"
                     29: #include "assert.h"
                     30: 
                     31: #include "hash.h"
                     32: #include "objc.h"
                     33: #include "objc-proto.h"
                     34: 
                     35: 
                     36: /* These two macros determine when a hash table is full and
                     37:    by how much it should be expanded respectively.
                     38: 
                     39:    These equations are percentages.  */
                     40: #define FULLNESS(cache) \
                     41:    ((((cache)->size * 75) / 100) <= (cache)->used)
                     42: #define EXPANSION(cache) \
                     43:   ((cache)->size * 2)
                     44: 
                     45: cache_ptr
                     46: hash_new (unsigned int size, hash_func_type hash_func,
                     47:          compare_func_type compare_func)
                     48: {
                     49:   cache_ptr cache;
                     50: 
                     51: 
                     52:   /* Pass me a value greater than 0 and a power of 2.  */
                     53:   assert (size);
                     54:   assert (!(size & (size - 1)));
                     55: 
                     56:   /* Allocate the cache structure.  calloc insures
                     57:      its initialization for default values.  */
                     58:   cache = (cache_ptr) calloc (1, sizeof (struct cache));
                     59:   assert (cache);
                     60: 
                     61:   /* Allocate the array of buckets for the cache.
                     62:      calloc initializes all of the pointers to NULL.  */
                     63:   cache->node_table
                     64:     = (node_ptr *) calloc (size, sizeof (node_ptr));
                     65:   assert (cache->node_table);
                     66: 
                     67:   cache->size  = size;
                     68: 
                     69:   /* This should work for all processor architectures? */
                     70:   cache->mask = (size - 1);
                     71:        
                     72:   /* Store the hashing function so that codes can be computed.  */
                     73:   cache->hash_func = hash_func;
                     74: 
                     75:   /* Store the function that compares hash keys to
                     76:      determine if they are equal.  */
                     77:   cache->compare_func = compare_func;
                     78: 
                     79:   return cache;
                     80: }
                     81: 
                     82: 
                     83: void
                     84: hash_delete (cache_ptr cache)
                     85: {
                     86:   node_ptr node;
                     87: 
                     88: 
                     89:   /* Purge all key/value pairs from the table.  */
                     90:   while (node = hash_next (cache, NULL))
                     91:     hash_remove (cache, node->key);
                     92: 
                     93:   /* Release the array of nodes and the cache itself.  */
                     94:   free (cache->node_table);
                     95:   free (cache);
                     96: }
                     97: 
                     98: 
                     99: void
                    100: hash_add (cache_ptr *cachep, const void *key, void *value)
                    101: {
                    102:   size_t indx = (*(*cachep)->hash_func)(*cachep, key);
                    103:   node_ptr node = (node_ptr) calloc (1, sizeof (struct cache_node));
                    104: 
                    105: 
                    106:   assert (node);
                    107: 
                    108:   /* Initialize the new node.  */
                    109:   node->key    = key;
                    110:   node->value  = value;
                    111:   node->next  = (*cachep)->node_table[indx];
                    112: 
                    113:   /* Debugging.
                    114:      Check the list for another key.  */
                    115: #ifdef DEBUG
                    116:   { node_ptr node1 = (*cachep)->node_table[indx];
                    117: 
                    118:     while (node1) {
                    119: 
                    120:       assert (node1->key != key);
                    121:       node1 = node1->next;
                    122:     }
                    123:   }
                    124: #endif
                    125: 
                    126:   /* Install the node as the first element on the list.  */
                    127:   (*cachep)->node_table[indx] = node;
                    128: 
                    129:   /* Bump the number of entries in the cache.  */
                    130:   ++(*cachep)->used;
                    131: 
                    132:   /* Check the hash table's fullness.   We're going
                    133:      to expand if it is above the fullness level.  */
                    134:   if (FULLNESS (*cachep)) {
                    135: 
                    136:     /* The hash table has reached its fullness level.  Time to
                    137:        expand it.
                    138: 
                    139:        I'm using a slow method here but is built on other
                    140:        primitive functions thereby increasing its
                    141:        correctness.  */
                    142:     node_ptr node1 = NULL;
                    143:     cache_ptr new = hash_new (EXPANSION (*cachep),
                    144:                              (*cachep)->hash_func,
                    145:                              (*cachep)->compare_func);
                    146: 
                    147:     DEBUG_PRINTF ("Expanding cache %#x from %d to %d\n",
                    148:                  *cachep, (*cachep)->size, new->size);
                    149: 
                    150:     /* Copy the nodes from the first hash table to the new one.  */
                    151:     while (node1 = hash_next (*cachep, node1))
                    152:       hash_add (&new, node1->key, node1->value);
                    153: 
                    154:     /* Trash the old cache.  */
                    155:     hash_delete (*cachep);
                    156: 
                    157:     /* Return a pointer to the new hash table.  */
                    158:     *cachep = new;
                    159:   }
                    160: }
                    161: 
                    162: 
                    163: void
                    164: hash_remove (cache_ptr cache, const void *key)
                    165: {
                    166:   size_t indx = (*cache->hash_func)(cache, key);
                    167:   node_ptr node = cache->node_table[indx];
                    168: 
                    169: 
                    170:   /* We assume there is an entry in the table.  Error if it is not.  */
                    171:   assert (node);
                    172: 
                    173:   /* Special case.  First element is the key/value pair to be removed.  */
                    174:   if ((*cache->compare_func)(node->key, key)) {
                    175:     cache->node_table[indx] = node->next;
                    176:     free (node);
                    177:   } else {
                    178: 
                    179:     /* Otherwise, find the hash entry.  */
                    180:     node_ptr prev = node;
                    181:     BOOL removed = NO;
                    182: 
                    183:     do {
                    184: 
                    185:       if ((*cache->compare_func)(node->key, key)) {
                    186:         prev->next = node->next, removed = YES;
                    187:         free (node);
                    188:       } else
                    189:         prev = node, node = node->next;
                    190:     } while (!removed && node);
                    191:     assert (removed);
                    192:   }
                    193: 
                    194:   /* Decrement the number of entries in the hash table.  */
                    195:   --cache->used;
                    196: }
                    197: 
                    198: 
                    199: node_ptr
                    200: hash_next (cache_ptr cache, node_ptr node)
                    201: {
                    202:   /* If the scan is being started then reset the last node
                    203:      visitied pointer and bucket index.  */
                    204:   if (!node)
                    205:     cache->last_bucket  = 0;
                    206: 
                    207:   /* If there is a node visited last then check for another
                    208:      entry in the same bucket;  Otherwise step to the next bucket.  */
                    209:   if (node) {
                    210:     if (node->next)
                    211:       /* There is a node which follows the last node
                    212:         returned.  Step to that node and retun it.  */
                    213:       return node->next;
                    214:     else
                    215:       ++cache->last_bucket;
                    216:   }
                    217: 
                    218:   /* If the list isn't exhausted then search the buckets for
                    219:      other nodes.  */
                    220:   if (cache->last_bucket < cache->size) {
                    221:     /*  Scan the remainder of the buckets looking for an entry
                    222:        at the head of the list.  Return the first item found.  */
                    223:     while (cache->last_bucket < cache->size)
                    224:       if (cache->node_table[cache->last_bucket])
                    225:         return cache->node_table[cache->last_bucket];
                    226:       else
                    227:         ++cache->last_bucket;
                    228: 
                    229:     /* No further nodes were found in the hash table.  */
                    230:     return NULL;
                    231:   } else
                    232:     return NULL;
                    233: }
                    234: 
                    235: 
                    236: /* Given KEY, return corresponding value for it in CACHE.
                    237:    Return NULL if the KEY is not recorded.  */
                    238: 
                    239: void *
                    240: hash_value_for_key (cache_ptr cache, const void *key)
                    241: {
                    242:   node_ptr node = cache->node_table[(*cache->hash_func)(cache, key)];
                    243:   void *retval = NULL;
                    244: 
                    245:   if (node)
                    246:     do {
                    247:       if ((*cache->compare_func)(node->key, key))
                    248:         retval = node->value;
                    249:       else
                    250:         node = node->next;
                    251:     } while (!retval && node);
                    252: 
                    253:   return retval;
                    254: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.