Annotation of tme/libtme/hash.c, revision 1.1.1.1

1.1       root        1: /* $Id: hash.c,v 1.2 2003/09/01 14:24:08 fredette Exp $ */
                      2: 
                      3: /* libtme/hash.c - hash table support: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2003 Matt Fredette
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by Matt Fredette.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     33:  * POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35: 
                     36: #include <tme/common.h>
                     37: _TME_RCSID("$Id: hash.c,v 1.2 2003/09/01 14:24:08 fredette Exp $");
                     38: 
                     39: /* includes: */
                     40: #include <tme/hash.h>
                     41: 
                     42: /* our hash table size array: */
                     43: static unsigned long _tme_hash_sizes[] = {
                     44:   2,
                     45:   3,
                     46:   5,
                     47:   7,
                     48:   11,
                     49:   17,
                     50:   37,
                     51:   83,
                     52:   281,
                     53:   421,
                     54:   631,
                     55:   947,
                     56:   2131,
                     57:   7193,
                     58:   10789,
                     59:   16183,
                     60:   81929,
                     61:   414763,
                     62:   933217,
                     63:   10629917,
                     64:   35875969,
                     65:   80720929,
                     66: };
                     67: 
                     68: /* this allocates and returns a new hash: */
                     69: tme_hash_t
                     70: tme_hash_new(tme_hash_func_t hash_func,
                     71:             tme_compare_func_t compare_func,
                     72:             tme_hash_data_t value_null)
                     73: {
                     74:   tme_hash_t hash;
                     75: 
                     76:   hash = tme_new0(struct _tme_hash, 1);
                     77:   hash->_tme_hash_size = _tme_hash_sizes[0];
                     78:   hash->_tme_hash_table = 
                     79:     tme_new0(struct _tme_hash_bucket *,
                     80:             hash->_tme_hash_size);
                     81:   hash->_tme_hash_count = 0;
                     82:   hash->_tme_hash_hash = hash_func;
                     83:   hash->_tme_hash_compare = compare_func;
                     84:   hash->_tme_hash_null = value_null;
                     85:   return (hash);
                     86: }
                     87: 
                     88: /* this destroys a hash: */
                     89: void
                     90: tme_hash_destroy(tme_hash_t hash)
                     91: {
                     92:   struct _tme_hash_bucket *bucket, *bucket_next;
                     93:   unsigned long bucket_i;
                     94: 
                     95:   /* free all of the buckets in the hash table: */
                     96:   for (bucket_i = 0;
                     97:        bucket_i < hash->_tme_hash_size;
                     98:        bucket_i++) {
                     99:     for (bucket = hash->_tme_hash_table[bucket_i];
                    100:         bucket != NULL;
                    101:         bucket = bucket_next) {
                    102:       bucket_next = bucket->_tme_hash_bucket_next;
                    103:       tme_free(bucket);
                    104:     }
                    105:   }
                    106:   tme_free(hash->_tme_hash_table);
                    107:   tme_free(hash);
                    108: }
                    109: 
                    110: /* this does an internal lookup in a hash table: */
                    111: static struct _tme_hash_bucket *
                    112: _tme_hash_lookup_internal(tme_hash_t hash,
                    113:                          tme_hash_data_t key,
                    114:                          struct _tme_hash_bucket ***__bucket)
                    115: {
                    116:   unsigned long bucket_i;
                    117:   struct _tme_hash_bucket **_bucket, *bucket;
                    118:   
                    119:   /* hash the key: */
                    120:   bucket_i = (*hash->_tme_hash_hash)(key) % hash->_tme_hash_size;
                    121: 
                    122:   /* walk the chain of buckets: */
                    123:   for (_bucket = hash->_tme_hash_table + bucket_i;
                    124:        (bucket = *_bucket) != NULL;
                    125:        _bucket = &bucket->_tme_hash_bucket_next) {
                    126:     
                    127:     /* compare the key in this bucket with the lookup key.
                    128:        if it succeeds, return the bucket: */
                    129:     if ((*hash->_tme_hash_compare)(key, bucket->_tme_hash_bucket_key)) {
                    130:       if (__bucket != NULL) {
                    131:        *__bucket = _bucket;
                    132:       }
                    133:       return (bucket);
                    134:     }
                    135:   }
                    136: 
                    137:   /* the lookup failed.  return where the bucket might be inserted: */
                    138:   if (__bucket != NULL) {
                    139:     *__bucket = _bucket;
                    140:   }
                    141:   return (NULL);
                    142: }
                    143: 
                    144: /* this inserts a value into a hash table: */
                    145: void
                    146: tme_hash_insert(tme_hash_t hash,
                    147:                tme_hash_data_t key,
                    148:                tme_hash_data_t value)
                    149: {
                    150:   struct _tme_hash_bucket *bucket, *bucket_next, **_bucket;
                    151:   struct _tme_hash hash_new;
                    152:   int size_i;
                    153:   unsigned long bucket_i;
                    154: 
                    155:   /* if this key is not already present in the hash table: */
                    156:   bucket = _tme_hash_lookup_internal(hash, key, &_bucket);
                    157:   if (bucket == NULL) {
                    158: 
                    159:     /* if we need to resize this hash table: */
                    160:     if ((hash->_tme_hash_count * 2) > hash->_tme_hash_size) {
                    161: 
                    162:       /* make a copy of the top of the hash: */
                    163:       hash_new = *hash;
                    164: 
                    165:       /* set the new size of the hash: */
                    166:       hash_new._tme_hash_size = hash->_tme_hash_count * 2;
                    167:       for (size_i = 0;
                    168:           _tme_hash_sizes[size_i] < hash_new._tme_hash_size;
                    169:           size_i++) {
                    170:        if (size_i + 1 == TME_ARRAY_ELS(_tme_hash_sizes)) {
                    171:          abort();
                    172:        }
                    173:       }
                    174:       hash_new._tme_hash_size = _tme_hash_sizes[size_i];
                    175: 
                    176:       /* allocate the new hash table: */
                    177:       hash_new._tme_hash_table = 
                    178:        tme_new0(struct _tme_hash_bucket *,
                    179:                 hash_new._tme_hash_size);
                    180: 
                    181:       /* move everything from the old hash table into the new: */
                    182:       for (bucket_i = 0;
                    183:           bucket_i < hash->_tme_hash_size;
                    184:           bucket_i++) {
                    185:        for (bucket = hash->_tme_hash_table[bucket_i];
                    186:             bucket != NULL;
                    187:             bucket = bucket_next) {
                    188:          bucket_next = bucket->_tme_hash_bucket_next;
                    189:          _tme_hash_lookup_internal(&hash_new,
                    190:                                    bucket->_tme_hash_bucket_key,
                    191:                                    &_bucket);
                    192:          bucket->_tme_hash_bucket_next = *_bucket;
                    193:          *_bucket = bucket;
                    194:        }
                    195:       }
                    196: 
                    197:       /* free the old hash table: */
                    198:       tme_free(hash->_tme_hash_table);
                    199: 
                    200:       /* set the new top of the hash: */
                    201:       *hash = hash_new;
                    202:     
                    203:       /* do the internal lookup again: */
                    204:       _tme_hash_lookup_internal(hash, key, &_bucket);
                    205:     }
                    206: 
                    207:     /* create the new bucket and link it in: */
                    208:     bucket = tme_new(struct _tme_hash_bucket, 1);
                    209:     bucket->_tme_hash_bucket_next = *_bucket;
                    210:     *_bucket = bucket;
                    211: 
                    212:     /* increment the number of keys in the hash: */
                    213:     hash->_tme_hash_count++;
                    214:   }
                    215: 
                    216:   /* set the key and value in the bucket: */
                    217:   bucket->_tme_hash_bucket_key = key;
                    218:   bucket->_tme_hash_bucket_value = value;
                    219: }
                    220: 
                    221: /* this looks up a key in the hash: */
                    222: tme_hash_data_t
                    223: tme_hash_lookup(tme_hash_t hash,
                    224:                tme_hash_data_t key)
                    225: {
                    226:   struct _tme_hash_bucket *bucket;
                    227: 
                    228:   bucket = _tme_hash_lookup_internal(hash, key, NULL);
                    229:   return (bucket != NULL
                    230:          ? bucket->_tme_hash_bucket_value
                    231:          : hash->_tme_hash_null);
                    232: }
                    233: 
                    234: /* this removes a key in the hash: */
                    235: void
                    236: tme_hash_remove(tme_hash_t hash,
                    237:                tme_hash_data_t key)
                    238: {
                    239:   struct _tme_hash_bucket *bucket, **_bucket;
                    240: 
                    241:   bucket = _tme_hash_lookup_internal(hash, key, &_bucket);
                    242:   if (bucket != NULL) {
                    243:     *_bucket = bucket->_tme_hash_bucket_next;
                    244:     tme_free(bucket);
                    245:     hash->_tme_hash_count--;
                    246:   }
                    247: }
                    248: 
                    249: /* this calls a function for each key and value in the hash: */
                    250: void
                    251: tme_hash_foreach(tme_hash_t hash,
                    252:                 tme_foreach_func_t func,
                    253:                 void *private)
                    254: {
                    255:   struct _tme_hash_bucket *bucket;
                    256:   unsigned long bucket_i;
                    257: 
                    258:   /* walk all of the buckets in the hash table: */
                    259:   for (bucket_i = 0;
                    260:        bucket_i < hash->_tme_hash_size;
                    261:        bucket_i++) {
                    262:     for (bucket = hash->_tme_hash_table[bucket_i];
                    263:         bucket != NULL;
                    264:         bucket = bucket->_tme_hash_bucket_next) {
                    265:       (*func)(bucket->_tme_hash_bucket_key,
                    266:              bucket->_tme_hash_bucket_value,
                    267:              private);
                    268:     }
                    269:   }
                    270: }
                    271: 
                    272: /* this calls a function for each key and value in the hash.
                    273:    if the function returns TRUE the entry is removed: */
                    274: unsigned long
                    275: tme_hash_foreach_remove(tme_hash_t hash,
                    276:                        tme_foreach_remove_func_t func,
                    277:                        void *private)
                    278: {
                    279:   struct _tme_hash_bucket **_bucket, *bucket;
                    280:   unsigned long bucket_i, count;
                    281: 
                    282:   /* walk all of the buckets in the hash table: */
                    283:   count = 0;
                    284:   for (bucket_i = 0;
                    285:        bucket_i < hash->_tme_hash_size;
                    286:        bucket_i++) {
                    287:     for (_bucket = &hash->_tme_hash_table[bucket_i];
                    288:         (bucket = *_bucket) != NULL; ) {
                    289:       if ((*func)(bucket->_tme_hash_bucket_key,
                    290:                  bucket->_tme_hash_bucket_value,
                    291:                  private)) {
                    292:        *_bucket = bucket->_tme_hash_bucket_next;
                    293:        tme_free(bucket);
                    294:        hash->_tme_hash_count--;
                    295:        count++;
                    296:       }
                    297:       else {
                    298:        _bucket = &bucket->_tme_hash_bucket_next;
                    299:       }
                    300:     }
                    301:   }
                    302:   return (count);
                    303: }
                    304: 
                    305: /* this hashes a direct value: */
                    306: unsigned long
                    307: tme_direct_hash(tme_hash_data_t key)
                    308: {
                    309:   return ((unsigned long) key);
                    310: }
                    311: 
                    312: /* this compares two direct values: */
                    313: int
                    314: tme_direct_compare(tme_hash_data_t key0,
                    315:                   tme_hash_data_t key1)
                    316: {
                    317:   return (key0 == key1);
                    318: }
                    319: 
                    320: /* this hashes a string value: */
                    321: unsigned long
                    322: tme_string_hash(tme_hash_data_t key)
                    323: {
                    324:   /* this is cribbed from the Dragon book: */
                    325:   const char *p;
                    326:   char c;
                    327:   unsigned long h, g;
                    328: 
                    329:   p = (const char *) key;
                    330:   h = 0;
                    331: 
                    332:   for (; (c = *(p++)) != '\0'; ) {
                    333:     h = (h << 4) + c;
                    334:     g = (h & 0xf0000000);
                    335:     if (g) {
                    336:       h = h ^ (g >> 24);
                    337:       h = h ^ g;
                    338:     }
                    339:   }
                    340: 
                    341:   return (h);
                    342: }
                    343: 
                    344: /* this compares two string values: */
                    345: int
                    346: tme_string_compare(tme_hash_data_t key0,
                    347:                   tme_hash_data_t key1)
                    348: {
                    349:   return (!strcmp((const char *) key0, (const char *) key1));
                    350: }
                    351: 

unix.superglobalmegacorp.com

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