Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals

st.c

Go to the documentation of this file.
00001 /* This is a public domain general purpose hash table package written by Peter Moore @ UCB. */
00002 
00003 /* static       char    sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */
00004 
00005 #include "config.h"
00006 #include "defines.h"
00007 #include <stdio.h>
00008 #ifdef HAVE_STDLIB_H
00009 #include <stdlib.h>
00010 #endif
00011 #include <string.h>
00012 #include "st.h"
00013 
00014 typedef struct st_table_entry st_table_entry;
00015 
00016 struct st_table_entry {
00017     unsigned int hash;
00018     st_data_t key;
00019     st_data_t record;
00020     st_table_entry *next;
00021 };
00022 
00023 #define ST_DEFAULT_MAX_DENSITY 5
00024 #define ST_DEFAULT_INIT_TABLE_SIZE 11
00025 
00026     /*
00027      * DEFAULT_MAX_DENSITY is the default for the largest we allow the
00028      * average number of items per bin before increasing the number of
00029      * bins
00030      *
00031      * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins
00032      * allocated initially
00033      *
00034      */
00035 static int numcmp(long, long);
00036 static int numhash(long);
00037 static struct st_hash_type type_numhash = {
00038     numcmp,
00039     numhash,
00040 };
00041 
00042 /* extern int strcmp(const char *, const char *); */
00043 static int strhash(const char *);
00044 static struct st_hash_type type_strhash = {
00045     strcmp,
00046     strhash,
00047 };
00048 
00049 static void rehash(st_table *);
00050 
00051 #define alloc(type) (type*)malloc((unsigned)sizeof(type))
00052 #define Calloc(n,s) (char*)calloc((n),(s))
00053 
00054 #define EQUAL(table,x,y) ((x)==(y) || (*table->type->compare)((x),(y)) == 0)
00055 
00056 #define do_hash(key,table) (unsigned int)(*(table)->type->hash)((key))
00057 #define do_hash_bin(key,table) (do_hash(key, table)%(table)->num_bins)
00058 
00059 /*
00060  * MINSIZE is the minimum size of a dictionary.
00061  */
00062 
00063 #define MINSIZE 8
00064 
00065 /*
00066 Table of prime numbers 2^n+a, 2<=n<=30.
00067 */
00068 static long primes[] = {
00069         8 + 3,
00070         16 + 3,
00071         32 + 5,
00072         64 + 3,
00073         128 + 3,
00074         256 + 27,
00075         512 + 9,
00076         1024 + 9,
00077         2048 + 5,
00078         4096 + 3,
00079         8192 + 27,
00080         16384 + 43,
00081         32768 + 3,
00082         65536 + 45,
00083         131072 + 29,
00084         262144 + 3,
00085         524288 + 21,
00086         1048576 + 7,
00087         2097152 + 17,
00088         4194304 + 15,
00089         8388608 + 9,
00090         16777216 + 43,
00091         33554432 + 35,
00092         67108864 + 15,
00093         134217728 + 29,
00094         268435456 + 3,
00095         536870912 + 11,
00096         1073741824 + 85,
00097         0
00098 };
00099 
00100 static int
00101 new_size(size)
00102     int size;
00103 {
00104     int i;
00105 
00106 #if 0
00107     for (i=3; i<31; i++) {
00108         if ((1<<i) > size) return 1<<i;
00109     }
00110     return -1;
00111 #else
00112     int newsize;
00113 
00114     for (i = 0, newsize = MINSIZE;
00115          i < sizeof(primes)/sizeof(primes[0]);
00116          i++, newsize <<= 1)
00117     {
00118         if (newsize > size) return primes[i];
00119     }
00120     /* Ran out of polynomials */
00121     return -1;                  /* should raise exception */
00122 #endif
00123 }
00124 
00125 #ifdef HASH_LOG
00126 static int collision = 0;
00127 static int init_st = 0;
00128 
00129 static void
00130 stat_col()
00131 {
00132     FILE *f = fopen("/tmp/col", "w");
00133     fprintf(f, "collision: %d\n", collision);
00134     fclose(f);
00135 }
00136 #endif
00137 
00138 st_table*
00139 st_init_table_with_size(type, size)
00140     struct st_hash_type *type;
00141     int size;
00142 {
00143     st_table *tbl;
00144 
00145 #ifdef HASH_LOG
00146     if (init_st == 0) {
00147         init_st = 1;
00148         atexit(stat_col);
00149     }
00150 #endif
00151 
00152     size = new_size(size);      /* round up to prime number */
00153 
00154     tbl = alloc(st_table);
00155     tbl->type = type;
00156     tbl->num_entries = 0;
00157     tbl->num_bins = size;
00158     tbl->bins = (st_table_entry **)Calloc(size, sizeof(st_table_entry*));
00159 
00160     return tbl;
00161 }
00162 
00163 st_table*
00164 st_init_table(type)
00165     struct st_hash_type *type;
00166 {
00167     return st_init_table_with_size(type, 0);
00168 }
00169 
00170 st_table*
00171 st_init_numtable(void)
00172 {
00173     return st_init_table(&type_numhash);
00174 }
00175 
00176 st_table*
00177 st_init_numtable_with_size(size)
00178     int size;
00179 {
00180     return st_init_table_with_size(&type_numhash, size);
00181 }
00182 
00183 st_table*
00184 st_init_strtable(void)
00185 {
00186     return st_init_table(&type_strhash);
00187 }
00188 
00189 st_table*
00190 st_init_strtable_with_size(size)
00191     int size;
00192 {
00193     return st_init_table_with_size(&type_strhash, size);
00194 }
00195 
00196 void
00197 st_free_table(table)
00198     st_table *table;
00199 {
00200     register st_table_entry *ptr, *next;
00201     int i;
00202 
00203     for(i = 0; i < table->num_bins; i++) {
00204         ptr = table->bins[i];
00205         while (ptr != 0) {
00206             next = ptr->next;
00207             free(ptr);
00208             ptr = next;
00209         }
00210     }
00211     free(table->bins);
00212     free(table);
00213 }
00214 
00215 #define PTR_NOT_EQUAL(table, ptr, hash_val, key) \
00216 ((ptr) != 0 && (ptr->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key)))
00217 
00218 #ifdef HASH_LOG
00219 #define COLLISION collision++
00220 #else
00221 #define COLLISION
00222 #endif
00223 
00224 #define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\
00225     bin_pos = hash_val%(table)->num_bins;\
00226     ptr = (table)->bins[bin_pos];\
00227     if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {\
00228         COLLISION;\
00229         while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\
00230             ptr = ptr->next;\
00231         }\
00232         ptr = ptr->next;\
00233     }\
00234 } while (0)
00235 
00236 int
00237 st_lookup(table, key, value)
00238     st_table *table;
00239     register st_data_t key;
00240     st_data_t *value;
00241 {
00242     unsigned int hash_val, bin_pos;
00243     register st_table_entry *ptr;
00244 
00245     hash_val = do_hash(key, table);
00246     FIND_ENTRY(table, ptr, hash_val, bin_pos);
00247 
00248     if (ptr == 0) {
00249         return 0;
00250     }
00251     else {
00252         if (value != 0)  *value = ptr->record;
00253         return 1;
00254     }
00255 }
00256 
00257 #define ADD_DIRECT(table, key, value, hash_val, bin_pos)\
00258 do {\
00259     st_table_entry *entry;\
00260     if (table->num_entries/(table->num_bins) > ST_DEFAULT_MAX_DENSITY) {\
00261         rehash(table);\
00262         bin_pos = hash_val % table->num_bins;\
00263     }\
00264     \
00265     entry = alloc(st_table_entry);\
00266     \
00267     entry->hash = hash_val;\
00268     entry->key = key;\
00269     entry->record = value;\
00270     entry->next = table->bins[bin_pos];\
00271     table->bins[bin_pos] = entry;\
00272     table->num_entries++;\
00273 } while (0)
00274 
00275 int
00276 st_insert(table, key, value)
00277     register st_table *table;
00278     register st_data_t key;
00279     st_data_t value;
00280 {
00281     unsigned int hash_val, bin_pos;
00282     register st_table_entry *ptr;
00283 
00284     hash_val = do_hash(key, table);
00285     FIND_ENTRY(table, ptr, hash_val, bin_pos);
00286 
00287     if (ptr == 0) {
00288         ADD_DIRECT(table, key, value, hash_val, bin_pos);
00289         return 0;
00290     }
00291     else {
00292         ptr->record = value;
00293         return 1;
00294     }
00295 }
00296 
00297 void
00298 st_add_direct(table, key, value)
00299     st_table *table;
00300     st_data_t key;
00301     st_data_t value;
00302 {
00303     unsigned int hash_val, bin_pos;
00304 
00305     hash_val = do_hash(key, table);
00306     bin_pos = hash_val % table->num_bins;
00307     ADD_DIRECT(table, key, value, hash_val, bin_pos);
00308 }
00309 
00310 static void
00311 rehash(table)
00312     register st_table *table;
00313 {
00314     register st_table_entry *ptr, *next, **new_bins;
00315     int i, old_num_bins = table->num_bins, new_num_bins;
00316     unsigned int hash_val;
00317 
00318     new_num_bins = new_size(old_num_bins+1);
00319     new_bins = (st_table_entry**)Calloc(new_num_bins, sizeof(st_table_entry*));
00320 
00321     for(i = 0; i < old_num_bins; i++) {
00322         ptr = table->bins[i];
00323         while (ptr != 0) {
00324             next = ptr->next;
00325             hash_val = ptr->hash % new_num_bins;
00326             ptr->next = new_bins[hash_val];
00327             new_bins[hash_val] = ptr;
00328             ptr = next;
00329         }
00330     }
00331     free(table->bins);
00332     table->num_bins = new_num_bins;
00333     table->bins = new_bins;
00334 }
00335 
00336 st_table*
00337 st_copy(old_table)
00338     st_table *old_table;
00339 {
00340     st_table *new_table;
00341     st_table_entry *ptr, *entry;
00342     int i, num_bins = old_table->num_bins;
00343 
00344     new_table = alloc(st_table);
00345     if (new_table == 0) {
00346         return 0;
00347     }
00348 
00349     *new_table = *old_table;
00350     new_table->bins = (st_table_entry**)
00351         Calloc((unsigned)num_bins, sizeof(st_table_entry*));
00352 
00353     if (new_table->bins == 0) {
00354         free(new_table);
00355         return 0;
00356     }
00357 
00358     for(i = 0; i < num_bins; i++) {
00359         new_table->bins[i] = 0;
00360         ptr = old_table->bins[i];
00361         while (ptr != 0) {
00362             entry = alloc(st_table_entry);
00363             if (entry == 0) {
00364                 free(new_table->bins);
00365                 free(new_table);
00366                 return 0;
00367             }
00368             *entry = *ptr;
00369             entry->next = new_table->bins[i];
00370             new_table->bins[i] = entry;
00371             ptr = ptr->next;
00372         }
00373     }
00374     return new_table;
00375 }
00376 
00377 int
00378 st_delete(table, key, value)
00379     register st_table *table;
00380     register st_data_t *key;
00381     st_data_t *value;
00382 {
00383     unsigned int hash_val;
00384     st_table_entry *tmp;
00385     register st_table_entry *ptr;
00386 
00387     hash_val = do_hash_bin(*key, table);
00388     ptr = table->bins[hash_val];
00389 
00390     if (ptr == 0) {
00391         if (value != 0) *value = 0;
00392         return 0;
00393     }
00394 
00395     if (EQUAL(table, *key, ptr->key)) {
00396         table->bins[hash_val] = ptr->next;
00397         table->num_entries--;
00398         if (value != 0) *value = ptr->record;
00399         *key = ptr->key;
00400         free(ptr);
00401         return 1;
00402     }
00403 
00404     for(; ptr->next != 0; ptr = ptr->next) {
00405         if (EQUAL(table, ptr->next->key, *key)) {
00406             tmp = ptr->next;
00407             ptr->next = ptr->next->next;
00408             table->num_entries--;
00409             if (value != 0) *value = tmp->record;
00410             *key = tmp->key;
00411             free(tmp);
00412             return 1;
00413         }
00414     }
00415 
00416     return 0;
00417 }
00418 
00419 int
00420 st_delete_safe(table, key, value, never)
00421     register st_table *table;
00422     register st_data_t *key;
00423     st_data_t *value;
00424     st_data_t never;
00425 {
00426     unsigned int hash_val;
00427     register st_table_entry *ptr;
00428 
00429     hash_val = do_hash_bin(*key, table);
00430     ptr = table->bins[hash_val];
00431 
00432     if (ptr == 0) {
00433         if (value != 0) *value = 0;
00434         return 0;
00435     }
00436 
00437     for(; ptr != 0; ptr = ptr->next) {
00438         if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) {
00439             table->num_entries--;
00440             *key = ptr->key;
00441             if (value != 0) *value = ptr->record;
00442             ptr->key = ptr->record = never;
00443             return 1;
00444         }
00445     }
00446 
00447     return 0;
00448 }
00449 
00450 static int
00451 delete_never(key, value, never)
00452     st_data_t key, value, never;
00453 {
00454     if (value == never) return ST_DELETE;
00455     return ST_CONTINUE;
00456 }
00457 
00458 void
00459 st_cleanup_safe(table, never)
00460     st_table *table;
00461     st_data_t never;
00462 {
00463     int num_entries = table->num_entries;
00464 
00465     st_foreach(table, delete_never, never);
00466     table->num_entries = num_entries;
00467 }
00468 
00469 int
00470 st_foreach(table, func, arg)
00471     st_table *table;
00472     int (*func)();
00473     st_data_t arg;
00474 {
00475     st_table_entry *ptr, *last, *tmp;
00476     enum st_retval retval;
00477     int i;
00478 
00479     for(i = 0; i < table->num_bins; i++) {
00480         last = 0;
00481         for(ptr = table->bins[i]; ptr != 0;) {
00482             retval = (*func)(ptr->key, ptr->record, arg);
00483             switch (retval) {
00484             case ST_CHECK:      /* check if hash is modified during iteration */
00485                 tmp = 0;
00486                 if (i < table->num_bins) {
00487                     for (tmp = table->bins[i]; tmp; tmp=tmp->next) {
00488                         if (tmp == ptr) break;
00489                     }
00490                 }
00491                 if (!tmp) {
00492                     /* call func with error notice */
00493                     return 1;
00494                 }
00495                 /* fall through */
00496             case ST_CONTINUE:
00497                 last = ptr;
00498                 ptr = ptr->next;
00499                 break;
00500             case ST_STOP:
00501                 return 0;
00502             case ST_DELETE:
00503                 tmp = ptr;
00504                 if (last == 0) {
00505                     table->bins[i] = ptr->next;
00506                 }
00507                 else {
00508                     last->next = ptr->next;
00509                 }
00510                 ptr = ptr->next;
00511                 free(tmp);
00512                 table->num_entries--;
00513             }
00514         }
00515     }
00516     return 0;
00517 }
00518 
00519 static int
00520 strhash(string)
00521     register const char *string;
00522 {
00523     register int c;
00524 
00525 #ifdef HASH_ELFHASH
00526     register unsigned int h = 0, g;
00527 
00528     while ((c = *string++) != '\0') {
00529         h = ( h << 4 ) + c;
00530         if ( g = h & 0xF0000000 )
00531             h ^= g >> 24;
00532         h &= ~g;
00533     }
00534     return h;
00535 #elif HASH_PERL
00536     register int val = 0;
00537 
00538     while ((c = *string++) != '\0') {
00539         val += c;
00540         val += (val << 10);
00541         val ^= (val >> 6);
00542     }
00543     val += (val << 3);
00544     val ^= (val >> 11);
00545 
00546     return val + (val << 15);
00547 #else
00548     register int val = 0;
00549 
00550     while ((c = *string++) != '\0') {
00551         val = val*997 + c;
00552     }
00553 
00554     return val + (val>>5);
00555 #endif
00556 }
00557 
00558 static int
00559 numcmp(x, y)
00560     long x, y;
00561 {
00562     return x != y;
00563 }
00564 
00565 static int
00566 numhash(n)
00567     long n;
00568 {
00569     return n;
00570 }
00571 

Generated on Wed Jan 18 23:32:06 2006 for Ruby by doxygen 1.3.5