|
Ruby
2.0.0p594(2014-10-27revision48167)
|
00001 /* This is a public domain general purpose hash table package written by Peter Moore @ UCB. */ 00002 00003 /* static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */ 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 * DEFAULT_MAX_DENSITY is the default for the largest we allow the 00047 * average number of items per bin before increasing the number of 00048 * bins 00049 * 00050 * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins 00051 * allocated initially 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 /* extern int strcmp(const char *, const char *); */ 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_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 /* preparation for possible allocation improvements */ 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 /* Shortage */ 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 /* preparation for possible packing improvements */ 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 /* this function depends much on packed layout, so that it placed here */ 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 * MINSIZE is the minimum size of a dictionary. 00144 */ 00145 00146 #define MINSIZE 8 00147 00148 /* 00149 Table of prime numbers 2^n+a, 2<=n<=30. 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 /* Ran out of polynomials */ 00200 #ifndef NOT_RUBY 00201 rb_raise(rb_eRuntimeError, "st_table too big"); 00202 #endif 00203 return -1; /* should raise exception */ 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); /* round up to prime number */ 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 void 00802 st_cleanup_safe(st_table *table, st_data_t never) 00803 { 00804 st_table_entry *ptr, **last, *tmp; 00805 st_index_t i; 00806 00807 if (table->entries_packed) { 00808 st_index_t i = 0, j = 0; 00809 while (PKEY(table, i) != never) { 00810 if (i++ == table->real_entries) return; 00811 } 00812 for (j = i; ++i < table->real_entries;) { 00813 if (PKEY(table, i) == never) continue; 00814 PACKED_ENT(table, j) = PACKED_ENT(table, i); 00815 j++; 00816 } 00817 table->real_entries = j; 00818 /* table->num_entries really should be equal j at this moment, but let set it anyway */ 00819 table->num_entries = j; 00820 return; 00821 } 00822 00823 for (i = 0; i < table->num_bins; i++) { 00824 ptr = *(last = &table->bins[i]); 00825 while (ptr != 0) { 00826 if (ptr->key == never) { 00827 tmp = ptr; 00828 *last = ptr = ptr->next; 00829 st_free_entry(tmp); 00830 } 00831 else { 00832 ptr = *(last = &ptr->next); 00833 } 00834 } 00835 } 00836 } 00837 00838 int 00839 st_update(st_table *table, st_data_t key, st_update_callback_func *func, st_data_t arg) 00840 { 00841 st_index_t hash_val, bin_pos; 00842 register st_table_entry *ptr, **last, *tmp; 00843 st_data_t value = 0; 00844 int retval, existing = 0; 00845 00846 hash_val = do_hash(key, table); 00847 00848 if (table->entries_packed) { 00849 st_index_t i = find_packed_index(table, hash_val, key); 00850 if (i < table->real_entries) { 00851 key = PKEY(table, i); 00852 value = PVAL(table, i); 00853 existing = 1; 00854 } 00855 { 00856 retval = (*func)(&key, &value, arg, existing); 00857 if (!table->entries_packed) { 00858 FIND_ENTRY(table, ptr, hash_val, bin_pos); 00859 goto unpacked; 00860 } 00861 switch (retval) { 00862 case ST_CONTINUE: 00863 if (!existing) { 00864 add_packed_direct(table, key, value, hash_val); 00865 break; 00866 } 00867 PVAL_SET(table, i, value); 00868 break; 00869 case ST_DELETE: 00870 if (!existing) break; 00871 remove_packed_entry(table, i); 00872 } 00873 } 00874 return existing; 00875 } 00876 00877 FIND_ENTRY(table, ptr, hash_val, bin_pos); 00878 00879 if (ptr != 0) { 00880 key = ptr->key; 00881 value = ptr->record; 00882 existing = 1; 00883 } 00884 { 00885 retval = (*func)(&key, &value, arg, existing); 00886 unpacked: 00887 switch (retval) { 00888 case ST_CONTINUE: 00889 if (!existing) { 00890 add_direct(table, key, value, hash_val, hash_val % table->num_bins); 00891 break; 00892 } 00893 ptr->record = value; 00894 break; 00895 case ST_DELETE: 00896 if (!existing) break; 00897 last = &table->bins[bin_pos]; 00898 for (; (tmp = *last) != 0; last = &tmp->next) { 00899 if (ptr == tmp) { 00900 tmp = ptr->fore; 00901 *last = ptr->next; 00902 remove_entry(table, ptr); 00903 st_free_entry(ptr); 00904 break; 00905 } 00906 } 00907 break; 00908 } 00909 return existing; 00910 } 00911 } 00912 00913 int 00914 st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never) 00915 { 00916 st_table_entry *ptr, **last, *tmp; 00917 enum st_retval retval; 00918 st_index_t i; 00919 00920 if (table->entries_packed) { 00921 for (i = 0; i < table->real_entries; i++) { 00922 st_data_t key, val; 00923 st_index_t hash; 00924 key = PKEY(table, i); 00925 val = PVAL(table, i); 00926 hash = PHASH(table, i); 00927 if (key == never) continue; 00928 retval = (*func)(key, val, arg); 00929 if (!table->entries_packed) { 00930 FIND_ENTRY(table, ptr, hash, i); 00931 if (retval == ST_CHECK) { 00932 if (!ptr) goto deleted; 00933 goto unpacked_continue; 00934 } 00935 goto unpacked; 00936 } 00937 switch (retval) { 00938 case ST_CHECK: /* check if hash is modified during iteration */ 00939 if (PHASH(table, i) == 0 && PKEY(table, i) == never) { 00940 break; 00941 } 00942 i = find_packed_index_from(table, hash, key, i); 00943 if (i >= table->real_entries) { 00944 i = find_packed_index(table, hash, key); 00945 if (i >= table->real_entries) goto deleted; 00946 } 00947 /* fall through */ 00948 case ST_CONTINUE: 00949 break; 00950 case ST_STOP: 00951 return 0; 00952 case ST_DELETE: 00953 remove_safe_packed_entry(table, i, never); 00954 break; 00955 } 00956 } 00957 return 0; 00958 } 00959 else { 00960 ptr = table->head; 00961 } 00962 00963 if (ptr != 0) { 00964 do { 00965 if (ptr->key == never) 00966 goto unpacked_continue; 00967 i = ptr->hash % table->num_bins; 00968 retval = (*func)(ptr->key, ptr->record, arg); 00969 unpacked: 00970 switch (retval) { 00971 case ST_CHECK: /* check if hash is modified during iteration */ 00972 for (tmp = table->bins[i]; tmp != ptr; tmp = tmp->next) { 00973 if (!tmp) { 00974 deleted: 00975 /* call func with error notice */ 00976 retval = (*func)(0, 0, arg, 1); 00977 return 1; 00978 } 00979 } 00980 /* fall through */ 00981 case ST_CONTINUE: 00982 unpacked_continue: 00983 ptr = ptr->fore; 00984 break; 00985 case ST_STOP: 00986 return 0; 00987 case ST_DELETE: 00988 last = &table->bins[ptr->hash % table->num_bins]; 00989 for (; (tmp = *last) != 0; last = &tmp->next) { 00990 if (ptr == tmp) { 00991 tmp = ptr->fore; 00992 remove_entry(table, ptr); 00993 ptr->key = ptr->record = never; 00994 ptr->hash = 0; 00995 ptr = tmp; 00996 break; 00997 } 00998 } 00999 } 01000 } while (ptr && table->head); 01001 } 01002 return 0; 01003 } 01004 01005 int 01006 st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg) 01007 { 01008 st_table_entry *ptr, **last, *tmp; 01009 enum st_retval retval; 01010 st_index_t i; 01011 01012 if (table->entries_packed) { 01013 for (i = 0; i < table->real_entries; i++) { 01014 st_data_t key, val, hash; 01015 key = PKEY(table, i); 01016 val = PVAL(table, i); 01017 hash = PHASH(table, i); 01018 retval = (*func)(key, val, arg); 01019 if (!table->entries_packed) { 01020 FIND_ENTRY(table, ptr, hash, i); 01021 if (!ptr) return 0; 01022 goto unpacked; 01023 } 01024 switch (retval) { 01025 case ST_CONTINUE: 01026 break; 01027 case ST_CHECK: 01028 case ST_STOP: 01029 return 0; 01030 case ST_DELETE: 01031 remove_packed_entry(table, i); 01032 i--; 01033 break; 01034 } 01035 } 01036 return 0; 01037 } 01038 else { 01039 ptr = table->head; 01040 } 01041 01042 if (ptr != 0) { 01043 do { 01044 i = ptr->hash % table->num_bins; 01045 retval = (*func)(ptr->key, ptr->record, arg); 01046 unpacked: 01047 switch (retval) { 01048 case ST_CONTINUE: 01049 ptr = ptr->fore; 01050 break; 01051 case ST_CHECK: 01052 case ST_STOP: 01053 return 0; 01054 case ST_DELETE: 01055 last = &table->bins[ptr->hash % table->num_bins]; 01056 for (; (tmp = *last) != 0; last = &tmp->next) { 01057 if (ptr == tmp) { 01058 tmp = ptr->fore; 01059 *last = ptr->next; 01060 remove_entry(table, ptr); 01061 st_free_entry(ptr); 01062 ptr = tmp; 01063 break; 01064 } 01065 } 01066 } 01067 } while (ptr && table->head); 01068 } 01069 return 0; 01070 } 01071 01072 #if 0 /* unused right now */ 01073 int 01074 st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg) 01075 { 01076 st_table_entry *ptr, **last, *tmp; 01077 enum st_retval retval; 01078 int i; 01079 01080 if (table->entries_packed) { 01081 for (i = table->num_entries-1; 0 <= i; i--) { 01082 int j; 01083 st_data_t key, val; 01084 key = PKEY(table, i); 01085 val = PVAL(table, i); 01086 retval = (*func)(key, val, arg); 01087 switch (retval) { 01088 case ST_CHECK: /* check if hash is modified during iteration */ 01089 for (j = 0; j < table->num_entries; j++) { 01090 if (PKEY(table, j) == key) 01091 break; 01092 } 01093 if (j == table->num_entries) { 01094 /* call func with error notice */ 01095 retval = (*func)(0, 0, arg, 1); 01096 return 1; 01097 } 01098 /* fall through */ 01099 case ST_CONTINUE: 01100 break; 01101 case ST_STOP: 01102 return 0; 01103 case ST_DELETE: 01104 remove_packed_entry(table, i); 01105 break; 01106 } 01107 } 01108 return 0; 01109 } 01110 01111 if ((ptr = table->head) != 0) { 01112 ptr = ptr->back; 01113 do { 01114 retval = (*func)(ptr->key, ptr->record, arg, 0); 01115 switch (retval) { 01116 case ST_CHECK: /* check if hash is modified during iteration */ 01117 i = ptr->hash % table->num_bins; 01118 for (tmp = table->bins[i]; tmp != ptr; tmp = tmp->next) { 01119 if (!tmp) { 01120 /* call func with error notice */ 01121 retval = (*func)(0, 0, arg, 1); 01122 return 1; 01123 } 01124 } 01125 /* fall through */ 01126 case ST_CONTINUE: 01127 ptr = ptr->back; 01128 break; 01129 case ST_STOP: 01130 return 0; 01131 case ST_DELETE: 01132 last = &table->bins[ptr->hash % table->num_bins]; 01133 for (; (tmp = *last) != 0; last = &tmp->next) { 01134 if (ptr == tmp) { 01135 tmp = ptr->back; 01136 *last = ptr->next; 01137 remove_entry(table, ptr); 01138 st_free_entry(ptr); 01139 ptr = tmp; 01140 break; 01141 } 01142 } 01143 ptr = ptr->next; 01144 free(tmp); 01145 table->num_entries--; 01146 } 01147 } while (ptr && table->head); 01148 } 01149 return 0; 01150 } 01151 #endif 01152 01153 /* 01154 * hash_32 - 32 bit Fowler/Noll/Vo FNV-1a hash code 01155 * 01156 * @(#) $Hash32: Revision: 1.1 $ 01157 * @(#) $Hash32: Id: hash_32a.c,v 1.1 2003/10/03 20:38:53 chongo Exp $ 01158 * @(#) $Hash32: Source: /usr/local/src/cmd/fnv/RCS/hash_32a.c,v $ 01159 * 01160 *** 01161 * 01162 * Fowler/Noll/Vo hash 01163 * 01164 * The basis of this hash algorithm was taken from an idea sent 01165 * as reviewer comments to the IEEE POSIX P1003.2 committee by: 01166 * 01167 * Phong Vo (http://www.research.att.com/info/kpv/) 01168 * Glenn Fowler (http://www.research.att.com/~gsf/) 01169 * 01170 * In a subsequent ballot round: 01171 * 01172 * Landon Curt Noll (http://www.isthe.com/chongo/) 01173 * 01174 * improved on their algorithm. Some people tried this hash 01175 * and found that it worked rather well. In an EMail message 01176 * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. 01177 * 01178 * FNV hashes are designed to be fast while maintaining a low 01179 * collision rate. The FNV speed allows one to quickly hash lots 01180 * of data while maintaining a reasonable collision rate. See: 01181 * 01182 * http://www.isthe.com/chongo/tech/comp/fnv/index.html 01183 * 01184 * for more details as well as other forms of the FNV hash. 01185 *** 01186 * 01187 * To use the recommended 32 bit FNV-1a hash, pass FNV1_32A_INIT as the 01188 * Fnv32_t hashval argument to fnv_32a_buf() or fnv_32a_str(). 01189 * 01190 *** 01191 * 01192 * Please do not copyright this code. This code is in the public domain. 01193 * 01194 * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 01195 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO 01196 * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR 01197 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 01198 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 01199 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 01200 * PERFORMANCE OF THIS SOFTWARE. 01201 * 01202 * By: 01203 * chongo <Landon Curt Noll> /\oo/\ 01204 * http://www.isthe.com/chongo/ 01205 * 01206 * Share and Enjoy! :-) 01207 */ 01208 01209 /* 01210 * 32 bit FNV-1 and FNV-1a non-zero initial basis 01211 * 01212 * The FNV-1 initial basis is the FNV-0 hash of the following 32 octets: 01213 * 01214 * chongo <Landon Curt Noll> /\../\ 01215 * 01216 * NOTE: The \'s above are not back-slashing escape characters. 01217 * They are literal ASCII backslash 0x5c characters. 01218 * 01219 * NOTE: The FNV-1a initial basis is the same value as FNV-1 by definition. 01220 */ 01221 #define FNV1_32A_INIT 0x811c9dc5 01222 01223 /* 01224 * 32 bit magic FNV-1a prime 01225 */ 01226 #define FNV_32_PRIME 0x01000193 01227 01228 #ifdef ST_USE_FNV1 01229 static st_index_t 01230 strhash(st_data_t arg) 01231 { 01232 register const char *string = (const char *)arg; 01233 register st_index_t hval = FNV1_32A_INIT; 01234 01235 /* 01236 * FNV-1a hash each octet in the buffer 01237 */ 01238 while (*string) { 01239 /* xor the bottom with the current octet */ 01240 hval ^= (unsigned int)*string++; 01241 01242 /* multiply by the 32 bit FNV magic prime mod 2^32 */ 01243 hval *= FNV_32_PRIME; 01244 } 01245 return hval; 01246 } 01247 #else 01248 01249 #ifndef UNALIGNED_WORD_ACCESS 01250 # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ 01251 defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD86) || \ 01252 defined(__mc68020__) 01253 # define UNALIGNED_WORD_ACCESS 1 01254 # endif 01255 #endif 01256 #ifndef UNALIGNED_WORD_ACCESS 01257 # define UNALIGNED_WORD_ACCESS 0 01258 #endif 01259 01260 /* MurmurHash described in http://murmurhash.googlepages.com/ */ 01261 #ifndef MURMUR 01262 #define MURMUR 2 01263 #endif 01264 01265 #define MurmurMagic_1 (st_index_t)0xc6a4a793 01266 #define MurmurMagic_2 (st_index_t)0x5bd1e995 01267 #if MURMUR == 1 01268 #define MurmurMagic MurmurMagic_1 01269 #elif MURMUR == 2 01270 #if SIZEOF_ST_INDEX_T > 4 01271 #define MurmurMagic ((MurmurMagic_1 << 32) | MurmurMagic_2) 01272 #else 01273 #define MurmurMagic MurmurMagic_2 01274 #endif 01275 #endif 01276 01277 static inline st_index_t 01278 murmur(st_index_t h, st_index_t k, int r) 01279 { 01280 const st_index_t m = MurmurMagic; 01281 #if MURMUR == 1 01282 h += k; 01283 h *= m; 01284 h ^= h >> r; 01285 #elif MURMUR == 2 01286 k *= m; 01287 k ^= k >> r; 01288 k *= m; 01289 01290 h *= m; 01291 h ^= k; 01292 #endif 01293 return h; 01294 } 01295 01296 static inline st_index_t 01297 murmur_finish(st_index_t h) 01298 { 01299 #if MURMUR == 1 01300 h = murmur(h, 0, 10); 01301 h = murmur(h, 0, 17); 01302 #elif MURMUR == 2 01303 h ^= h >> 13; 01304 h *= MurmurMagic; 01305 h ^= h >> 15; 01306 #endif 01307 return h; 01308 } 01309 01310 #define murmur_step(h, k) murmur((h), (k), 16) 01311 01312 #if MURMUR == 1 01313 #define murmur1(h) murmur_step((h), 16) 01314 #else 01315 #define murmur1(h) murmur_step((h), 24) 01316 #endif 01317 01318 st_index_t 01319 st_hash(const void *ptr, size_t len, st_index_t h) 01320 { 01321 const char *data = ptr; 01322 st_index_t t = 0; 01323 01324 h += 0xdeadbeef; 01325 01326 #define data_at(n) (st_index_t)((unsigned char)data[(n)]) 01327 #define UNALIGNED_ADD_4 UNALIGNED_ADD(2); UNALIGNED_ADD(1); UNALIGNED_ADD(0) 01328 #if SIZEOF_ST_INDEX_T > 4 01329 #define UNALIGNED_ADD_8 UNALIGNED_ADD(6); UNALIGNED_ADD(5); UNALIGNED_ADD(4); UNALIGNED_ADD(3); UNALIGNED_ADD_4 01330 #if SIZEOF_ST_INDEX_T > 8 01331 #define UNALIGNED_ADD_16 UNALIGNED_ADD(14); UNALIGNED_ADD(13); UNALIGNED_ADD(12); UNALIGNED_ADD(11); \ 01332 UNALIGNED_ADD(10); UNALIGNED_ADD(9); UNALIGNED_ADD(8); UNALIGNED_ADD(7); UNALIGNED_ADD_8 01333 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_16 01334 #endif 01335 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_8 01336 #else 01337 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_4 01338 #endif 01339 if (len >= sizeof(st_index_t)) { 01340 #if !UNALIGNED_WORD_ACCESS 01341 int align = (int)((st_data_t)data % sizeof(st_index_t)); 01342 if (align) { 01343 st_index_t d = 0; 01344 int sl, sr, pack; 01345 01346 switch (align) { 01347 #ifdef WORDS_BIGENDIAN 01348 # define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \ 01349 t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 2) 01350 #else 01351 # define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \ 01352 t |= data_at(n) << CHAR_BIT*(n) 01353 #endif 01354 UNALIGNED_ADD_ALL; 01355 #undef UNALIGNED_ADD 01356 } 01357 01358 #ifdef WORDS_BIGENDIAN 01359 t >>= (CHAR_BIT * align) - CHAR_BIT; 01360 #else 01361 t <<= (CHAR_BIT * align); 01362 #endif 01363 01364 data += sizeof(st_index_t)-align; 01365 len -= sizeof(st_index_t)-align; 01366 01367 sl = CHAR_BIT * (SIZEOF_ST_INDEX_T-align); 01368 sr = CHAR_BIT * align; 01369 01370 while (len >= sizeof(st_index_t)) { 01371 d = *(st_index_t *)data; 01372 #ifdef WORDS_BIGENDIAN 01373 t = (t << sr) | (d >> sl); 01374 #else 01375 t = (t >> sr) | (d << sl); 01376 #endif 01377 h = murmur_step(h, t); 01378 t = d; 01379 data += sizeof(st_index_t); 01380 len -= sizeof(st_index_t); 01381 } 01382 01383 pack = len < (size_t)align ? (int)len : align; 01384 d = 0; 01385 switch (pack) { 01386 #ifdef WORDS_BIGENDIAN 01387 # define UNALIGNED_ADD(n) case (n) + 1: \ 01388 d |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1) 01389 #else 01390 # define UNALIGNED_ADD(n) case (n) + 1: \ 01391 d |= data_at(n) << CHAR_BIT*(n) 01392 #endif 01393 UNALIGNED_ADD_ALL; 01394 #undef UNALIGNED_ADD 01395 } 01396 #ifdef WORDS_BIGENDIAN 01397 t = (t << sr) | (d >> sl); 01398 #else 01399 t = (t >> sr) | (d << sl); 01400 #endif 01401 01402 #if MURMUR == 2 01403 if (len < (size_t)align) goto skip_tail; 01404 #endif 01405 h = murmur_step(h, t); 01406 data += pack; 01407 len -= pack; 01408 } 01409 else 01410 #endif 01411 { 01412 do { 01413 h = murmur_step(h, *(st_index_t *)data); 01414 data += sizeof(st_index_t); 01415 len -= sizeof(st_index_t); 01416 } while (len >= sizeof(st_index_t)); 01417 } 01418 } 01419 01420 t = 0; 01421 switch (len) { 01422 #ifdef WORDS_BIGENDIAN 01423 # define UNALIGNED_ADD(n) case (n) + 1: \ 01424 t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1) 01425 #else 01426 # define UNALIGNED_ADD(n) case (n) + 1: \ 01427 t |= data_at(n) << CHAR_BIT*(n) 01428 #endif 01429 UNALIGNED_ADD_ALL; 01430 #undef UNALIGNED_ADD 01431 #if MURMUR == 1 01432 h = murmur_step(h, t); 01433 #elif MURMUR == 2 01434 # if !UNALIGNED_WORD_ACCESS 01435 skip_tail: 01436 # endif 01437 h ^= t; 01438 h *= MurmurMagic; 01439 #endif 01440 } 01441 01442 return murmur_finish(h); 01443 } 01444 01445 st_index_t 01446 st_hash_uint32(st_index_t h, uint32_t i) 01447 { 01448 return murmur_step(h + i, 16); 01449 } 01450 01451 st_index_t 01452 st_hash_uint(st_index_t h, st_index_t i) 01453 { 01454 st_index_t v = 0; 01455 h += i; 01456 #ifdef WORDS_BIGENDIAN 01457 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8 01458 v = murmur1(v + (h >> 12*8)); 01459 #endif 01460 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8 01461 v = murmur1(v + (h >> 8*8)); 01462 #endif 01463 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8 01464 v = murmur1(v + (h >> 4*8)); 01465 #endif 01466 #endif 01467 v = murmur1(v + h); 01468 #ifndef WORDS_BIGENDIAN 01469 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8 01470 v = murmur1(v + (h >> 4*8)); 01471 #endif 01472 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8 01473 v = murmur1(v + (h >> 8*8)); 01474 #endif 01475 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8 01476 v = murmur1(v + (h >> 12*8)); 01477 #endif 01478 #endif 01479 return v; 01480 } 01481 01482 st_index_t 01483 st_hash_end(st_index_t h) 01484 { 01485 h = murmur_step(h, 10); 01486 h = murmur_step(h, 17); 01487 return h; 01488 } 01489 01490 #undef st_hash_start 01491 st_index_t 01492 st_hash_start(st_index_t h) 01493 { 01494 return h; 01495 } 01496 01497 static st_index_t 01498 strhash(st_data_t arg) 01499 { 01500 register const char *string = (const char *)arg; 01501 return st_hash(string, strlen(string), FNV1_32A_INIT); 01502 } 01503 #endif 01504 01505 int 01506 st_strcasecmp(const char *s1, const char *s2) 01507 { 01508 unsigned int c1, c2; 01509 01510 while (1) { 01511 c1 = (unsigned char)*s1++; 01512 c2 = (unsigned char)*s2++; 01513 if (c1 == '\0' || c2 == '\0') { 01514 if (c1 != '\0') return 1; 01515 if (c2 != '\0') return -1; 01516 return 0; 01517 } 01518 if ((unsigned int)(c1 - 'A') <= ('Z' - 'A')) c1 += 'a' - 'A'; 01519 if ((unsigned int)(c2 - 'A') <= ('Z' - 'A')) c2 += 'a' - 'A'; 01520 if (c1 != c2) { 01521 if (c1 > c2) 01522 return 1; 01523 else 01524 return -1; 01525 } 01526 } 01527 } 01528 01529 int 01530 st_strncasecmp(const char *s1, const char *s2, size_t n) 01531 { 01532 unsigned int c1, c2; 01533 01534 while (n--) { 01535 c1 = (unsigned char)*s1++; 01536 c2 = (unsigned char)*s2++; 01537 if (c1 == '\0' || c2 == '\0') { 01538 if (c1 != '\0') return 1; 01539 if (c2 != '\0') return -1; 01540 return 0; 01541 } 01542 if ((unsigned int)(c1 - 'A') <= ('Z' - 'A')) c1 += 'a' - 'A'; 01543 if ((unsigned int)(c2 - 'A') <= ('Z' - 'A')) c2 += 'a' - 'A'; 01544 if (c1 != c2) { 01545 if (c1 > c2) 01546 return 1; 01547 else 01548 return -1; 01549 } 01550 } 01551 return 0; 01552 } 01553 01554 static st_index_t 01555 strcasehash(st_data_t arg) 01556 { 01557 register const char *string = (const char *)arg; 01558 register st_index_t hval = FNV1_32A_INIT; 01559 01560 /* 01561 * FNV-1a hash each octet in the buffer 01562 */ 01563 while (*string) { 01564 unsigned int c = (unsigned char)*string++; 01565 if ((unsigned int)(c - 'A') <= ('Z' - 'A')) c += 'a' - 'A'; 01566 hval ^= c; 01567 01568 /* multiply by the 32 bit FNV magic prime mod 2^32 */ 01569 hval *= FNV_32_PRIME; 01570 } 01571 return hval; 01572 } 01573 01574 int 01575 st_numcmp(st_data_t x, st_data_t y) 01576 { 01577 return x != y; 01578 } 01579 01580 st_index_t 01581 st_numhash(st_data_t n) 01582 { 01583 return (st_index_t)n; 01584 } 01585
1.7.6.1