00001
00002
00003
00004
00005 #ifdef NOT_RUBY
00006 #include "regint.h"
00007 #include "st.h"
00008 #else
00009 #include "ruby/ruby.h"
00010 #endif
00011
00012 #include <stdio.h>
00013 #ifdef HAVE_STDLIB_H
00014 #include <stdlib.h>
00015 #endif
00016 #include <string.h>
00017
00018 typedef struct st_table_entry st_table_entry;
00019
00020 struct st_table_entry {
00021 st_index_t hash;
00022 st_data_t key;
00023 st_data_t record;
00024 st_table_entry *next;
00025 st_table_entry *fore, *back;
00026 };
00027
00028 #define ST_DEFAULT_MAX_DENSITY 5
00029 #define ST_DEFAULT_INIT_TABLE_SIZE 11
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 static const struct st_hash_type type_numhash = {
00042 st_numcmp,
00043 st_numhash,
00044 };
00045
00046
00047 static st_index_t strhash(st_data_t);
00048 static const struct st_hash_type type_strhash = {
00049 strcmp,
00050 strhash,
00051 };
00052
00053 static st_index_t strcasehash(st_data_t);
00054 static const struct st_hash_type type_strcasehash = {
00055 st_strcasecmp,
00056 strcasehash,
00057 };
00058
00059 static void rehash(st_table *);
00060
00061 #ifdef RUBY
00062 #define malloc xmalloc
00063 #define calloc xcalloc
00064 #define free(x) xfree(x)
00065 #endif
00066
00067 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
00068
00069 #define alloc(type) (type*)malloc((size_t)sizeof(type))
00070 #define Calloc(n,s) (char*)calloc((n),(s))
00071
00072 #define EQUAL(table,x,y) ((x)==(y) || (*(table)->type->compare)((x),(y)) == 0)
00073
00074
00075 #define do_hash(key,table) (unsigned int)(st_index_t)(*(table)->type->hash)((key))
00076 #define do_hash_bin(key,table) (do_hash((key), (table))%(table)->num_bins)
00077
00078
00079
00080
00081
00082 #define MINSIZE 8
00083
00084
00085
00086
00087 static const unsigned int primes[] = {
00088 8 + 3,
00089 16 + 3,
00090 32 + 5,
00091 64 + 3,
00092 128 + 3,
00093 256 + 27,
00094 512 + 9,
00095 1024 + 9,
00096 2048 + 5,
00097 4096 + 3,
00098 8192 + 27,
00099 16384 + 43,
00100 32768 + 3,
00101 65536 + 45,
00102 131072 + 29,
00103 262144 + 3,
00104 524288 + 21,
00105 1048576 + 7,
00106 2097152 + 17,
00107 4194304 + 15,
00108 8388608 + 9,
00109 16777216 + 43,
00110 33554432 + 35,
00111 67108864 + 15,
00112 134217728 + 29,
00113 268435456 + 3,
00114 536870912 + 11,
00115 1073741824 + 85,
00116 0
00117 };
00118
00119 static st_index_t
00120 new_size(st_index_t 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 st_index_t newsize;
00131
00132 for (i = 0, newsize = MINSIZE; i < numberof(primes); i++, newsize <<= 1) {
00133 if (newsize > size) return primes[i];
00134 }
00135
00136 #ifndef NOT_RUBY
00137 rb_raise(rb_eRuntimeError, "st_table too big");
00138 #endif
00139 return -1;
00140 #endif
00141 }
00142
00143 #ifdef HASH_LOG
00144 #ifdef HAVE_UNISTD_H
00145 #include <unistd.h>
00146 #endif
00147 static struct {
00148 int all, total, num, str, strcase;
00149 } collision;
00150 static int init_st = 0;
00151
00152 static void
00153 stat_col(void)
00154 {
00155 char fname[10+sizeof(long)*3];
00156 FILE *f = fopen((snprintf(fname, sizeof(fname), "/tmp/col%ld", (long)getpid()), fname), "w");
00157 fprintf(f, "collision: %d / %d (%6.2f)\n", collision.all, collision.total,
00158 ((double)collision.all / (collision.total)) * 100);
00159 fprintf(f, "num: %d, str: %d, strcase: %d\n", collision.num, collision.str, collision.strcase);
00160 fclose(f);
00161 }
00162 #endif
00163
00164 #define MAX_PACKED_NUMHASH (ST_DEFAULT_INIT_TABLE_SIZE/2)
00165
00166 st_table*
00167 st_init_table_with_size(const struct st_hash_type *type, st_index_t size)
00168 {
00169 st_table *tbl;
00170
00171 #ifdef HASH_LOG
00172 # if HASH_LOG+0 < 0
00173 {
00174 const char *e = getenv("ST_HASH_LOG");
00175 if (!e || !*e) init_st = 1;
00176 }
00177 # endif
00178 if (init_st == 0) {
00179 init_st = 1;
00180 atexit(stat_col);
00181 }
00182 #endif
00183
00184 size = new_size(size);
00185
00186 tbl = alloc(st_table);
00187 tbl->type = type;
00188 tbl->num_entries = 0;
00189 tbl->entries_packed = type == &type_numhash && size/2 <= MAX_PACKED_NUMHASH;
00190 tbl->num_bins = size;
00191 tbl->bins = (st_table_entry **)Calloc(size, sizeof(st_table_entry*));
00192 tbl->head = 0;
00193 tbl->tail = 0;
00194
00195 return tbl;
00196 }
00197
00198 st_table*
00199 st_init_table(const struct st_hash_type *type)
00200 {
00201 return st_init_table_with_size(type, 0);
00202 }
00203
00204 st_table*
00205 st_init_numtable(void)
00206 {
00207 return st_init_table(&type_numhash);
00208 }
00209
00210 st_table*
00211 st_init_numtable_with_size(st_index_t size)
00212 {
00213 return st_init_table_with_size(&type_numhash, size);
00214 }
00215
00216 st_table*
00217 st_init_strtable(void)
00218 {
00219 return st_init_table(&type_strhash);
00220 }
00221
00222 st_table*
00223 st_init_strtable_with_size(st_index_t size)
00224 {
00225 return st_init_table_with_size(&type_strhash, size);
00226 }
00227
00228 st_table*
00229 st_init_strcasetable(void)
00230 {
00231 return st_init_table(&type_strcasehash);
00232 }
00233
00234 st_table*
00235 st_init_strcasetable_with_size(st_index_t size)
00236 {
00237 return st_init_table_with_size(&type_strcasehash, size);
00238 }
00239
00240 void
00241 st_clear(st_table *table)
00242 {
00243 register st_table_entry *ptr, *next;
00244 st_index_t i;
00245
00246 if (table->entries_packed) {
00247 table->num_entries = 0;
00248 return;
00249 }
00250
00251 for(i = 0; i < table->num_bins; i++) {
00252 ptr = table->bins[i];
00253 table->bins[i] = 0;
00254 while (ptr != 0) {
00255 next = ptr->next;
00256 free(ptr);
00257 ptr = next;
00258 }
00259 }
00260 table->num_entries = 0;
00261 table->head = 0;
00262 table->tail = 0;
00263 }
00264
00265 void
00266 st_free_table(st_table *table)
00267 {
00268 st_clear(table);
00269 free(table->bins);
00270 free(table);
00271 }
00272
00273 size_t
00274 st_memsize(const st_table *table)
00275 {
00276 if (table->entries_packed) {
00277 return table->num_bins * sizeof (void *) + sizeof(st_table);
00278 }
00279 else {
00280 return table->num_entries * sizeof(struct st_table_entry) + table->num_bins * sizeof (void *) + sizeof(st_table);
00281 }
00282 }
00283
00284 #define PTR_NOT_EQUAL(table, ptr, hash_val, key) \
00285 ((ptr) != 0 && ((ptr)->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key)))
00286
00287 #ifdef HASH_LOG
00288 static void
00289 count_collision(const struct st_hash_type *type)
00290 {
00291 collision.all++;
00292 if (type == &type_numhash) {
00293 collision.num++;
00294 }
00295 else if (type == &type_strhash) {
00296 collision.strcase++;
00297 }
00298 else if (type == &type_strcasehash) {
00299 collision.str++;
00300 }
00301 }
00302 #define COLLISION (collision_check ? count_collision(table->type) : (void)0)
00303 #define FOUND_ENTRY (collision_check ? collision.total++ : (void)0)
00304 #else
00305 #define COLLISION
00306 #define FOUND_ENTRY
00307 #endif
00308
00309 #define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\
00310 (bin_pos) = (hash_val)%(table)->num_bins;\
00311 (ptr) = (table)->bins[(bin_pos)];\
00312 FOUND_ENTRY;\
00313 if (PTR_NOT_EQUAL((table), (ptr), (hash_val), key)) {\
00314 COLLISION;\
00315 while (PTR_NOT_EQUAL((table), (ptr)->next, (hash_val), key)) {\
00316 (ptr) = (ptr)->next;\
00317 }\
00318 (ptr) = (ptr)->next;\
00319 }\
00320 } while (0)
00321
00322 #define collision_check 0
00323
00324 int
00325 st_lookup(st_table *table, register st_data_t key, st_data_t *value)
00326 {
00327 st_index_t hash_val, bin_pos;
00328 register st_table_entry *ptr;
00329
00330 if (table->entries_packed) {
00331 st_index_t i;
00332 for (i = 0; i < table->num_entries; i++) {
00333 if ((st_data_t)table->bins[i*2] == key) {
00334 if (value !=0) *value = (st_data_t)table->bins[i*2+1];
00335 return 1;
00336 }
00337 }
00338 return 0;
00339 }
00340
00341 hash_val = do_hash(key, table);
00342 FIND_ENTRY(table, ptr, hash_val, bin_pos);
00343
00344 if (ptr == 0) {
00345 return 0;
00346 }
00347 else {
00348 if (value != 0) *value = ptr->record;
00349 return 1;
00350 }
00351 }
00352
00353 int
00354 st_get_key(st_table *table, register st_data_t key, st_data_t *result)
00355 {
00356 st_index_t hash_val, bin_pos;
00357 register st_table_entry *ptr;
00358
00359 if (table->entries_packed) {
00360 st_index_t i;
00361 for (i = 0; i < table->num_entries; i++) {
00362 if ((st_data_t)table->bins[i*2] == key) {
00363 if (result !=0) *result = (st_data_t)table->bins[i*2];
00364 return 1;
00365 }
00366 }
00367 return 0;
00368 }
00369
00370 hash_val = do_hash(key, table);
00371 FIND_ENTRY(table, ptr, hash_val, bin_pos);
00372
00373 if (ptr == 0) {
00374 return 0;
00375 }
00376 else {
00377 if (result != 0) *result = ptr->key;
00378 return 1;
00379 }
00380 }
00381
00382 #undef collision_check
00383 #define collision_check 1
00384
00385 #define MORE_PACKABLE_P(table) \
00386 ((st_index_t)((table)->num_entries+1) * 2 <= (table)->num_bins && \
00387 (table)->num_entries+1 <= MAX_PACKED_NUMHASH)
00388
00389 #define ADD_DIRECT(table, key, value, hash_val, bin_pos)\
00390 do {\
00391 st_table_entry *entry;\
00392 if ((table)->num_entries > ST_DEFAULT_MAX_DENSITY * (table)->num_bins) {\
00393 rehash(table);\
00394 (bin_pos) = (hash_val) % (table)->num_bins;\
00395 }\
00396 \
00397 entry = alloc(st_table_entry);\
00398 \
00399 entry->hash = (hash_val);\
00400 entry->key = (key);\
00401 entry->record = (value);\
00402 entry->next = (table)->bins[(bin_pos)];\
00403 if ((table)->head != 0) {\
00404 entry->fore = 0;\
00405 (entry->back = (table)->tail)->fore = entry;\
00406 (table)->tail = entry;\
00407 }\
00408 else {\
00409 (table)->head = (table)->tail = entry;\
00410 entry->fore = entry->back = 0;\
00411 }\
00412 (table)->bins[(bin_pos)] = entry;\
00413 (table)->num_entries++;\
00414 } while (0)
00415
00416 static void
00417 unpack_entries(register st_table *table)
00418 {
00419 st_index_t i;
00420 struct st_table_entry *packed_bins[MAX_PACKED_NUMHASH*2];
00421 st_table tmp_table = *table;
00422
00423 memcpy(packed_bins, table->bins, sizeof(struct st_table_entry *) * table->num_entries*2);
00424 table->bins = packed_bins;
00425 tmp_table.entries_packed = 0;
00426 tmp_table.num_entries = 0;
00427 memset(tmp_table.bins, 0, sizeof(struct st_table_entry *) * tmp_table.num_bins);
00428 for (i = 0; i < table->num_entries; i++) {
00429 st_insert(&tmp_table, (st_data_t)packed_bins[i*2], (st_data_t)packed_bins[i*2+1]);
00430 }
00431 *table = tmp_table;
00432 }
00433
00434 int
00435 st_insert(register st_table *table, register st_data_t key, st_data_t value)
00436 {
00437 st_index_t hash_val, bin_pos;
00438 register st_table_entry *ptr;
00439
00440 if (table->entries_packed) {
00441 st_index_t i;
00442 for (i = 0; i < table->num_entries; i++) {
00443 if ((st_data_t)table->bins[i*2] == key) {
00444 table->bins[i*2+1] = (struct st_table_entry*)value;
00445 return 1;
00446 }
00447 }
00448 if (MORE_PACKABLE_P(table)) {
00449 i = table->num_entries++;
00450 table->bins[i*2] = (struct st_table_entry*)key;
00451 table->bins[i*2+1] = (struct st_table_entry*)value;
00452 return 0;
00453 }
00454 else {
00455 unpack_entries(table);
00456 }
00457 }
00458
00459 hash_val = do_hash(key, table);
00460 FIND_ENTRY(table, ptr, hash_val, bin_pos);
00461
00462 if (ptr == 0) {
00463 ADD_DIRECT(table, key, value, hash_val, bin_pos);
00464 return 0;
00465 }
00466 else {
00467 ptr->record = value;
00468 return 1;
00469 }
00470 }
00471
00472 int
00473 st_insert2(register st_table *table, register st_data_t key, st_data_t value,
00474 st_data_t (*func)(st_data_t))
00475 {
00476 st_index_t hash_val, bin_pos;
00477 register st_table_entry *ptr;
00478
00479 if (table->entries_packed) {
00480 st_index_t i;
00481 for (i = 0; i < table->num_entries; i++) {
00482 if ((st_data_t)table->bins[i*2] == key) {
00483 table->bins[i*2+1] = (struct st_table_entry*)value;
00484 return 1;
00485 }
00486 }
00487 if (MORE_PACKABLE_P(table)) {
00488 i = table->num_entries++;
00489 table->bins[i*2] = (struct st_table_entry*)key;
00490 table->bins[i*2+1] = (struct st_table_entry*)value;
00491 return 0;
00492 }
00493 else {
00494 unpack_entries(table);
00495 }
00496 }
00497
00498 hash_val = do_hash(key, table);
00499 FIND_ENTRY(table, ptr, hash_val, bin_pos);
00500
00501 if (ptr == 0) {
00502 key = (*func)(key);
00503 ADD_DIRECT(table, key, value, hash_val, bin_pos);
00504 return 0;
00505 }
00506 else {
00507 ptr->record = value;
00508 return 1;
00509 }
00510 }
00511
00512 void
00513 st_add_direct(st_table *table, st_data_t key, st_data_t value)
00514 {
00515 st_index_t hash_val, bin_pos;
00516
00517 if (table->entries_packed) {
00518 st_index_t i;
00519 if (MORE_PACKABLE_P(table)) {
00520 i = table->num_entries++;
00521 table->bins[i*2] = (struct st_table_entry*)key;
00522 table->bins[i*2+1] = (struct st_table_entry*)value;
00523 return;
00524 }
00525 else {
00526 unpack_entries(table);
00527 }
00528 }
00529
00530 hash_val = do_hash(key, table);
00531 bin_pos = hash_val % table->num_bins;
00532 ADD_DIRECT(table, key, value, hash_val, bin_pos);
00533 }
00534
00535 static void
00536 rehash(register st_table *table)
00537 {
00538 register st_table_entry *ptr, **new_bins;
00539 st_index_t i, new_num_bins, hash_val;
00540
00541 new_num_bins = new_size(table->num_bins+1);
00542 new_bins = (st_table_entry**)
00543 xrealloc(table->bins, new_num_bins * sizeof(st_table_entry*));
00544 for (i = 0; i < new_num_bins; ++i) new_bins[i] = 0;
00545 table->num_bins = new_num_bins;
00546 table->bins = new_bins;
00547
00548 if ((ptr = table->head) != 0) {
00549 do {
00550 hash_val = ptr->hash % new_num_bins;
00551 ptr->next = new_bins[hash_val];
00552 new_bins[hash_val] = ptr;
00553 } while ((ptr = ptr->fore) != 0);
00554 }
00555 }
00556
00557 st_table*
00558 st_copy(st_table *old_table)
00559 {
00560 st_table *new_table;
00561 st_table_entry *ptr, *entry, *prev, **tail;
00562 st_index_t num_bins = old_table->num_bins;
00563 st_index_t hash_val;
00564
00565 new_table = alloc(st_table);
00566 if (new_table == 0) {
00567 return 0;
00568 }
00569
00570 *new_table = *old_table;
00571 new_table->bins = (st_table_entry**)
00572 Calloc((unsigned)num_bins, sizeof(st_table_entry*));
00573
00574 if (new_table->bins == 0) {
00575 free(new_table);
00576 return 0;
00577 }
00578
00579 if (old_table->entries_packed) {
00580 memcpy(new_table->bins, old_table->bins, sizeof(struct st_table_entry *) * old_table->num_bins);
00581 return new_table;
00582 }
00583
00584 if ((ptr = old_table->head) != 0) {
00585 prev = 0;
00586 tail = &new_table->head;
00587 do {
00588 entry = alloc(st_table_entry);
00589 if (entry == 0) {
00590 st_free_table(new_table);
00591 return 0;
00592 }
00593 *entry = *ptr;
00594 hash_val = entry->hash % num_bins;
00595 entry->next = new_table->bins[hash_val];
00596 new_table->bins[hash_val] = entry;
00597 entry->back = prev;
00598 *tail = prev = entry;
00599 tail = &entry->fore;
00600 } while ((ptr = ptr->fore) != 0);
00601 new_table->tail = prev;
00602 }
00603
00604 return new_table;
00605 }
00606
00607 #define REMOVE_ENTRY(table, ptr) do \
00608 { \
00609 if ((ptr)->fore == 0 && (ptr)->back == 0) { \
00610 (table)->head = 0; \
00611 (table)->tail = 0; \
00612 } \
00613 else { \
00614 st_table_entry *fore = (ptr)->fore, *back = (ptr)->back; \
00615 if (fore) fore->back = back; \
00616 if (back) back->fore = fore; \
00617 if ((ptr) == (table)->head) (table)->head = fore; \
00618 if ((ptr) == (table)->tail) (table)->tail = back; \
00619 } \
00620 (table)->num_entries--; \
00621 } while (0)
00622
00623 int
00624 st_delete(register st_table *table, register st_data_t *key, st_data_t *value)
00625 {
00626 st_index_t hash_val;
00627 st_table_entry **prev;
00628 register st_table_entry *ptr;
00629
00630 if (table->entries_packed) {
00631 st_index_t i;
00632 for (i = 0; i < table->num_entries; i++) {
00633 if ((st_data_t)table->bins[i*2] == *key) {
00634 if (value != 0) *value = (st_data_t)table->bins[i*2+1];
00635 table->num_entries--;
00636 memmove(&table->bins[i*2], &table->bins[(i+1)*2],
00637 sizeof(struct st_table_entry*) * 2*(table->num_entries-i));
00638 return 1;
00639 }
00640 }
00641 if (value != 0) *value = 0;
00642 return 0;
00643 }
00644
00645 hash_val = do_hash_bin(*key, table);
00646
00647 for (prev = &table->bins[hash_val]; (ptr = *prev) != 0; prev = &ptr->next) {
00648 if (EQUAL(table, *key, ptr->key)) {
00649 *prev = ptr->next;
00650 REMOVE_ENTRY(table, ptr);
00651 if (value != 0) *value = ptr->record;
00652 *key = ptr->key;
00653 free(ptr);
00654 return 1;
00655 }
00656 }
00657
00658 if (value != 0) *value = 0;
00659 return 0;
00660 }
00661
00662 int
00663 st_delete_safe(register st_table *table, register st_data_t *key, st_data_t *value, st_data_t never)
00664 {
00665 st_index_t hash_val;
00666 register st_table_entry *ptr;
00667
00668 if (table->entries_packed) {
00669 st_index_t i;
00670 for (i = 0; i < table->num_entries; i++) {
00671 if ((st_data_t)table->bins[i*2] == *key) {
00672 if (value != 0) *value = (st_data_t)table->bins[i*2+1];
00673 table->bins[i*2] = (void *)never;
00674 return 1;
00675 }
00676 }
00677 if (value != 0) *value = 0;
00678 return 0;
00679 }
00680
00681 hash_val = do_hash_bin(*key, table);
00682 ptr = table->bins[hash_val];
00683
00684 for (; ptr != 0; ptr = ptr->next) {
00685 if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) {
00686 REMOVE_ENTRY(table, ptr);
00687 *key = ptr->key;
00688 if (value != 0) *value = ptr->record;
00689 ptr->key = ptr->record = never;
00690 return 1;
00691 }
00692 }
00693
00694 if (value != 0) *value = 0;
00695 return 0;
00696 }
00697
00698 int
00699 st_shift(register st_table *table, register st_data_t *key, st_data_t *value)
00700 {
00701 st_index_t hash_val;
00702 st_table_entry **prev;
00703 register st_table_entry *ptr;
00704
00705 if (table->num_entries == 0) {
00706 if (value != 0) *value = 0;
00707 return 0;
00708 }
00709
00710 if (table->entries_packed) {
00711 if (value != 0) *value = (st_data_t)table->bins[1];
00712 *key = (st_data_t)table->bins[0];
00713 table->num_entries--;
00714 memmove(&table->bins[0], &table->bins[2],
00715 sizeof(struct st_table_entry*) * 2*table->num_entries);
00716 return 1;
00717 }
00718
00719 hash_val = do_hash_bin(table->head->key, table);
00720 prev = &table->bins[hash_val];
00721 for (;(ptr = *prev) != 0; prev = &ptr->next) {
00722 if (ptr == table->head) {
00723 *prev = ptr->next;
00724 REMOVE_ENTRY(table, ptr);
00725 if (value != 0) *value = ptr->record;
00726 *key = ptr->key;
00727 free(ptr);
00728 return 1;
00729 }
00730 }
00731
00732
00733 if (value != 0) *value = 0;
00734 return 0;
00735 }
00736
00737 void
00738 st_cleanup_safe(st_table *table, st_data_t never)
00739 {
00740 st_table_entry *ptr, **last, *tmp;
00741 st_index_t i;
00742
00743 if (table->entries_packed) {
00744 st_index_t i = 0, j = 0;
00745 while ((st_data_t)table->bins[i*2] != never) {
00746 if (i++ == table->num_entries) return;
00747 }
00748 for (j = i; ++i < table->num_entries;) {
00749 if ((st_data_t)table->bins[i*2] == never) continue;
00750 table->bins[j*2] = table->bins[i*2];
00751 table->bins[j*2+1] = table->bins[i*2+1];
00752 j++;
00753 }
00754 table->num_entries = j;
00755 return;
00756 }
00757
00758 for (i = 0; i < table->num_bins; i++) {
00759 ptr = *(last = &table->bins[i]);
00760 while (ptr != 0) {
00761 if (ptr->key == never) {
00762 tmp = ptr;
00763 *last = ptr = ptr->next;
00764 free(tmp);
00765 }
00766 else {
00767 ptr = *(last = &ptr->next);
00768 }
00769 }
00770 }
00771 }
00772
00773 int
00774 st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
00775 {
00776 st_table_entry *ptr, **last, *tmp;
00777 enum st_retval retval;
00778 st_index_t i;
00779
00780 if (table->entries_packed) {
00781 for (i = 0; i < table->num_entries; i++) {
00782 st_index_t j;
00783 st_data_t key, val;
00784 key = (st_data_t)table->bins[i*2];
00785 val = (st_data_t)table->bins[i*2+1];
00786 retval = (*func)(key, val, arg);
00787 if (!table->entries_packed) {
00788 FIND_ENTRY(table, ptr, key, i);
00789 if (retval == ST_CHECK) {
00790 if (!ptr) goto deleted;
00791 goto unpacked_continue;
00792 }
00793 goto unpacked;
00794 }
00795 switch (retval) {
00796 case ST_CHECK:
00797 for (j = 0; j < table->num_entries; j++) {
00798 if ((st_data_t)table->bins[j*2] == key)
00799 break;
00800 }
00801 if (j == table->num_entries) {
00802 goto deleted;
00803 }
00804
00805 case ST_CONTINUE:
00806 break;
00807 case ST_STOP:
00808 return 0;
00809 case ST_DELETE:
00810 table->num_entries--;
00811 memmove(&table->bins[i*2], &table->bins[(i+1)*2],
00812 sizeof(struct st_table_entry*) * 2*(table->num_entries-i));
00813 i--;
00814 break;
00815 }
00816 }
00817 return 0;
00818 }
00819 else {
00820 ptr = table->head;
00821 }
00822
00823 if (ptr != 0) {
00824 do {
00825 i = ptr->hash % table->num_bins;
00826 retval = (*func)(ptr->key, ptr->record, arg);
00827 unpacked:
00828 switch (retval) {
00829 case ST_CHECK:
00830 for (tmp = table->bins[i]; tmp != ptr; tmp = tmp->next) {
00831 if (!tmp) {
00832 deleted:
00833
00834 retval = (*func)(0, 0, arg, 1);
00835 return 1;
00836 }
00837 }
00838
00839 case ST_CONTINUE:
00840 unpacked_continue:
00841 ptr = ptr->fore;
00842 break;
00843 case ST_STOP:
00844 return 0;
00845 case ST_DELETE:
00846 last = &table->bins[ptr->hash % table->num_bins];
00847 for (; (tmp = *last) != 0; last = &tmp->next) {
00848 if (ptr == tmp) {
00849 tmp = ptr->fore;
00850 *last = ptr->next;
00851 REMOVE_ENTRY(table, ptr);
00852 free(ptr);
00853 if (ptr == tmp) return 0;
00854 ptr = tmp;
00855 break;
00856 }
00857 }
00858 }
00859 } while (ptr && table->head);
00860 }
00861 return 0;
00862 }
00863
00864 #if 0
00865 int
00866 st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
00867 {
00868 st_table_entry *ptr, **last, *tmp;
00869 enum st_retval retval;
00870 int i;
00871
00872 if (table->entries_packed) {
00873 for (i = table->num_entries-1; 0 <= i; i--) {
00874 int j;
00875 st_data_t key, val;
00876 key = (st_data_t)table->bins[i*2];
00877 val = (st_data_t)table->bins[i*2+1];
00878 retval = (*func)(key, val, arg);
00879 switch (retval) {
00880 case ST_CHECK:
00881 for (j = 0; j < table->num_entries; j++) {
00882 if ((st_data_t)table->bins[j*2] == key)
00883 break;
00884 }
00885 if (j == table->num_entries) {
00886
00887 retval = (*func)(0, 0, arg, 1);
00888 return 1;
00889 }
00890
00891 case ST_CONTINUE:
00892 break;
00893 case ST_STOP:
00894 return 0;
00895 case ST_DELETE:
00896 table->num_entries--;
00897 memmove(&table->bins[i*2], &table->bins[(i+1)*2],
00898 sizeof(struct st_table_entry*) * 2*(table->num_entries-i));
00899 break;
00900 }
00901 }
00902 return 0;
00903 }
00904
00905 if ((ptr = table->head) != 0) {
00906 ptr = ptr->back;
00907 do {
00908 retval = (*func)(ptr->key, ptr->record, arg, 0);
00909 switch (retval) {
00910 case ST_CHECK:
00911 i = ptr->hash % table->num_bins;
00912 for (tmp = table->bins[i]; tmp != ptr; tmp = tmp->next) {
00913 if (!tmp) {
00914
00915 retval = (*func)(0, 0, arg, 1);
00916 return 1;
00917 }
00918 }
00919
00920 case ST_CONTINUE:
00921 ptr = ptr->back;
00922 break;
00923 case ST_STOP:
00924 return 0;
00925 case ST_DELETE:
00926 last = &table->bins[ptr->hash % table->num_bins];
00927 for (; (tmp = *last) != 0; last = &tmp->next) {
00928 if (ptr == tmp) {
00929 tmp = ptr->back;
00930 *last = ptr->next;
00931 REMOVE_ENTRY(table, ptr);
00932 free(ptr);
00933 ptr = tmp;
00934 break;
00935 }
00936 }
00937 ptr = ptr->next;
00938 free(tmp);
00939 table->num_entries--;
00940 }
00941 } while (ptr && table->head);
00942 }
00943 return 0;
00944 }
00945 #endif
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015 #define FNV1_32A_INIT 0x811c9dc5
01016
01017
01018
01019
01020 #define FNV_32_PRIME 0x01000193
01021
01022 #ifdef ST_USE_FNV1
01023 static st_index_t
01024 strhash(st_data_t arg)
01025 {
01026 register const char *string = (const char *)arg;
01027 register st_index_t hval = FNV1_32A_INIT;
01028
01029
01030
01031
01032 while (*string) {
01033
01034 hval ^= (unsigned int)*string++;
01035
01036
01037 hval *= FNV_32_PRIME;
01038 }
01039 return hval;
01040 }
01041 #else
01042
01043 #ifndef UNALIGNED_WORD_ACCESS
01044 # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
01045 defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD86) || \
01046 defined(__mc68020__)
01047 # define UNALIGNED_WORD_ACCESS 1
01048 # endif
01049 #endif
01050 #ifndef UNALIGNED_WORD_ACCESS
01051 # define UNALIGNED_WORD_ACCESS 0
01052 #endif
01053
01054
01055 #ifndef MURMUR
01056 #define MURMUR 2
01057 #endif
01058
01059 #define MurmurMagic_1 (st_index_t)0xc6a4a793
01060 #define MurmurMagic_2 (st_index_t)0x5bd1e995
01061 #if MURMUR == 1
01062 #define MurmurMagic MurmurMagic_1
01063 #elif MURMUR == 2
01064 #if SIZEOF_ST_INDEX_T > 4
01065 #define MurmurMagic ((MurmurMagic_1 << 32) | MurmurMagic_2)
01066 #else
01067 #define MurmurMagic MurmurMagic_2
01068 #endif
01069 #endif
01070
01071 static inline st_index_t
01072 murmur(st_index_t h, st_index_t k, int r)
01073 {
01074 const st_index_t m = MurmurMagic;
01075 #if MURMUR == 1
01076 h += k;
01077 h *= m;
01078 h ^= h >> r;
01079 #elif MURMUR == 2
01080 k *= m;
01081 k ^= k >> r;
01082 k *= m;
01083
01084 h *= m;
01085 h ^= k;
01086 #endif
01087 return h;
01088 }
01089
01090 static inline st_index_t
01091 murmur_finish(st_index_t h)
01092 {
01093 #if MURMUR == 1
01094 h = murmur(h, 0, 10);
01095 h = murmur(h, 0, 17);
01096 #elif MURMUR == 2
01097 h ^= h >> 13;
01098 h *= MurmurMagic;
01099 h ^= h >> 15;
01100 #endif
01101 return h;
01102 }
01103
01104 #define murmur_step(h, k) murmur((h), (k), 16)
01105
01106 #if MURMUR == 1
01107 #define murmur1(h) murmur_step((h), 16)
01108 #else
01109 #define murmur1(h) murmur_step((h), 24)
01110 #endif
01111
01112 st_index_t
01113 st_hash(const void *ptr, size_t len, st_index_t h)
01114 {
01115 const char *data = ptr;
01116 st_index_t t = 0;
01117
01118 h += 0xdeadbeef;
01119
01120 #define data_at(n) (st_index_t)((unsigned char)data[(n)])
01121 #define UNALIGNED_ADD_4 UNALIGNED_ADD(2); UNALIGNED_ADD(1); UNALIGNED_ADD(0)
01122 #if SIZEOF_ST_INDEX_T > 4
01123 #define UNALIGNED_ADD_8 UNALIGNED_ADD(6); UNALIGNED_ADD(5); UNALIGNED_ADD(4); UNALIGNED_ADD(3); UNALIGNED_ADD_4
01124 #if SIZEOF_ST_INDEX_T > 8
01125 #define UNALIGNED_ADD_16 UNALIGNED_ADD(14); UNALIGNED_ADD(13); UNALIGNED_ADD(12); UNALIGNED_ADD(11); \
01126 UNALIGNED_ADD(10); UNALIGNED_ADD(9); UNALIGNED_ADD(8); UNALIGNED_ADD(7); UNALIGNED_ADD_8
01127 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_16
01128 #endif
01129 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_8
01130 #else
01131 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_4
01132 #endif
01133 if (len >= sizeof(st_index_t)) {
01134 #if !UNALIGNED_WORD_ACCESS
01135 int align = (int)((st_data_t)data % sizeof(st_index_t));
01136 if (align) {
01137 st_index_t d = 0;
01138 int sl, sr, pack;
01139
01140 switch (align) {
01141 #ifdef WORDS_BIGENDIAN
01142 # define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \
01143 t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 2)
01144 #else
01145 # define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \
01146 t |= data_at(n) << CHAR_BIT*(n)
01147 #endif
01148 UNALIGNED_ADD_ALL;
01149 #undef UNALIGNED_ADD
01150 }
01151
01152 #ifdef WORDS_BIGENDIAN
01153 t >>= (CHAR_BIT * align) - CHAR_BIT;
01154 #else
01155 t <<= (CHAR_BIT * align);
01156 #endif
01157
01158 data += sizeof(st_index_t)-align;
01159 len -= sizeof(st_index_t)-align;
01160
01161 sl = CHAR_BIT * (SIZEOF_ST_INDEX_T-align);
01162 sr = CHAR_BIT * align;
01163
01164 while (len >= sizeof(st_index_t)) {
01165 d = *(st_index_t *)data;
01166 #ifdef WORDS_BIGENDIAN
01167 t = (t << sr) | (d >> sl);
01168 #else
01169 t = (t >> sr) | (d << sl);
01170 #endif
01171 h = murmur_step(h, t);
01172 t = d;
01173 data += sizeof(st_index_t);
01174 len -= sizeof(st_index_t);
01175 }
01176
01177 pack = len < (size_t)align ? (int)len : align;
01178 d = 0;
01179 switch (pack) {
01180 #ifdef WORDS_BIGENDIAN
01181 # define UNALIGNED_ADD(n) case (n) + 1: \
01182 d |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1)
01183 #else
01184 # define UNALIGNED_ADD(n) case (n) + 1: \
01185 d |= data_at(n) << CHAR_BIT*(n)
01186 #endif
01187 UNALIGNED_ADD_ALL;
01188 #undef UNALIGNED_ADD
01189 }
01190 #ifdef WORDS_BIGENDIAN
01191 t = (t << sr) | (d >> sl);
01192 #else
01193 t = (t >> sr) | (d << sl);
01194 #endif
01195
01196 #if MURMUR == 2
01197 if (len < (size_t)align) goto skip_tail;
01198 #endif
01199 h = murmur_step(h, t);
01200 data += pack;
01201 len -= pack;
01202 }
01203 else
01204 #endif
01205 {
01206 do {
01207 h = murmur_step(h, *(st_index_t *)data);
01208 data += sizeof(st_index_t);
01209 len -= sizeof(st_index_t);
01210 } while (len >= sizeof(st_index_t));
01211 }
01212 }
01213
01214 t = 0;
01215 switch (len) {
01216 #ifdef WORDS_BIGENDIAN
01217 # define UNALIGNED_ADD(n) case (n) + 1: \
01218 t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1)
01219 #else
01220 # define UNALIGNED_ADD(n) case (n) + 1: \
01221 t |= data_at(n) << CHAR_BIT*(n)
01222 #endif
01223 UNALIGNED_ADD_ALL;
01224 #undef UNALIGNED_ADD
01225 #if MURMUR == 1
01226 h = murmur_step(h, t);
01227 #elif MURMUR == 2
01228 # if !UNALIGNED_WORD_ACCESS
01229 skip_tail:
01230 # endif
01231 h ^= t;
01232 h *= MurmurMagic;
01233 #endif
01234 }
01235
01236 return murmur_finish(h);
01237 }
01238
01239 st_index_t
01240 st_hash_uint32(st_index_t h, uint32_t i)
01241 {
01242 return murmur_step(h + i, 16);
01243 }
01244
01245 st_index_t
01246 st_hash_uint(st_index_t h, st_index_t i)
01247 {
01248 st_index_t v = 0;
01249 h += i;
01250 #ifdef WORDS_BIGENDIAN
01251 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8
01252 v = murmur1(v + (h >> 12*8));
01253 #endif
01254 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8
01255 v = murmur1(v + (h >> 8*8));
01256 #endif
01257 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8
01258 v = murmur1(v + (h >> 4*8));
01259 #endif
01260 #endif
01261 v = murmur1(v + h);
01262 #ifndef WORDS_BIGENDIAN
01263 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8
01264 v = murmur1(v + (h >> 4*8));
01265 #endif
01266 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8
01267 v = murmur1(v + (h >> 8*8));
01268 #endif
01269 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8
01270 v = murmur1(v + (h >> 12*8));
01271 #endif
01272 #endif
01273 return v;
01274 }
01275
01276 st_index_t
01277 st_hash_end(st_index_t h)
01278 {
01279 h = murmur_step(h, 10);
01280 h = murmur_step(h, 17);
01281 return h;
01282 }
01283
01284 #undef st_hash_start
01285 st_index_t
01286 st_hash_start(st_index_t h)
01287 {
01288 return h;
01289 }
01290
01291 static st_index_t
01292 strhash(st_data_t arg)
01293 {
01294 register const char *string = (const char *)arg;
01295 return st_hash(string, strlen(string), FNV1_32A_INIT);
01296 }
01297 #endif
01298
01299 int
01300 st_strcasecmp(const char *s1, const char *s2)
01301 {
01302 unsigned int c1, c2;
01303
01304 while (1) {
01305 c1 = (unsigned char)*s1++;
01306 c2 = (unsigned char)*s2++;
01307 if (c1 == '\0' || c2 == '\0') {
01308 if (c1 != '\0') return 1;
01309 if (c2 != '\0') return -1;
01310 return 0;
01311 }
01312 if ((unsigned int)(c1 - 'A') <= ('Z' - 'A')) c1 += 'a' - 'A';
01313 if ((unsigned int)(c2 - 'A') <= ('Z' - 'A')) c2 += 'a' - 'A';
01314 if (c1 != c2) {
01315 if (c1 > c2)
01316 return 1;
01317 else
01318 return -1;
01319 }
01320 }
01321 }
01322
01323 int
01324 st_strncasecmp(const char *s1, const char *s2, size_t n)
01325 {
01326 unsigned int c1, c2;
01327
01328 while (n--) {
01329 c1 = (unsigned char)*s1++;
01330 c2 = (unsigned char)*s2++;
01331 if (c1 == '\0' || c2 == '\0') {
01332 if (c1 != '\0') return 1;
01333 if (c2 != '\0') return -1;
01334 return 0;
01335 }
01336 if ((unsigned int)(c1 - 'A') <= ('Z' - 'A')) c1 += 'a' - 'A';
01337 if ((unsigned int)(c2 - 'A') <= ('Z' - 'A')) c2 += 'a' - 'A';
01338 if (c1 != c2) {
01339 if (c1 > c2)
01340 return 1;
01341 else
01342 return -1;
01343 }
01344 }
01345 return 0;
01346 }
01347
01348 static st_index_t
01349 strcasehash(st_data_t arg)
01350 {
01351 register const char *string = (const char *)arg;
01352 register st_index_t hval = FNV1_32A_INIT;
01353
01354
01355
01356
01357 while (*string) {
01358 unsigned int c = (unsigned char)*string++;
01359 if ((unsigned int)(c - 'A') <= ('Z' - 'A')) c += 'a' - 'A';
01360 hval ^= c;
01361
01362
01363 hval *= FNV_32_PRIME;
01364 }
01365 return hval;
01366 }
01367
01368 int
01369 st_numcmp(st_data_t x, st_data_t y)
01370 {
01371 return x != y;
01372 }
01373
01374 st_index_t
01375 st_numhash(st_data_t n)
01376 {
01377 return (st_index_t)n;
01378 }
01379