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