00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 #include <stdio.h>
00011 #include "extra.h"
00012 #include "stmm.h"
00013 
00014 #ifndef ABS
00015 #  define ABS(a)                        ((a) < 0 ? -(a) : (a))
00016 #endif
00017 
00018 #define STMM_NUMCMP(x,y) ((x) != (y))
00019 #define STMM_NUMHASH(x,size) (ABS((long)x)%(size))
00020 
00021 #define STMM_PTRHASH(x,size) ((int)(((unsigned long)(x)>>2)%size))
00022 #define EQUAL(func, x, y) \
00023     ((((func) == stmm_numcmp) || ((func) == stmm_ptrcmp)) ?\
00024       (STMM_NUMCMP((x),(y)) == 0) : ((*func)((x), (y)) == 0))
00025 
00026 
00027 #define do_hash(key, table)\
00028     ((table->hash == stmm_ptrhash) ? STMM_PTRHASH((key),(table)->num_bins) :\
00029      (table->hash == stmm_numhash) ? STMM_NUMHASH((key), (table)->num_bins) :\
00030      (*table->hash)((key), (table)->num_bins))
00031 
00032 static int rehash ();
00033 int stmm_numhash (), stmm_ptrhash (), stmm_numcmp (), stmm_ptrcmp ();
00034 
00035 stmm_table *
00036 stmm_init_table_with_params (compare, hash, size, density, grow_factor,
00037                              reorder_flag)
00038     int (*compare) ();
00039     int (*hash) ();
00040     int size;
00041     int density;
00042     double grow_factor;
00043     int reorder_flag;
00044 {
00045     int i;
00046     stmm_table *new;
00047 
00048     new = ALLOC (stmm_table, 1);
00049     if (new == NULL) {
00050         return NULL;
00051     }
00052     new->compare = compare;
00053     new->hash = hash;
00054     new->num_entries = 0;
00055     new->max_density = density;
00056     new->grow_factor = grow_factor;
00057     new->reorder_flag = reorder_flag;
00058     if (size <= 0) {
00059         size = 1;
00060     }
00061     new->num_bins = size;
00062     new->bins = ALLOC (stmm_table_entry *, size);
00063     if (new->bins == NULL) {
00064         FREE (new);
00065         return NULL;
00066     }
00067     for (i = 0; i < size; i++) {
00068         new->bins[i] = 0;
00069     }
00070 
00071     
00072     new->pMemMan = Extra_MmFixedStart(sizeof (stmm_table_entry));
00073     return new;
00074 }
00075 
00076 stmm_table *
00077 stmm_init_table (compare, hash)
00078     int (*compare) ();
00079     int (*hash) ();
00080 {
00081     return stmm_init_table_with_params (compare, hash,
00082                                         STMM_DEFAULT_INIT_TABLE_SIZE,
00083                                         STMM_DEFAULT_MAX_DENSITY,
00084                                         STMM_DEFAULT_GROW_FACTOR,
00085                                         STMM_DEFAULT_REORDER_FLAG);
00086 }
00087 
00088 void
00089 stmm_free_table (table)
00090     stmm_table *table;
00091 {
00092 
00093 
00094 
00095 
00096 
00097 
00098 
00099 
00100 
00101 
00102 
00103 
00104 
00105 
00106     
00107     
00108     if ( table->pMemMan )
00109         Extra_MmFixedStop (table->pMemMan);
00110     FREE (table->bins);
00111     FREE (table);
00112 }
00113 
00114 
00115 void
00116 stmm_clean (table)
00117     stmm_table *table;
00118 {
00119     int i;
00120     
00121     for (i = 0; i < table->num_bins; i++)
00122             table->bins[i] = NULL;
00123     
00124     table->num_entries = 0;
00125     
00126     Extra_MmFixedRestart (table->pMemMan);
00127 }
00128 
00129 
00130 #define PTR_NOT_EQUAL(table, ptr, user_key)\
00131 (ptr != NULL && !EQUAL(table->compare, user_key, (ptr)->key))
00132 
00133 #define FIND_ENTRY(table, hash_val, key, ptr, last) \
00134     (last) = &(table)->bins[hash_val];\
00135     (ptr) = *(last);\
00136     while (PTR_NOT_EQUAL((table), (ptr), (key))) {\
00137         (last) = &(ptr)->next; (ptr) = *(last);\
00138     }\
00139     if ((ptr) != NULL && (table)->reorder_flag) {\
00140         *(last) = (ptr)->next;\
00141         (ptr)->next = (table)->bins[hash_val];\
00142         (table)->bins[hash_val] = (ptr);\
00143     }
00144 
00145 int
00146 stmm_lookup (table, key, value)
00147     stmm_table *table;
00148     register char *key;
00149     char **value;
00150 {
00151     int hash_val;
00152     register stmm_table_entry *ptr, **last;
00153 
00154     hash_val = do_hash (key, table);
00155 
00156     FIND_ENTRY (table, hash_val, key, ptr, last);
00157 
00158     if (ptr == NULL) {
00159         return 0;
00160     }
00161     else {
00162         if (value != NULL)
00163         {
00164             *value = ptr->record;
00165         }
00166         return 1;
00167     }
00168 }
00169 
00170 int
00171 stmm_lookup_int (table, key, value)
00172     stmm_table *table;
00173     register char *key;
00174     int *value;
00175 {
00176     int hash_val;
00177     register stmm_table_entry *ptr, **last;
00178 
00179     hash_val = do_hash (key, table);
00180 
00181     FIND_ENTRY (table, hash_val, key, ptr, last);
00182 
00183     if (ptr == NULL) {
00184         return 0;
00185     }
00186     else {
00187         if (value != 0)
00188         {
00189             *value = (long) ptr->record;
00190         }
00191         return 1;
00192     }
00193 }
00194 
00195 
00196 
00197 
00198 
00199 
00200 
00201 #define ADD_DIRECT(table, key, value, hash_val, new)\
00202 {\
00203     if (table->num_entries/table->num_bins >= table->max_density) {\
00204         rehash(table);\
00205         hash_val = do_hash(key,table);\
00206     }\
00207     \
00208     new = (stmm_table_entry *)Extra_MmFixedEntryFetch( table->pMemMan );\
00209     \
00210     new->key = key;\
00211     new->record = value;\
00212     new->next = table->bins[hash_val];\
00213     table->bins[hash_val] = new;\
00214     table->num_entries++;\
00215 }
00216 
00217 int
00218 stmm_insert (table, key, value)
00219     register stmm_table *table;
00220     register char *key;
00221     char *value;
00222 {
00223     int hash_val;
00224     stmm_table_entry *new;
00225     register stmm_table_entry *ptr, **last;
00226 
00227     hash_val = do_hash (key, table);
00228 
00229     FIND_ENTRY (table, hash_val, key, ptr, last);
00230 
00231     if (ptr == NULL) {
00232         if (table->num_entries / table->num_bins >= table->max_density) {
00233             if (rehash (table) == STMM_OUT_OF_MEM) {
00234                 return STMM_OUT_OF_MEM;
00235             }
00236             hash_val = do_hash (key, table);
00237         }
00238 
00239 
00240         new = (stmm_table_entry *) Extra_MmFixedEntryFetch (table->pMemMan);
00241         if (new == NULL) {
00242             return STMM_OUT_OF_MEM;
00243         }
00244 
00245         new->key = key;
00246         new->record = value;
00247         new->next = table->bins[hash_val];
00248         table->bins[hash_val] = new;
00249         table->num_entries++;
00250         return 0;
00251     }
00252     else {
00253         ptr->record = value;
00254         return 1;
00255     }
00256 }
00257 
00258 int
00259 stmm_add_direct (table, key, value)
00260     stmm_table *table;
00261     char *key;
00262     char *value;
00263 {
00264     int hash_val;
00265     stmm_table_entry *new;
00266 
00267     hash_val = do_hash (key, table);
00268     if (table->num_entries / table->num_bins >= table->max_density) {
00269         if (rehash (table) == STMM_OUT_OF_MEM) {
00270             return STMM_OUT_OF_MEM;
00271         }
00272     }
00273     hash_val = do_hash (key, table);
00274 
00275 
00276     new = (stmm_table_entry *) Extra_MmFixedEntryFetch (table->pMemMan);
00277     if (new == NULL) {
00278         return STMM_OUT_OF_MEM;
00279     }
00280 
00281     new->key = key;
00282     new->record = value;
00283     new->next = table->bins[hash_val];
00284     table->bins[hash_val] = new;
00285     table->num_entries++;
00286     return 1;
00287 }
00288 
00289 int
00290 stmm_find_or_add (table, key, slot)
00291     stmm_table *table;
00292     char *key;
00293     char ***slot;
00294 {
00295     int hash_val;
00296     stmm_table_entry *new, *ptr, **last;
00297 
00298     hash_val = do_hash (key, table);
00299 
00300     FIND_ENTRY (table, hash_val, key, ptr, last);
00301 
00302     if (ptr == NULL) {
00303         if (table->num_entries / table->num_bins >= table->max_density) {
00304             if (rehash (table) == STMM_OUT_OF_MEM) {
00305                 return STMM_OUT_OF_MEM;
00306             }
00307             hash_val = do_hash (key, table);
00308         }
00309 
00310         
00311         new = (stmm_table_entry *) Extra_MmFixedEntryFetch (table->pMemMan);
00312         if (new == NULL) {
00313             return STMM_OUT_OF_MEM;
00314         }
00315 
00316         new->key = key;
00317         new->record = (char *) 0;
00318         new->next = table->bins[hash_val];
00319         table->bins[hash_val] = new;
00320         table->num_entries++;
00321         if (slot != NULL)
00322              *slot = &new->record;
00323         return 0;
00324     }
00325     else {
00326         if (slot != NULL)
00327              *slot = &ptr->record;
00328         return 1;
00329     }
00330 }
00331 
00332 int
00333 stmm_find (table, key, slot)
00334     stmm_table *table;
00335     char *key;
00336     char ***slot;
00337 {
00338     int hash_val;
00339     stmm_table_entry *ptr, **last;
00340 
00341     hash_val = do_hash (key, table);
00342 
00343     FIND_ENTRY (table, hash_val, key, ptr, last);
00344 
00345     if (ptr == NULL) {
00346         return 0;
00347     }
00348     else {
00349         if (slot != NULL)
00350         {
00351             *slot = &ptr->record;
00352         }
00353         return 1;
00354     }
00355 }
00356 
00357 static int
00358 rehash (table)
00359     register stmm_table *table;
00360 {
00361     register stmm_table_entry *ptr, *next, **old_bins;
00362     int i, old_num_bins, hash_val, old_num_entries;
00363 
00364     
00365     old_bins = table->bins;
00366     old_num_bins = table->num_bins;
00367     old_num_entries = table->num_entries;
00368 
00369     
00370     table->num_bins = (int) (table->grow_factor * old_num_bins);
00371     if (table->num_bins % 2 == 0) {
00372         table->num_bins += 1;
00373     }
00374     table->num_entries = 0;
00375     table->bins = ALLOC (stmm_table_entry *, table->num_bins);
00376     if (table->bins == NULL) {
00377         table->bins = old_bins;
00378         table->num_bins = old_num_bins;
00379         table->num_entries = old_num_entries;
00380         return STMM_OUT_OF_MEM;
00381     }
00382     
00383     for (i = 0; i < table->num_bins; i++) {
00384         table->bins[i] = 0;
00385     }
00386 
00387     
00388     for (i = 0; i < old_num_bins; i++) {
00389         ptr = old_bins[i];
00390         while (ptr != NULL) {
00391             next = ptr->next;
00392             hash_val = do_hash (ptr->key, table);
00393             ptr->next = table->bins[hash_val];
00394             table->bins[hash_val] = ptr;
00395             table->num_entries++;
00396             ptr = next;
00397         }
00398     }
00399     FREE (old_bins);
00400 
00401     return 1;
00402 }
00403 
00404 stmm_table *
00405 stmm_copy (old_table)
00406     stmm_table *old_table;
00407 {
00408     stmm_table *new_table;
00409     stmm_table_entry *ptr,  *new;
00410     int i,  num_bins = old_table->num_bins;
00411 
00412     new_table = ALLOC (stmm_table, 1);
00413     if (new_table == NULL) {
00414         return NULL;
00415     }
00416 
00417     *new_table = *old_table;
00418     new_table->bins = ALLOC (stmm_table_entry *, num_bins);
00419     if (new_table->bins == NULL) {
00420         FREE (new_table);
00421         return NULL;
00422     }
00423 
00424     
00425     new_table->pMemMan =
00426         Extra_MmFixedStart (sizeof (stmm_table_entry));
00427 
00428     for (i = 0; i < num_bins; i++) {
00429         new_table->bins[i] = NULL;
00430         ptr = old_table->bins[i];
00431         while (ptr != NULL) {
00432 
00433             new =
00434                 (stmm_table_entry *) Extra_MmFixedEntryFetch (new_table->
00435                                                             pMemMan);
00436 
00437             if (new == NULL) {
00438 
00439 
00440 
00441 
00442 
00443 
00444 
00445 
00446 
00447 
00448 
00449 
00450                 Extra_MmFixedStop (new_table->pMemMan);
00451 
00452                 FREE (new_table->bins);
00453                 FREE (new_table);
00454                 return NULL;
00455             }
00456             *new = *ptr;
00457             new->next = new_table->bins[i];
00458             new_table->bins[i] = new;
00459             ptr = ptr->next;
00460         }
00461     }
00462     return new_table;
00463 }
00464 
00465 int
00466 stmm_delete (table, keyp, value)
00467     register stmm_table *table;
00468     register char **keyp;
00469     char **value;
00470 {
00471     int hash_val;
00472     char *key = *keyp;
00473     register stmm_table_entry *ptr, **last;
00474 
00475     hash_val = do_hash (key, table);
00476 
00477     FIND_ENTRY (table, hash_val, key, ptr, last);
00478 
00479     if (ptr == NULL) {
00480         return 0;
00481     }
00482 
00483     *last = ptr->next;
00484     if (value != NULL)
00485          *value = ptr->record;
00486     *keyp = ptr->key;
00487 
00488     Extra_MmFixedEntryRecycle (table->pMemMan, (char *) ptr);
00489 
00490     table->num_entries--;
00491     return 1;
00492 }
00493 
00494 int
00495 stmm_delete_int (table, keyp, value)
00496     register stmm_table *table;
00497     register long *keyp;
00498     char **value;
00499 {
00500     int hash_val;
00501     char *key = (char *) *keyp;
00502     register stmm_table_entry *ptr, **last;
00503 
00504     hash_val = do_hash (key, table);
00505 
00506     FIND_ENTRY (table, hash_val, key, ptr, last);
00507 
00508     if (ptr == NULL) {
00509         return 0;
00510     }
00511 
00512     *last = ptr->next;
00513     if (value != NULL)
00514          *value = ptr->record;
00515     *keyp = (long) ptr->key;
00516 
00517     Extra_MmFixedEntryRecycle (table->pMemMan, (char *) ptr);
00518 
00519     table->num_entries--;
00520     return 1;
00521 }
00522 
00523 int
00524 stmm_foreach (table, func, arg)
00525     stmm_table *table;
00526     enum stmm_retval (*func) ();
00527     char *arg;
00528 {
00529     stmm_table_entry *ptr, **last;
00530     enum stmm_retval retval;
00531     int i;
00532 
00533     for (i = 0; i < table->num_bins; i++) {
00534         last = &table->bins[i];
00535         ptr = *last;
00536         while (ptr != NULL) {
00537             retval = (*func) (ptr->key, ptr->record, arg);
00538             switch (retval) {
00539             case STMM_CONTINUE:
00540                 last = &ptr->next;
00541                 ptr = *last;
00542                 break;
00543             case STMM_STOP:
00544                 return 0;
00545             case STMM_DELETE:
00546                 *last = ptr->next;
00547                 table->num_entries--;   
00548 
00549                 Extra_MmFixedEntryRecycle (table->pMemMan, (char *) ptr);
00550 
00551                 ptr = *last;
00552             }
00553         }
00554     }
00555     return 1;
00556 }
00557 
00558 int
00559 stmm_strhash (string, modulus)
00560     register char *string;
00561     int modulus;
00562 {
00563     register int val = 0;
00564     register int c;
00565 
00566     while ((c = *string++) != '\0') {
00567         val = val * 997 + c;
00568     }
00569 
00570     return ((val < 0) ? -val : val) % modulus;
00571 }
00572 
00573 int
00574 stmm_numhash (x, size)
00575     char *x;
00576     int size;
00577 {
00578     return STMM_NUMHASH (x, size);
00579 }
00580 
00581 int
00582 stmm_ptrhash (x, size)
00583     char *x;
00584     int size;
00585 {
00586     return STMM_PTRHASH (x, size);
00587 }
00588 
00589 int
00590 stmm_numcmp (x, y)
00591     char *x;
00592     char *y;
00593 {
00594     return STMM_NUMCMP (x, y);
00595 }
00596 
00597 int
00598 stmm_ptrcmp (x, y)
00599     char *x;
00600     char *y;
00601 {
00602     return STMM_NUMCMP (x, y);
00603 }
00604 
00605 stmm_generator *
00606 stmm_init_gen (table)
00607     stmm_table *table;
00608 {
00609     stmm_generator *gen;
00610 
00611     gen = ALLOC (stmm_generator, 1);
00612     if (gen == NULL) {
00613         return NULL;
00614     }
00615     gen->table = table;
00616     gen->entry = NULL;
00617     gen->index = 0;
00618     return gen;
00619 }
00620 
00621 
00622 int
00623 stmm_gen (gen, key_p, value_p)
00624     stmm_generator *gen;
00625     char **key_p;
00626     char **value_p;
00627 {
00628     register int i;
00629 
00630     if (gen->entry == NULL) {
00631         
00632         for (i = gen->index; i < gen->table->num_bins; i++) {
00633             if (gen->table->bins[i] != NULL) {
00634                 gen->index = i + 1;
00635                 gen->entry = gen->table->bins[i];
00636                 break;
00637             }
00638         }
00639         if (gen->entry == NULL) {
00640             return 0;           
00641         }
00642     }
00643     *key_p = gen->entry->key;
00644     if (value_p != 0) {
00645         *value_p = gen->entry->record;
00646     }
00647     gen->entry = gen->entry->next;
00648     return 1;
00649 }
00650 
00651 
00652 int
00653 stmm_gen_int (gen, key_p, value_p)
00654     stmm_generator *gen;
00655     char **key_p;
00656     long *value_p;
00657 {
00658     register int i;
00659 
00660     if (gen->entry == NULL) {
00661         
00662         for (i = gen->index; i < gen->table->num_bins; i++) {
00663             if (gen->table->bins[i] != NULL) {
00664                 gen->index = i + 1;
00665                 gen->entry = gen->table->bins[i];
00666                 break;
00667             }
00668         }
00669         if (gen->entry == NULL) {
00670             return 0;           
00671         }
00672     }
00673     *key_p = gen->entry->key;
00674     if (value_p != 0)
00675     {
00676         *value_p = (long) gen->entry->record;
00677     }
00678     gen->entry = gen->entry->next;
00679     return 1;
00680 }
00681 
00682 
00683 void
00684 stmm_free_gen (gen)
00685     stmm_generator *gen;
00686 {
00687     FREE (gen);
00688 }