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 typedef struct st_packed_entry {
00029 st_index_t hash;
00030 st_data_t key, val;
00031 } st_packed_entry;
00032
00033 #define STATIC_ASSERT(name, expr) typedef int static_assert_##name##_check[(expr) ? 1 : -1];
00034
00035 #define ST_DEFAULT_MAX_DENSITY 5
00036 #define ST_DEFAULT_INIT_TABLE_SIZE 11
00037 #define ST_DEFAULT_SECOND_TABLE_SIZE 19
00038 #define ST_DEFAULT_PACKED_TABLE_SIZE 18
00039 #define PACKED_UNIT (int)(sizeof(st_packed_entry) / sizeof(st_table_entry*))
00040 #define MAX_PACKED_HASH (int)(ST_DEFAULT_PACKED_TABLE_SIZE * sizeof(st_table_entry*) / sizeof(st_packed_entry))
00041
00042 STATIC_ASSERT(st_packed_entry, sizeof(st_packed_entry) == sizeof(st_table_entry*[PACKED_UNIT]))
00043 STATIC_ASSERT(st_packed_bins, sizeof(st_packed_entry[MAX_PACKED_HASH]) <= sizeof(st_table_entry*[ST_DEFAULT_PACKED_TABLE_SIZE]))
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #define type_numhash st_hashtype_num
00056 const struct st_hash_type st_hashtype_num = {
00057 st_numcmp,
00058 st_numhash,
00059 };
00060
00061
00062 static st_index_t strhash(st_data_t);
00063 static const struct st_hash_type type_strhash = {
00064 strcmp,
00065 strhash,
00066 };
00067
00068 static st_index_t strcasehash(st_data_t);
00069 static const struct st_hash_type type_strcasehash = {
00070 st_locale_insensitive_strcasecmp,
00071 strcasehash,
00072 };
00073
00074 static void rehash(st_table *);
00075
00076 #ifdef RUBY
00077 #define malloc xmalloc
00078 #define calloc xcalloc
00079 #define realloc xrealloc
00080 #define free(x) xfree(x)
00081 #endif
00082
00083 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
00084
00085 #define EQUAL(table,x,y) ((x)==(y) || (*(table)->type->compare)((x),(y)) == 0)
00086
00087 #define do_hash(key,table) (st_index_t)(*(table)->type->hash)((key))
00088 #define do_hash_bin(key,table) (do_hash((key), (table))%(table)->num_bins)
00089
00090
00091 #define st_alloc_entry() (st_table_entry *)malloc(sizeof(st_table_entry))
00092 #define st_free_entry(entry) free(entry)
00093 #define st_alloc_table() (st_table *)malloc(sizeof(st_table))
00094 #define st_dealloc_table(table) free(table)
00095 #define st_alloc_bins(size) (st_table_entry **)calloc(size, sizeof(st_table_entry *))
00096 #define st_free_bins(bins, size) free(bins)
00097 static inline st_table_entry**
00098 st_realloc_bins(st_table_entry **bins, st_index_t newsize, st_index_t oldsize)
00099 {
00100 bins = (st_table_entry **)realloc(bins, newsize * sizeof(st_table_entry *));
00101 MEMZERO(bins, st_table_entry*, newsize);
00102 return bins;
00103 }
00104
00105
00106 #define bins as.big.bins
00107 #define head as.big.head
00108 #define tail as.big.tail
00109 #define real_entries as.packed.real_entries
00110
00111
00112 #define PACKED_BINS(table) ((table)->as.packed.entries)
00113 #define PACKED_ENT(table, i) PACKED_BINS(table)[i]
00114 #define PKEY(table, i) PACKED_ENT((table), (i)).key
00115 #define PVAL(table, i) PACKED_ENT((table), (i)).val
00116 #define PHASH(table, i) PACKED_ENT((table), (i)).hash
00117 #define PKEY_SET(table, i, v) (PKEY((table), (i)) = (v))
00118 #define PVAL_SET(table, i, v) (PVAL((table), (i)) = (v))
00119 #define PHASH_SET(table, i, v) (PHASH((table), (i)) = (v))
00120
00121
00122 static inline void
00123 remove_packed_entry(st_table *table, st_index_t i)
00124 {
00125 table->real_entries--;
00126 table->num_entries--;
00127 if (i < table->real_entries) {
00128 MEMMOVE(&PACKED_ENT(table, i), &PACKED_ENT(table, i+1),
00129 st_packed_entry, table->real_entries - i);
00130 }
00131 }
00132
00133 static inline void
00134 remove_safe_packed_entry(st_table *table, st_index_t i, st_data_t never)
00135 {
00136 table->num_entries--;
00137 PKEY_SET(table, i, never);
00138 PVAL_SET(table, i, never);
00139 PHASH_SET(table, i, 0);
00140 }
00141
00142
00143
00144
00145
00146 #define MINSIZE 8
00147
00148
00149
00150
00151 static const unsigned int primes[] = {
00152 ST_DEFAULT_INIT_TABLE_SIZE,
00153 ST_DEFAULT_SECOND_TABLE_SIZE,
00154 32 + 5,
00155 64 + 3,
00156 128 + 3,
00157 256 + 27,
00158 512 + 9,
00159 1024 + 9,
00160 2048 + 5,
00161 4096 + 3,
00162 8192 + 27,
00163 16384 + 43,
00164 32768 + 3,
00165 65536 + 45,
00166 131072 + 29,
00167 262144 + 3,
00168 524288 + 21,
00169 1048576 + 7,
00170 2097152 + 17,
00171 4194304 + 15,
00172 8388608 + 9,
00173 16777216 + 43,
00174 33554432 + 35,
00175 67108864 + 15,
00176 134217728 + 29,
00177 268435456 + 3,
00178 536870912 + 11,
00179 1073741824 + 85,
00180 0
00181 };
00182
00183 static st_index_t
00184 new_size(st_index_t size)
00185 {
00186 int i;
00187
00188 #if 0
00189 for (i=3; i<31; i++) {
00190 if ((1<<i) > size) return 1<<i;
00191 }
00192 return -1;
00193 #else
00194 st_index_t newsize;
00195
00196 for (i = 0, newsize = MINSIZE; i < numberof(primes); i++, newsize <<= 1) {
00197 if (newsize > size) return primes[i];
00198 }
00199
00200 #ifndef NOT_RUBY
00201 rb_raise(rb_eRuntimeError, "st_table too big");
00202 #endif
00203 return -1;
00204 #endif
00205 }
00206
00207 #ifdef HASH_LOG
00208 #ifdef HAVE_UNISTD_H
00209 #include <unistd.h>
00210 #endif
00211 static struct {
00212 int all, total, num, str, strcase;
00213 } collision;
00214 static int init_st = 0;
00215
00216 static void
00217 stat_col(void)
00218 {
00219 char fname[10+sizeof(long)*3];
00220 FILE *f = fopen((snprintf(fname, sizeof(fname), "/tmp/col%ld", (long)getpid()), fname), "w");
00221 fprintf(f, "collision: %d / %d (%6.2f)\n", collision.all, collision.total,
00222 ((double)collision.all / (collision.total)) * 100);
00223 fprintf(f, "num: %d, str: %d, strcase: %d\n", collision.num, collision.str, collision.strcase);
00224 fclose(f);
00225 }
00226 #endif
00227
00228 st_table*
00229 st_init_table_with_size(const struct st_hash_type *type, st_index_t size)
00230 {
00231 st_table *tbl;
00232
00233 #ifdef HASH_LOG
00234 # if HASH_LOG+0 < 0
00235 {
00236 const char *e = getenv("ST_HASH_LOG");
00237 if (!e || !*e) init_st = 1;
00238 }
00239 # endif
00240 if (init_st == 0) {
00241 init_st = 1;
00242 atexit(stat_col);
00243 }
00244 #endif
00245
00246
00247 tbl = st_alloc_table();
00248 tbl->type = type;
00249 tbl->num_entries = 0;
00250 tbl->entries_packed = size <= MAX_PACKED_HASH;
00251 if (tbl->entries_packed) {
00252 size = ST_DEFAULT_PACKED_TABLE_SIZE;
00253 }
00254 else {
00255 size = new_size(size);
00256 }
00257 tbl->num_bins = size;
00258 tbl->bins = st_alloc_bins(size);
00259 tbl->head = 0;
00260 tbl->tail = 0;
00261
00262 return tbl;
00263 }
00264
00265 st_table*
00266 st_init_table(const struct st_hash_type *type)
00267 {
00268 return st_init_table_with_size(type, 0);
00269 }
00270
00271 st_table*
00272 st_init_numtable(void)
00273 {
00274 return st_init_table(&type_numhash);
00275 }
00276
00277 st_table*
00278 st_init_numtable_with_size(st_index_t size)
00279 {
00280 return st_init_table_with_size(&type_numhash, size);
00281 }
00282
00283 st_table*
00284 st_init_strtable(void)
00285 {
00286 return st_init_table(&type_strhash);
00287 }
00288
00289 st_table*
00290 st_init_strtable_with_size(st_index_t size)
00291 {
00292 return st_init_table_with_size(&type_strhash, size);
00293 }
00294
00295 st_table*
00296 st_init_strcasetable(void)
00297 {
00298 return st_init_table(&type_strcasehash);
00299 }
00300
00301 st_table*
00302 st_init_strcasetable_with_size(st_index_t size)
00303 {
00304 return st_init_table_with_size(&type_strcasehash, size);
00305 }
00306
00307 void
00308 st_clear(st_table *table)
00309 {
00310 register st_table_entry *ptr, *next;
00311 st_index_t i;
00312
00313 if (table->entries_packed) {
00314 table->num_entries = 0;
00315 table->real_entries = 0;
00316 return;
00317 }
00318
00319 for (i = 0; i < table->num_bins; i++) {
00320 ptr = table->bins[i];
00321 table->bins[i] = 0;
00322 while (ptr != 0) {
00323 next = ptr->next;
00324 st_free_entry(ptr);
00325 ptr = next;
00326 }
00327 }
00328 table->num_entries = 0;
00329 table->head = 0;
00330 table->tail = 0;
00331 }
00332
00333 void
00334 st_free_table(st_table *table)
00335 {
00336 st_clear(table);
00337 st_free_bins(table->bins, table->num_bins);
00338 st_dealloc_table(table);
00339 }
00340
00341 size_t
00342 st_memsize(const st_table *table)
00343 {
00344 if (table->entries_packed) {
00345 return table->num_bins * sizeof (void *) + sizeof(st_table);
00346 }
00347 else {
00348 return table->num_entries * sizeof(struct st_table_entry) + table->num_bins * sizeof (void *) + sizeof(st_table);
00349 }
00350 }
00351
00352 #define PTR_NOT_EQUAL(table, ptr, hash_val, key) \
00353 ((ptr) != 0 && ((ptr)->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key)))
00354
00355 #ifdef HASH_LOG
00356 static void
00357 count_collision(const struct st_hash_type *type)
00358 {
00359 collision.all++;
00360 if (type == &type_numhash) {
00361 collision.num++;
00362 }
00363 else if (type == &type_strhash) {
00364 collision.strcase++;
00365 }
00366 else if (type == &type_strcasehash) {
00367 collision.str++;
00368 }
00369 }
00370 #define COLLISION (collision_check ? count_collision(table->type) : (void)0)
00371 #define FOUND_ENTRY (collision_check ? collision.total++ : (void)0)
00372 #else
00373 #define COLLISION
00374 #define FOUND_ENTRY
00375 #endif
00376
00377 #define FIND_ENTRY(table, ptr, hash_val, bin_pos) \
00378 ((ptr) = find_entry((table), key, (hash_val), ((bin_pos) = (hash_val)%(table)->num_bins)))
00379
00380 static st_table_entry *
00381 find_entry(st_table *table, st_data_t key, st_index_t hash_val, st_index_t bin_pos)
00382 {
00383 register st_table_entry *ptr = table->bins[bin_pos];
00384 FOUND_ENTRY;
00385 if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {
00386 COLLISION;
00387 while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {
00388 ptr = ptr->next;
00389 }
00390 ptr = ptr->next;
00391 }
00392 return ptr;
00393 }
00394
00395 static inline st_index_t
00396 find_packed_index_from(st_table *table, st_index_t hash_val, st_data_t key, st_index_t i)
00397 {
00398 while (i < table->real_entries &&
00399 (PHASH(table, i) != hash_val || !EQUAL(table, key, PKEY(table, i)))) {
00400 i++;
00401 }
00402 return i;
00403 }
00404
00405 static inline st_index_t
00406 find_packed_index(st_table *table, st_index_t hash_val, st_data_t key)
00407 {
00408 return find_packed_index_from(table, hash_val, key, 0);
00409 }
00410
00411 #define collision_check 0
00412
00413 int
00414 st_lookup(st_table *table, register st_data_t key, st_data_t *value)
00415 {
00416 st_index_t hash_val;
00417 register st_table_entry *ptr;
00418
00419 hash_val = do_hash(key, table);
00420
00421 if (table->entries_packed) {
00422 st_index_t i = find_packed_index(table, hash_val, key);
00423 if (i < table->real_entries) {
00424 if (value != 0) *value = PVAL(table, i);
00425 return 1;
00426 }
00427 return 0;
00428 }
00429
00430 ptr = find_entry(table, key, hash_val, hash_val % table->num_bins);
00431
00432 if (ptr == 0) {
00433 return 0;
00434 }
00435 else {
00436 if (value != 0) *value = ptr->record;
00437 return 1;
00438 }
00439 }
00440
00441 int
00442 st_get_key(st_table *table, register st_data_t key, st_data_t *result)
00443 {
00444 st_index_t hash_val;
00445 register st_table_entry *ptr;
00446
00447 hash_val = do_hash(key, table);
00448
00449 if (table->entries_packed) {
00450 st_index_t i = find_packed_index(table, hash_val, key);
00451 if (i < table->real_entries) {
00452 if (result != 0) *result = PKEY(table, i);
00453 return 1;
00454 }
00455 return 0;
00456 }
00457
00458 ptr = find_entry(table, key, hash_val, hash_val % table->num_bins);
00459
00460 if (ptr == 0) {
00461 return 0;
00462 }
00463 else {
00464 if (result != 0) *result = ptr->key;
00465 return 1;
00466 }
00467 }
00468
00469 #undef collision_check
00470 #define collision_check 1
00471
00472 static inline st_table_entry *
00473 new_entry(st_table * table, st_data_t key, st_data_t value,
00474 st_index_t hash_val, register st_index_t bin_pos)
00475 {
00476 register st_table_entry *entry = st_alloc_entry();
00477
00478 entry->next = table->bins[bin_pos];
00479 table->bins[bin_pos] = entry;
00480 entry->hash = hash_val;
00481 entry->key = key;
00482 entry->record = value;
00483
00484 return entry;
00485 }
00486
00487 static inline void
00488 add_direct(st_table *table, st_data_t key, st_data_t value,
00489 st_index_t hash_val, register st_index_t bin_pos)
00490 {
00491 register st_table_entry *entry;
00492 if (table->num_entries > ST_DEFAULT_MAX_DENSITY * table->num_bins) {
00493 rehash(table);
00494 bin_pos = hash_val % table->num_bins;
00495 }
00496
00497 entry = new_entry(table, key, value, hash_val, bin_pos);
00498
00499 if (table->head != 0) {
00500 entry->fore = 0;
00501 (entry->back = table->tail)->fore = entry;
00502 table->tail = entry;
00503 }
00504 else {
00505 table->head = table->tail = entry;
00506 entry->fore = entry->back = 0;
00507 }
00508 table->num_entries++;
00509 }
00510
00511 static void
00512 unpack_entries(register st_table *table)
00513 {
00514 st_index_t i;
00515 st_packed_entry packed_bins[MAX_PACKED_HASH];
00516 register st_table_entry *entry, *preventry = 0, **chain;
00517 st_table tmp_table = *table;
00518
00519 MEMCPY(packed_bins, PACKED_BINS(table), st_packed_entry, MAX_PACKED_HASH);
00520 table->as.packed.entries = packed_bins;
00521 tmp_table.entries_packed = 0;
00522 #if ST_DEFAULT_INIT_TABLE_SIZE == ST_DEFAULT_PACKED_TABLE_SIZE
00523 MEMZERO(tmp_table.bins, st_table_entry*, tmp_table.num_bins);
00524 #else
00525 tmp_table.bins = st_realloc_bins(tmp_table.bins, ST_DEFAULT_INIT_TABLE_SIZE, tmp_table.num_bins);
00526 tmp_table.num_bins = ST_DEFAULT_INIT_TABLE_SIZE;
00527 #endif
00528 i = 0;
00529 chain = &tmp_table.head;
00530 do {
00531 st_data_t key = packed_bins[i].key;
00532 st_data_t val = packed_bins[i].val;
00533 st_index_t hash = packed_bins[i].hash;
00534 entry = new_entry(&tmp_table, key, val, hash,
00535 hash % ST_DEFAULT_INIT_TABLE_SIZE);
00536 *chain = entry;
00537 entry->back = preventry;
00538 preventry = entry;
00539 chain = &entry->fore;
00540 } while (++i < MAX_PACKED_HASH);
00541 *chain = NULL;
00542 tmp_table.tail = entry;
00543 *table = tmp_table;
00544 }
00545
00546 static void
00547 add_packed_direct(st_table *table, st_data_t key, st_data_t value, st_index_t hash_val)
00548 {
00549 if (table->real_entries < MAX_PACKED_HASH) {
00550 st_index_t i = table->real_entries++;
00551 PKEY_SET(table, i, key);
00552 PVAL_SET(table, i, value);
00553 PHASH_SET(table, i, hash_val);
00554 table->num_entries++;
00555 }
00556 else {
00557 unpack_entries(table);
00558 add_direct(table, key, value, hash_val, hash_val % table->num_bins);
00559 }
00560 }
00561
00562
00563 int
00564 st_insert(register st_table *table, register st_data_t key, st_data_t value)
00565 {
00566 st_index_t hash_val;
00567 register st_index_t bin_pos;
00568 register st_table_entry *ptr;
00569
00570 hash_val = do_hash(key, table);
00571
00572 if (table->entries_packed) {
00573 st_index_t i = find_packed_index(table, hash_val, key);
00574 if (i < table->real_entries) {
00575 PVAL_SET(table, i, value);
00576 return 1;
00577 }
00578 add_packed_direct(table, key, value, hash_val);
00579 return 0;
00580 }
00581
00582 FIND_ENTRY(table, ptr, hash_val, bin_pos);
00583
00584 if (ptr == 0) {
00585 add_direct(table, key, value, hash_val, bin_pos);
00586 return 0;
00587 }
00588 else {
00589 ptr->record = value;
00590 return 1;
00591 }
00592 }
00593
00594 int
00595 st_insert2(register st_table *table, register st_data_t key, st_data_t value,
00596 st_data_t (*func)(st_data_t))
00597 {
00598 st_index_t hash_val;
00599 register st_index_t bin_pos;
00600 register st_table_entry *ptr;
00601
00602 hash_val = do_hash(key, table);
00603
00604 if (table->entries_packed) {
00605 st_index_t i = find_packed_index(table, hash_val, key);
00606 if (i < table->real_entries) {
00607 PVAL_SET(table, i, value);
00608 return 1;
00609 }
00610 key = (*func)(key);
00611 add_packed_direct(table, key, value, hash_val);
00612 return 0;
00613 }
00614
00615 FIND_ENTRY(table, ptr, hash_val, bin_pos);
00616
00617 if (ptr == 0) {
00618 key = (*func)(key);
00619 add_direct(table, key, value, hash_val, bin_pos);
00620 return 0;
00621 }
00622 else {
00623 ptr->record = value;
00624 return 1;
00625 }
00626 }
00627
00628 void
00629 st_add_direct(st_table *table, st_data_t key, st_data_t value)
00630 {
00631 st_index_t hash_val;
00632
00633 hash_val = do_hash(key, table);
00634 if (table->entries_packed) {
00635 add_packed_direct(table, key, value, hash_val);
00636 return;
00637 }
00638
00639 add_direct(table, key, value, hash_val, hash_val % table->num_bins);
00640 }
00641
00642 static void
00643 rehash(register st_table *table)
00644 {
00645 register st_table_entry *ptr, **new_bins;
00646 st_index_t new_num_bins, hash_val;
00647
00648 new_num_bins = new_size(table->num_bins+1);
00649 new_bins = st_realloc_bins(table->bins, new_num_bins, table->num_bins);
00650 table->num_bins = new_num_bins;
00651 table->bins = new_bins;
00652
00653 if ((ptr = table->head) != 0) {
00654 do {
00655 hash_val = ptr->hash % new_num_bins;
00656 ptr->next = new_bins[hash_val];
00657 new_bins[hash_val] = ptr;
00658 } while ((ptr = ptr->fore) != 0);
00659 }
00660 }
00661
00662 st_table*
00663 st_copy(st_table *old_table)
00664 {
00665 st_table *new_table;
00666 st_table_entry *ptr, *entry, *prev, **tailp;
00667 st_index_t num_bins = old_table->num_bins;
00668 st_index_t hash_val;
00669
00670 new_table = st_alloc_table();
00671 if (new_table == 0) {
00672 return 0;
00673 }
00674
00675 *new_table = *old_table;
00676 new_table->bins = st_alloc_bins(num_bins);
00677
00678 if (new_table->bins == 0) {
00679 st_dealloc_table(new_table);
00680 return 0;
00681 }
00682
00683 if (old_table->entries_packed) {
00684 MEMCPY(new_table->bins, old_table->bins, st_table_entry*, old_table->num_bins);
00685 return new_table;
00686 }
00687
00688 if ((ptr = old_table->head) != 0) {
00689 prev = 0;
00690 tailp = &new_table->head;
00691 do {
00692 entry = st_alloc_entry();
00693 if (entry == 0) {
00694 st_free_table(new_table);
00695 return 0;
00696 }
00697 *entry = *ptr;
00698 hash_val = entry->hash % num_bins;
00699 entry->next = new_table->bins[hash_val];
00700 new_table->bins[hash_val] = entry;
00701 entry->back = prev;
00702 *tailp = prev = entry;
00703 tailp = &entry->fore;
00704 } while ((ptr = ptr->fore) != 0);
00705 new_table->tail = prev;
00706 }
00707
00708 return new_table;
00709 }
00710
00711 static inline void
00712 remove_entry(st_table *table, st_table_entry *ptr)
00713 {
00714 if (ptr->fore == 0 && ptr->back == 0) {
00715 table->head = 0;
00716 table->tail = 0;
00717 }
00718 else {
00719 st_table_entry *fore = ptr->fore, *back = ptr->back;
00720 if (fore) fore->back = back;
00721 if (back) back->fore = fore;
00722 if (ptr == table->head) table->head = fore;
00723 if (ptr == table->tail) table->tail = back;
00724 }
00725 table->num_entries--;
00726 }
00727
00728 int
00729 st_delete(register st_table *table, register st_data_t *key, st_data_t *value)
00730 {
00731 st_index_t hash_val;
00732 st_table_entry **prev;
00733 register st_table_entry *ptr;
00734
00735 hash_val = do_hash(*key, table);
00736
00737 if (table->entries_packed) {
00738 st_index_t i = find_packed_index(table, hash_val, *key);
00739 if (i < table->real_entries) {
00740 if (value != 0) *value = PVAL(table, i);
00741 *key = PKEY(table, i);
00742 remove_packed_entry(table, i);
00743 return 1;
00744 }
00745 if (value != 0) *value = 0;
00746 return 0;
00747 }
00748
00749 prev = &table->bins[hash_val % table->num_bins];
00750 for (;(ptr = *prev) != 0; prev = &ptr->next) {
00751 if (EQUAL(table, *key, ptr->key)) {
00752 *prev = ptr->next;
00753 remove_entry(table, ptr);
00754 if (value != 0) *value = ptr->record;
00755 *key = ptr->key;
00756 st_free_entry(ptr);
00757 return 1;
00758 }
00759 }
00760
00761 if (value != 0) *value = 0;
00762 return 0;
00763 }
00764
00765 int
00766 st_delete_safe(register st_table *table, register st_data_t *key, st_data_t *value, st_data_t never)
00767 {
00768 st_index_t hash_val;
00769 register st_table_entry *ptr;
00770
00771 hash_val = do_hash(*key, table);
00772
00773 if (table->entries_packed) {
00774 st_index_t i = find_packed_index(table, hash_val, *key);
00775 if (i < table->real_entries) {
00776 if (value != 0) *value = PVAL(table, i);
00777 *key = PKEY(table, i);
00778 remove_safe_packed_entry(table, i, never);
00779 return 1;
00780 }
00781 if (value != 0) *value = 0;
00782 return 0;
00783 }
00784
00785 ptr = table->bins[hash_val % table->num_bins];
00786
00787 for (; ptr != 0; ptr = ptr->next) {
00788 if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) {
00789 remove_entry(table, ptr);
00790 *key = ptr->key;
00791 if (value != 0) *value = ptr->record;
00792 ptr->key = ptr->record = never;
00793 return 1;
00794 }
00795 }
00796
00797 if (value != 0) *value = 0;
00798 return 0;
00799 }
00800
00801 int
00802 st_shift(register st_table *table, register st_data_t *key, st_data_t *value)
00803 {
00804 st_table_entry **prev;
00805 register st_table_entry *ptr;
00806
00807 if (table->num_entries == 0) {
00808 if (value != 0) *value = 0;
00809 return 0;
00810 }
00811
00812 if (table->entries_packed) {
00813 if (value != 0) *value = PVAL(table, 0);
00814 *key = PKEY(table, 0);
00815 remove_packed_entry(table, 0);
00816 return 1;
00817 }
00818
00819 prev = &table->bins[table->head->hash % table->num_bins];
00820 while ((ptr = *prev) != table->head) prev = &ptr->next;
00821 *prev = ptr->next;
00822 if (value != 0) *value = ptr->record;
00823 *key = ptr->key;
00824 remove_entry(table, ptr);
00825 st_free_entry(ptr);
00826 return 1;
00827 }
00828
00829 void
00830 st_cleanup_safe(st_table *table, st_data_t never)
00831 {
00832 st_table_entry *ptr, **last, *tmp;
00833 st_index_t i;
00834
00835 if (table->entries_packed) {
00836 st_index_t i = 0, j = 0;
00837 while (PKEY(table, i) != never) {
00838 if (i++ == table->real_entries) return;
00839 }
00840 for (j = i; ++i < table->real_entries;) {
00841 if (PKEY(table, i) == never) continue;
00842 PACKED_ENT(table, j) = PACKED_ENT(table, i);
00843 j++;
00844 }
00845 table->real_entries = j;
00846
00847 table->num_entries = j;
00848 return;
00849 }
00850
00851 for (i = 0; i < table->num_bins; i++) {
00852 ptr = *(last = &table->bins[i]);
00853 while (ptr != 0) {
00854 if (ptr->key == never) {
00855 tmp = ptr;
00856 *last = ptr = ptr->next;
00857 st_free_entry(tmp);
00858 }
00859 else {
00860 ptr = *(last = &ptr->next);
00861 }
00862 }
00863 }
00864 }
00865
00866 int
00867 st_update(st_table *table, st_data_t key, st_update_callback_func *func, st_data_t arg)
00868 {
00869 st_index_t hash_val, bin_pos;
00870 register st_table_entry *ptr, **last, *tmp;
00871 st_data_t value = 0;
00872 int retval, existing = 0;
00873
00874 hash_val = do_hash(key, table);
00875
00876 if (table->entries_packed) {
00877 st_index_t i = find_packed_index(table, hash_val, key);
00878 if (i < table->real_entries) {
00879 key = PKEY(table, i);
00880 value = PVAL(table, i);
00881 existing = 1;
00882 }
00883 {
00884 retval = (*func)(&key, &value, arg, existing);
00885 if (!table->entries_packed) {
00886 FIND_ENTRY(table, ptr, hash_val, bin_pos);
00887 goto unpacked;
00888 }
00889 switch (retval) {
00890 case ST_CONTINUE:
00891 if (!existing) {
00892 add_packed_direct(table, key, value, hash_val);
00893 break;
00894 }
00895 PVAL_SET(table, i, value);
00896 break;
00897 case ST_DELETE:
00898 if (!existing) break;
00899 remove_packed_entry(table, i);
00900 }
00901 }
00902 return existing;
00903 }
00904
00905 FIND_ENTRY(table, ptr, hash_val, bin_pos);
00906
00907 if (ptr != 0) {
00908 key = ptr->key;
00909 value = ptr->record;
00910 existing = 1;
00911 }
00912 {
00913 retval = (*func)(&key, &value, arg, existing);
00914 unpacked:
00915 switch (retval) {
00916 case ST_CONTINUE:
00917 if (!existing) {
00918 add_direct(table, key, value, hash_val, hash_val % table->num_bins);
00919 break;
00920 }
00921 ptr->record = value;
00922 break;
00923 case ST_DELETE:
00924 if (!existing) break;
00925 last = &table->bins[bin_pos];
00926 for (; (tmp = *last) != 0; last = &tmp->next) {
00927 if (ptr == tmp) {
00928 tmp = ptr->fore;
00929 *last = ptr->next;
00930 remove_entry(table, ptr);
00931 st_free_entry(ptr);
00932 break;
00933 }
00934 }
00935 break;
00936 }
00937 return existing;
00938 }
00939 }
00940
00941 int
00942 st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never)
00943 {
00944 st_table_entry *ptr, **last, *tmp;
00945 enum st_retval retval;
00946 st_index_t i;
00947
00948 if (table->entries_packed) {
00949 for (i = 0; i < table->real_entries; i++) {
00950 st_data_t key, val;
00951 st_index_t hash;
00952 key = PKEY(table, i);
00953 val = PVAL(table, i);
00954 hash = PHASH(table, i);
00955 if (key == never) continue;
00956 retval = (*func)(key, val, arg, 0);
00957 if (!table->entries_packed) {
00958 FIND_ENTRY(table, ptr, hash, i);
00959 if (retval == ST_CHECK) {
00960 if (!ptr) goto deleted;
00961 goto unpacked_continue;
00962 }
00963 goto unpacked;
00964 }
00965 switch (retval) {
00966 case ST_CHECK:
00967 if (PHASH(table, i) == 0 && PKEY(table, i) == never) {
00968 break;
00969 }
00970 i = find_packed_index_from(table, hash, key, i);
00971 if (i >= table->real_entries) {
00972 i = find_packed_index(table, hash, key);
00973 if (i >= table->real_entries) goto deleted;
00974 }
00975
00976 case ST_CONTINUE:
00977 break;
00978 case ST_STOP:
00979 return 0;
00980 case ST_DELETE:
00981 remove_safe_packed_entry(table, i, never);
00982 break;
00983 }
00984 }
00985 return 0;
00986 }
00987 else {
00988 ptr = table->head;
00989 }
00990
00991 if (ptr != 0) {
00992 do {
00993 if (ptr->key == never)
00994 goto unpacked_continue;
00995 i = ptr->hash % table->num_bins;
00996 retval = (*func)(ptr->key, ptr->record, arg, 0);
00997 unpacked:
00998 switch (retval) {
00999 case ST_CHECK:
01000 for (tmp = table->bins[i]; tmp != ptr; tmp = tmp->next) {
01001 if (!tmp) {
01002 deleted:
01003
01004 retval = (*func)(0, 0, arg, 1);
01005 return 1;
01006 }
01007 }
01008
01009 case ST_CONTINUE:
01010 unpacked_continue:
01011 ptr = ptr->fore;
01012 break;
01013 case ST_STOP:
01014 return 0;
01015 case ST_DELETE:
01016 last = &table->bins[ptr->hash % table->num_bins];
01017 for (; (tmp = *last) != 0; last = &tmp->next) {
01018 if (ptr == tmp) {
01019 tmp = ptr->fore;
01020 remove_entry(table, ptr);
01021 ptr->key = ptr->record = never;
01022 ptr->hash = 0;
01023 ptr = tmp;
01024 break;
01025 }
01026 }
01027 }
01028 } while (ptr && table->head);
01029 }
01030 return 0;
01031 }
01032
01033 int
01034 st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
01035 {
01036 st_table_entry *ptr, **last, *tmp;
01037 enum st_retval retval;
01038 st_index_t i;
01039
01040 if (table->entries_packed) {
01041 for (i = 0; i < table->real_entries; i++) {
01042 st_data_t key, val, hash;
01043 key = PKEY(table, i);
01044 val = PVAL(table, i);
01045 hash = PHASH(table, i);
01046 retval = (*func)(key, val, arg, 0);
01047 if (!table->entries_packed) {
01048 FIND_ENTRY(table, ptr, hash, i);
01049 if (!ptr) return 0;
01050 goto unpacked;
01051 }
01052 switch (retval) {
01053 case ST_CONTINUE:
01054 break;
01055 case ST_CHECK:
01056 case ST_STOP:
01057 return 0;
01058 case ST_DELETE:
01059 remove_packed_entry(table, i);
01060 i--;
01061 break;
01062 }
01063 }
01064 return 0;
01065 }
01066 else {
01067 ptr = table->head;
01068 }
01069
01070 if (ptr != 0) {
01071 do {
01072 i = ptr->hash % table->num_bins;
01073 retval = (*func)(ptr->key, ptr->record, arg, 0);
01074 unpacked:
01075 switch (retval) {
01076 case ST_CONTINUE:
01077 ptr = ptr->fore;
01078 break;
01079 case ST_CHECK:
01080 case ST_STOP:
01081 return 0;
01082 case ST_DELETE:
01083 last = &table->bins[ptr->hash % table->num_bins];
01084 for (; (tmp = *last) != 0; last = &tmp->next) {
01085 if (ptr == tmp) {
01086 tmp = ptr->fore;
01087 *last = ptr->next;
01088 remove_entry(table, ptr);
01089 st_free_entry(ptr);
01090 ptr = tmp;
01091 break;
01092 }
01093 }
01094 }
01095 } while (ptr && table->head);
01096 }
01097 return 0;
01098 }
01099
01100 static st_index_t
01101 get_keys(st_table *table, st_data_t *keys, st_index_t size, int check, st_data_t never)
01102 {
01103 st_data_t key;
01104 st_data_t *keys_start = keys;
01105
01106 if (table->entries_packed) {
01107 st_index_t i;
01108
01109 if (size > table->real_entries) size = table->real_entries;
01110 for (i = 0; i < size; i++) {
01111 key = PKEY(table, i);
01112 if (check && key == never) continue;
01113 *keys++ = key;
01114 }
01115 }
01116 else {
01117 st_table_entry *ptr = table->head;
01118 st_data_t *keys_end = keys + size;
01119 for (; ptr && keys < keys_end; ptr = ptr->fore) {
01120 key = ptr->key;
01121 if (check && key == never) continue;
01122 *keys++ = key;
01123 }
01124 }
01125
01126 return keys - keys_start;
01127 }
01128
01129 st_index_t
01130 st_keys(st_table *table, st_data_t *keys, st_index_t size)
01131 {
01132 return get_keys(table, keys, size, 0, 0);
01133 }
01134
01135 st_index_t
01136 st_keys_check(st_table *table, st_data_t *keys, st_index_t size, st_data_t never)
01137 {
01138 return get_keys(table, keys, size, 1, never);
01139 }
01140
01141 static st_index_t
01142 get_values(st_table *table, st_data_t *values, st_index_t size, int check, st_data_t never)
01143 {
01144 st_data_t key;
01145 st_data_t *values_start = values;
01146
01147 if (table->entries_packed) {
01148 st_index_t i;
01149
01150 if (size > table->real_entries) size = table->real_entries;
01151 for (i = 0; i < size; i++) {
01152 key = PKEY(table, i);
01153 if (check && key == never) continue;
01154 *values++ = PVAL(table, i);
01155 }
01156 }
01157 else {
01158 st_table_entry *ptr = table->head;
01159 st_data_t *values_end = values + size;
01160 for (; ptr && values < values_end; ptr = ptr->fore) {
01161 key = ptr->key;
01162 if (check && key == never) continue;
01163 *values++ = ptr->record;
01164 }
01165 }
01166
01167 return values - values_start;
01168 }
01169
01170 st_index_t
01171 st_values(st_table *table, st_data_t *values, st_index_t size)
01172 {
01173 return get_values(table, values, size, 0, 0);
01174 }
01175
01176 st_index_t
01177 st_values_check(st_table *table, st_data_t *values, st_index_t size, st_data_t never)
01178 {
01179 return get_values(table, values, size, 1, never);
01180 }
01181
01182 #if 0
01183 int
01184 st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
01185 {
01186 st_table_entry *ptr, **last, *tmp;
01187 enum st_retval retval;
01188 int i;
01189
01190 if (table->entries_packed) {
01191 for (i = table->num_entries-1; 0 <= i; i--) {
01192 int j;
01193 st_data_t key, val;
01194 key = PKEY(table, i);
01195 val = PVAL(table, i);
01196 retval = (*func)(key, val, arg, 0);
01197 switch (retval) {
01198 case ST_CHECK:
01199 for (j = 0; j < table->num_entries; j++) {
01200 if (PKEY(table, j) == key)
01201 break;
01202 }
01203 if (j == table->num_entries) {
01204
01205 retval = (*func)(0, 0, arg, 1);
01206 return 1;
01207 }
01208
01209 case ST_CONTINUE:
01210 break;
01211 case ST_STOP:
01212 return 0;
01213 case ST_DELETE:
01214 remove_packed_entry(table, i);
01215 break;
01216 }
01217 }
01218 return 0;
01219 }
01220
01221 if ((ptr = table->head) != 0) {
01222 ptr = ptr->back;
01223 do {
01224 retval = (*func)(ptr->key, ptr->record, arg, 0);
01225 switch (retval) {
01226 case ST_CHECK:
01227 i = ptr->hash % table->num_bins;
01228 for (tmp = table->bins[i]; tmp != ptr; tmp = tmp->next) {
01229 if (!tmp) {
01230
01231 retval = (*func)(0, 0, arg, 1);
01232 return 1;
01233 }
01234 }
01235
01236 case ST_CONTINUE:
01237 ptr = ptr->back;
01238 break;
01239 case ST_STOP:
01240 return 0;
01241 case ST_DELETE:
01242 last = &table->bins[ptr->hash % table->num_bins];
01243 for (; (tmp = *last) != 0; last = &tmp->next) {
01244 if (ptr == tmp) {
01245 tmp = ptr->back;
01246 *last = ptr->next;
01247 remove_entry(table, ptr);
01248 st_free_entry(ptr);
01249 ptr = tmp;
01250 break;
01251 }
01252 }
01253 ptr = ptr->next;
01254 free(tmp);
01255 table->num_entries--;
01256 }
01257 } while (ptr && table->head);
01258 }
01259 return 0;
01260 }
01261 #endif
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331 #define FNV1_32A_INIT 0x811c9dc5
01332
01333
01334
01335
01336 #define FNV_32_PRIME 0x01000193
01337
01338 #ifdef ST_USE_FNV1
01339 static st_index_t
01340 strhash(st_data_t arg)
01341 {
01342 register const char *string = (const char *)arg;
01343 register st_index_t hval = FNV1_32A_INIT;
01344
01345
01346
01347
01348 while (*string) {
01349
01350 hval ^= (unsigned int)*string++;
01351
01352
01353 hval *= FNV_32_PRIME;
01354 }
01355 return hval;
01356 }
01357 #else
01358
01359 #ifndef UNALIGNED_WORD_ACCESS
01360 # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
01361 defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \
01362 defined(__mc68020__)
01363 # define UNALIGNED_WORD_ACCESS 1
01364 # endif
01365 #endif
01366 #ifndef UNALIGNED_WORD_ACCESS
01367 # define UNALIGNED_WORD_ACCESS 0
01368 #endif
01369
01370
01371 #ifndef MURMUR
01372 #define MURMUR 2
01373 #endif
01374
01375 #define MurmurMagic_1 (st_index_t)0xc6a4a793
01376 #define MurmurMagic_2 (st_index_t)0x5bd1e995
01377 #if MURMUR == 1
01378 #define MurmurMagic MurmurMagic_1
01379 #elif MURMUR == 2
01380 #if SIZEOF_ST_INDEX_T > 4
01381 #define MurmurMagic ((MurmurMagic_1 << 32) | MurmurMagic_2)
01382 #else
01383 #define MurmurMagic MurmurMagic_2
01384 #endif
01385 #endif
01386
01387 static inline st_index_t
01388 murmur(st_index_t h, st_index_t k, int r)
01389 {
01390 const st_index_t m = MurmurMagic;
01391 #if MURMUR == 1
01392 h += k;
01393 h *= m;
01394 h ^= h >> r;
01395 #elif MURMUR == 2
01396 k *= m;
01397 k ^= k >> r;
01398 k *= m;
01399
01400 h *= m;
01401 h ^= k;
01402 #endif
01403 return h;
01404 }
01405
01406 static inline st_index_t
01407 murmur_finish(st_index_t h)
01408 {
01409 #if MURMUR == 1
01410 h = murmur(h, 0, 10);
01411 h = murmur(h, 0, 17);
01412 #elif MURMUR == 2
01413 h ^= h >> 13;
01414 h *= MurmurMagic;
01415 h ^= h >> 15;
01416 #endif
01417 return h;
01418 }
01419
01420 #define murmur_step(h, k) murmur((h), (k), 16)
01421
01422 #if MURMUR == 1
01423 #define murmur1(h) murmur_step((h), 16)
01424 #else
01425 #define murmur1(h) murmur_step((h), 24)
01426 #endif
01427
01428 st_index_t
01429 st_hash(const void *ptr, size_t len, st_index_t h)
01430 {
01431 const char *data = ptr;
01432 st_index_t t = 0;
01433
01434 h += 0xdeadbeef;
01435
01436 #define data_at(n) (st_index_t)((unsigned char)data[(n)])
01437 #define UNALIGNED_ADD_4 UNALIGNED_ADD(2); UNALIGNED_ADD(1); UNALIGNED_ADD(0)
01438 #if SIZEOF_ST_INDEX_T > 4
01439 #define UNALIGNED_ADD_8 UNALIGNED_ADD(6); UNALIGNED_ADD(5); UNALIGNED_ADD(4); UNALIGNED_ADD(3); UNALIGNED_ADD_4
01440 #if SIZEOF_ST_INDEX_T > 8
01441 #define UNALIGNED_ADD_16 UNALIGNED_ADD(14); UNALIGNED_ADD(13); UNALIGNED_ADD(12); UNALIGNED_ADD(11); \
01442 UNALIGNED_ADD(10); UNALIGNED_ADD(9); UNALIGNED_ADD(8); UNALIGNED_ADD(7); UNALIGNED_ADD_8
01443 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_16
01444 #endif
01445 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_8
01446 #else
01447 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_4
01448 #endif
01449 if (len >= sizeof(st_index_t)) {
01450 #if !UNALIGNED_WORD_ACCESS
01451 int align = (int)((st_data_t)data % sizeof(st_index_t));
01452 if (align) {
01453 st_index_t d = 0;
01454 int sl, sr, pack;
01455
01456 switch (align) {
01457 #ifdef WORDS_BIGENDIAN
01458 # define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \
01459 t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 2)
01460 #else
01461 # define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \
01462 t |= data_at(n) << CHAR_BIT*(n)
01463 #endif
01464 UNALIGNED_ADD_ALL;
01465 #undef UNALIGNED_ADD
01466 }
01467
01468 #ifdef WORDS_BIGENDIAN
01469 t >>= (CHAR_BIT * align) - CHAR_BIT;
01470 #else
01471 t <<= (CHAR_BIT * align);
01472 #endif
01473
01474 data += sizeof(st_index_t)-align;
01475 len -= sizeof(st_index_t)-align;
01476
01477 sl = CHAR_BIT * (SIZEOF_ST_INDEX_T-align);
01478 sr = CHAR_BIT * align;
01479
01480 while (len >= sizeof(st_index_t)) {
01481 d = *(st_index_t *)data;
01482 #ifdef WORDS_BIGENDIAN
01483 t = (t << sr) | (d >> sl);
01484 #else
01485 t = (t >> sr) | (d << sl);
01486 #endif
01487 h = murmur_step(h, t);
01488 t = d;
01489 data += sizeof(st_index_t);
01490 len -= sizeof(st_index_t);
01491 }
01492
01493 pack = len < (size_t)align ? (int)len : align;
01494 d = 0;
01495 switch (pack) {
01496 #ifdef WORDS_BIGENDIAN
01497 # define UNALIGNED_ADD(n) case (n) + 1: \
01498 d |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1)
01499 #else
01500 # define UNALIGNED_ADD(n) case (n) + 1: \
01501 d |= data_at(n) << CHAR_BIT*(n)
01502 #endif
01503 UNALIGNED_ADD_ALL;
01504 #undef UNALIGNED_ADD
01505 }
01506 #ifdef WORDS_BIGENDIAN
01507 t = (t << sr) | (d >> sl);
01508 #else
01509 t = (t >> sr) | (d << sl);
01510 #endif
01511
01512 #if MURMUR == 2
01513 if (len < (size_t)align) goto skip_tail;
01514 #endif
01515 h = murmur_step(h, t);
01516 data += pack;
01517 len -= pack;
01518 }
01519 else
01520 #endif
01521 {
01522 do {
01523 h = murmur_step(h, *(st_index_t *)data);
01524 data += sizeof(st_index_t);
01525 len -= sizeof(st_index_t);
01526 } while (len >= sizeof(st_index_t));
01527 }
01528 }
01529
01530 t = 0;
01531 switch (len) {
01532 #ifdef WORDS_BIGENDIAN
01533 # define UNALIGNED_ADD(n) case (n) + 1: \
01534 t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1)
01535 #else
01536 # define UNALIGNED_ADD(n) case (n) + 1: \
01537 t |= data_at(n) << CHAR_BIT*(n)
01538 #endif
01539 UNALIGNED_ADD_ALL;
01540 #undef UNALIGNED_ADD
01541 #if MURMUR == 1
01542 h = murmur_step(h, t);
01543 #elif MURMUR == 2
01544 # if !UNALIGNED_WORD_ACCESS
01545 skip_tail:
01546 # endif
01547 h ^= t;
01548 h *= MurmurMagic;
01549 #endif
01550 }
01551
01552 return murmur_finish(h);
01553 }
01554
01555 st_index_t
01556 st_hash_uint32(st_index_t h, uint32_t i)
01557 {
01558 return murmur_step(h + i, 16);
01559 }
01560
01561 st_index_t
01562 st_hash_uint(st_index_t h, st_index_t i)
01563 {
01564 st_index_t v = 0;
01565 h += i;
01566 #ifdef WORDS_BIGENDIAN
01567 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8
01568 v = murmur1(v + (h >> 12*8));
01569 #endif
01570 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8
01571 v = murmur1(v + (h >> 8*8));
01572 #endif
01573 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8
01574 v = murmur1(v + (h >> 4*8));
01575 #endif
01576 #endif
01577 v = murmur1(v + h);
01578 #ifndef WORDS_BIGENDIAN
01579 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8
01580 v = murmur1(v + (h >> 4*8));
01581 #endif
01582 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8
01583 v = murmur1(v + (h >> 8*8));
01584 #endif
01585 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8
01586 v = murmur1(v + (h >> 12*8));
01587 #endif
01588 #endif
01589 return v;
01590 }
01591
01592 st_index_t
01593 st_hash_end(st_index_t h)
01594 {
01595 h = murmur_step(h, 10);
01596 h = murmur_step(h, 17);
01597 return h;
01598 }
01599
01600 #undef st_hash_start
01601 st_index_t
01602 st_hash_start(st_index_t h)
01603 {
01604 return h;
01605 }
01606
01607 static st_index_t
01608 strhash(st_data_t arg)
01609 {
01610 register const char *string = (const char *)arg;
01611 return st_hash(string, strlen(string), FNV1_32A_INIT);
01612 }
01613 #endif
01614
01615 int
01616 st_locale_insensitive_strcasecmp(const char *s1, const char *s2)
01617 {
01618 unsigned int c1, c2;
01619
01620 while (1) {
01621 c1 = (unsigned char)*s1++;
01622 c2 = (unsigned char)*s2++;
01623 if (c1 == '\0' || c2 == '\0') {
01624 if (c1 != '\0') return 1;
01625 if (c2 != '\0') return -1;
01626 return 0;
01627 }
01628 if ((unsigned int)(c1 - 'A') <= ('Z' - 'A')) c1 += 'a' - 'A';
01629 if ((unsigned int)(c2 - 'A') <= ('Z' - 'A')) c2 += 'a' - 'A';
01630 if (c1 != c2) {
01631 if (c1 > c2)
01632 return 1;
01633 else
01634 return -1;
01635 }
01636 }
01637 }
01638
01639 int
01640 st_locale_insensitive_strncasecmp(const char *s1, const char *s2, size_t n)
01641 {
01642 unsigned int c1, c2;
01643
01644 while (n--) {
01645 c1 = (unsigned char)*s1++;
01646 c2 = (unsigned char)*s2++;
01647 if (c1 == '\0' || c2 == '\0') {
01648 if (c1 != '\0') return 1;
01649 if (c2 != '\0') return -1;
01650 return 0;
01651 }
01652 if ((unsigned int)(c1 - 'A') <= ('Z' - 'A')) c1 += 'a' - 'A';
01653 if ((unsigned int)(c2 - 'A') <= ('Z' - 'A')) c2 += 'a' - 'A';
01654 if (c1 != c2) {
01655 if (c1 > c2)
01656 return 1;
01657 else
01658 return -1;
01659 }
01660 }
01661 return 0;
01662 }
01663
01664 static st_index_t
01665 strcasehash(st_data_t arg)
01666 {
01667 register const char *string = (const char *)arg;
01668 register st_index_t hval = FNV1_32A_INIT;
01669
01670
01671
01672
01673 while (*string) {
01674 unsigned int c = (unsigned char)*string++;
01675 if ((unsigned int)(c - 'A') <= ('Z' - 'A')) c += 'a' - 'A';
01676 hval ^= c;
01677
01678
01679 hval *= FNV_32_PRIME;
01680 }
01681 return hval;
01682 }
01683
01684 int
01685 st_numcmp(st_data_t x, st_data_t y)
01686 {
01687 return x != y;
01688 }
01689
01690 st_index_t
01691 st_numhash(st_data_t n)
01692 {
01693 return (st_index_t)n;
01694 }
01695