メインページ | 構成 | ファイル一覧 | 構成メンバ | ファイルメンバ | 関連ページ

st.c

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

dkutil_cに対してSun Jul 18 22:45:22 2004に生成されました。 doxygen 1.3.6