|
Ruby 1.9.2p290(2011-07-09revision32553)
|
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 #define ST_DEFAULT_MAX_DENSITY 5 00029 #define ST_DEFAULT_INIT_TABLE_SIZE 11 00030 00031 /* 00032 * DEFAULT_MAX_DENSITY is the default for the largest we allow the 00033 * average number of items per bin before increasing the number of 00034 * bins 00035 * 00036 * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins 00037 * allocated initially 00038 * 00039 */ 00040 00041 static const struct st_hash_type type_numhash = { 00042 st_numcmp, 00043 st_numhash, 00044 }; 00045 00046 /* extern int strcmp(const char *, const char *); */ 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 /* remove cast to unsigned int in the future */ 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 * MINSIZE is the minimum size of a dictionary. 00080 */ 00081 00082 #define MINSIZE 8 00083 00084 /* 00085 Table of prime numbers 2^n+a, 2<=n<=30. 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 /* Ran out of polynomials */ 00136 #ifndef NOT_RUBY 00137 rb_raise(rb_eRuntimeError, "st_table too big"); 00138 #endif 00139 return -1; /* should raise exception */ 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); /* round up to prime number */ 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 int 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 void 00699 st_cleanup_safe(st_table *table, st_data_t never) 00700 { 00701 st_table_entry *ptr, **last, *tmp; 00702 st_index_t i; 00703 00704 if (table->entries_packed) { 00705 st_index_t i = 0, j = 0; 00706 while ((st_data_t)table->bins[i*2] != never) { 00707 if (i++ == table->num_entries) return; 00708 } 00709 for (j = i; ++i < table->num_entries;) { 00710 if ((st_data_t)table->bins[i*2] == never) continue; 00711 table->bins[j*2] = table->bins[i*2]; 00712 table->bins[j*2+1] = table->bins[i*2+1]; 00713 j++; 00714 } 00715 table->num_entries = j; 00716 return; 00717 } 00718 00719 for (i = 0; i < table->num_bins; i++) { 00720 ptr = *(last = &table->bins[i]); 00721 while (ptr != 0) { 00722 if (ptr->key == never) { 00723 tmp = ptr; 00724 *last = ptr = ptr->next; 00725 free(tmp); 00726 } 00727 else { 00728 ptr = *(last = &ptr->next); 00729 } 00730 } 00731 } 00732 } 00733 00734 int 00735 st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg) 00736 { 00737 st_table_entry *ptr, **last, *tmp; 00738 enum st_retval retval; 00739 st_index_t i; 00740 00741 if (table->entries_packed) { 00742 for (i = 0; i < table->num_entries; i++) { 00743 st_index_t j; 00744 st_data_t key, val; 00745 key = (st_data_t)table->bins[i*2]; 00746 val = (st_data_t)table->bins[i*2+1]; 00747 retval = (*func)(key, val, arg); 00748 switch (retval) { 00749 case ST_CHECK: /* check if hash is modified during iteration */ 00750 for (j = 0; j < table->num_entries; j++) { 00751 if ((st_data_t)table->bins[j*2] == key) 00752 break; 00753 } 00754 if (j == table->num_entries) { 00755 /* call func with error notice */ 00756 retval = (*func)(0, 0, arg, 1); 00757 return 1; 00758 } 00759 /* fall through */ 00760 case ST_CONTINUE: 00761 break; 00762 case ST_STOP: 00763 return 0; 00764 case ST_DELETE: 00765 table->num_entries--; 00766 memmove(&table->bins[i*2], &table->bins[(i+1)*2], 00767 sizeof(struct st_table_entry*) * 2*(table->num_entries-i)); 00768 i--; 00769 break; 00770 } 00771 } 00772 return 0; 00773 } 00774 00775 if ((ptr = table->head) != 0) { 00776 do { 00777 i = ptr->hash % table->num_bins; 00778 retval = (*func)(ptr->key, ptr->record, arg); 00779 switch (retval) { 00780 case ST_CHECK: /* check if hash is modified during iteration */ 00781 for (tmp = table->bins[i]; tmp != ptr; tmp = tmp->next) { 00782 if (!tmp) { 00783 /* call func with error notice */ 00784 retval = (*func)(0, 0, arg, 1); 00785 return 1; 00786 } 00787 } 00788 /* fall through */ 00789 case ST_CONTINUE: 00790 ptr = ptr->fore; 00791 break; 00792 case ST_STOP: 00793 return 0; 00794 case ST_DELETE: 00795 last = &table->bins[ptr->hash % table->num_bins]; 00796 for (; (tmp = *last) != 0; last = &tmp->next) { 00797 if (ptr == tmp) { 00798 tmp = ptr->fore; 00799 *last = ptr->next; 00800 REMOVE_ENTRY(table, ptr); 00801 free(ptr); 00802 if (ptr == tmp) return 0; 00803 ptr = tmp; 00804 break; 00805 } 00806 } 00807 } 00808 } while (ptr && table->head); 00809 } 00810 return 0; 00811 } 00812 00813 #if 0 /* unused right now */ 00814 int 00815 st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg) 00816 { 00817 st_table_entry *ptr, **last, *tmp; 00818 enum st_retval retval; 00819 int i; 00820 00821 if (table->entries_packed) { 00822 for (i = table->num_entries-1; 0 <= i; i--) { 00823 int j; 00824 st_data_t key, val; 00825 key = (st_data_t)table->bins[i*2]; 00826 val = (st_data_t)table->bins[i*2+1]; 00827 retval = (*func)(key, val, arg); 00828 switch (retval) { 00829 case ST_CHECK: /* check if hash is modified during iteration */ 00830 for (j = 0; j < table->num_entries; j++) { 00831 if ((st_data_t)table->bins[j*2] == key) 00832 break; 00833 } 00834 if (j == table->num_entries) { 00835 /* call func with error notice */ 00836 retval = (*func)(0, 0, arg, 1); 00837 return 1; 00838 } 00839 /* fall through */ 00840 case ST_CONTINUE: 00841 break; 00842 case ST_STOP: 00843 return 0; 00844 case ST_DELETE: 00845 table->num_entries--; 00846 memmove(&table->bins[i*2], &table->bins[(i+1)*2], 00847 sizeof(struct st_table_entry*) * 2*(table->num_entries-i)); 00848 break; 00849 } 00850 } 00851 return 0; 00852 } 00853 00854 if ((ptr = table->head) != 0) { 00855 ptr = ptr->back; 00856 do { 00857 retval = (*func)(ptr->key, ptr->record, arg, 0); 00858 switch (retval) { 00859 case ST_CHECK: /* check if hash is modified during iteration */ 00860 i = ptr->hash % table->num_bins; 00861 for (tmp = table->bins[i]; tmp != ptr; tmp = tmp->next) { 00862 if (!tmp) { 00863 /* call func with error notice */ 00864 retval = (*func)(0, 0, arg, 1); 00865 return 1; 00866 } 00867 } 00868 /* fall through */ 00869 case ST_CONTINUE: 00870 ptr = ptr->back; 00871 break; 00872 case ST_STOP: 00873 return 0; 00874 case ST_DELETE: 00875 last = &table->bins[ptr->hash % table->num_bins]; 00876 for (; (tmp = *last) != 0; last = &tmp->next) { 00877 if (ptr == tmp) { 00878 tmp = ptr->back; 00879 *last = ptr->next; 00880 REMOVE_ENTRY(table, ptr); 00881 free(ptr); 00882 ptr = tmp; 00883 break; 00884 } 00885 } 00886 ptr = ptr->next; 00887 free(tmp); 00888 table->num_entries--; 00889 } 00890 } while (ptr && table->head); 00891 } 00892 return 0; 00893 } 00894 #endif 00895 00896 /* 00897 * hash_32 - 32 bit Fowler/Noll/Vo FNV-1a hash code 00898 * 00899 * @(#) $Hash32: Revision: 1.1 $ 00900 * @(#) $Hash32: Id: hash_32a.c,v 1.1 2003/10/03 20:38:53 chongo Exp $ 00901 * @(#) $Hash32: Source: /usr/local/src/cmd/fnv/RCS/hash_32a.c,v $ 00902 * 00903 *** 00904 * 00905 * Fowler/Noll/Vo hash 00906 * 00907 * The basis of this hash algorithm was taken from an idea sent 00908 * as reviewer comments to the IEEE POSIX P1003.2 committee by: 00909 * 00910 * Phong Vo (http://www.research.att.com/info/kpv/) 00911 * Glenn Fowler (http://www.research.att.com/~gsf/) 00912 * 00913 * In a subsequent ballot round: 00914 * 00915 * Landon Curt Noll (http://www.isthe.com/chongo/) 00916 * 00917 * improved on their algorithm. Some people tried this hash 00918 * and found that it worked rather well. In an EMail message 00919 * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. 00920 * 00921 * FNV hashes are designed to be fast while maintaining a low 00922 * collision rate. The FNV speed allows one to quickly hash lots 00923 * of data while maintaining a reasonable collision rate. See: 00924 * 00925 * http://www.isthe.com/chongo/tech/comp/fnv/index.html 00926 * 00927 * for more details as well as other forms of the FNV hash. 00928 *** 00929 * 00930 * To use the recommended 32 bit FNV-1a hash, pass FNV1_32A_INIT as the 00931 * Fnv32_t hashval argument to fnv_32a_buf() or fnv_32a_str(). 00932 * 00933 *** 00934 * 00935 * Please do not copyright this code. This code is in the public domain. 00936 * 00937 * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 00938 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO 00939 * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR 00940 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 00941 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 00942 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00943 * PERFORMANCE OF THIS SOFTWARE. 00944 * 00945 * By: 00946 * chongo <Landon Curt Noll> /\oo/\ 00947 * http://www.isthe.com/chongo/ 00948 * 00949 * Share and Enjoy! :-) 00950 */ 00951 00952 /* 00953 * 32 bit FNV-1 and FNV-1a non-zero initial basis 00954 * 00955 * The FNV-1 initial basis is the FNV-0 hash of the following 32 octets: 00956 * 00957 * chongo <Landon Curt Noll> /\../\ 00958 * 00959 * NOTE: The \'s above are not back-slashing escape characters. 00960 * They are literal ASCII backslash 0x5c characters. 00961 * 00962 * NOTE: The FNV-1a initial basis is the same value as FNV-1 by definition. 00963 */ 00964 #define FNV1_32A_INIT 0x811c9dc5 00965 00966 /* 00967 * 32 bit magic FNV-1a prime 00968 */ 00969 #define FNV_32_PRIME 0x01000193 00970 00971 #ifdef ST_USE_FNV1 00972 static st_index_t 00973 strhash(st_data_t arg) 00974 { 00975 register const char *string = (const char *)arg; 00976 register st_index_t hval = FNV1_32A_INIT; 00977 00978 /* 00979 * FNV-1a hash each octet in the buffer 00980 */ 00981 while (*string) { 00982 /* xor the bottom with the current octet */ 00983 hval ^= (unsigned int)*string++; 00984 00985 /* multiply by the 32 bit FNV magic prime mod 2^32 */ 00986 hval *= FNV_32_PRIME; 00987 } 00988 return hval; 00989 } 00990 #else 00991 00992 #ifndef UNALIGNED_WORD_ACCESS 00993 # if defined __i386__ || defined _M_IX86 00994 # define UNALIGNED_WORD_ACCESS 1 00995 # endif 00996 #endif 00997 #ifndef UNALIGNED_WORD_ACCESS 00998 # define UNALIGNED_WORD_ACCESS 0 00999 #endif 01000 01001 /* MurmurHash described in http://murmurhash.googlepages.com/ */ 01002 #ifndef MURMUR 01003 #define MURMUR 2 01004 #endif 01005 01006 #if MURMUR == 1 01007 #define MurmurMagic 0xc6a4a793 01008 #elif MURMUR == 2 01009 #if SIZEOF_ST_INDEX_T > 4 01010 #define MurmurMagic 0xc6a4a7935bd1e995 01011 #else 01012 #define MurmurMagic 0x5bd1e995 01013 #endif 01014 #endif 01015 01016 static inline st_index_t 01017 murmur(st_index_t h, st_index_t k, int r) 01018 { 01019 const st_index_t m = MurmurMagic; 01020 #if MURMUR == 1 01021 h += k; 01022 h *= m; 01023 h ^= h >> r; 01024 #elif MURMUR == 2 01025 k *= m; 01026 k ^= k >> r; 01027 k *= m; 01028 01029 h *= m; 01030 h ^= k; 01031 #endif 01032 return h; 01033 } 01034 01035 static inline st_index_t 01036 murmur_finish(st_index_t h) 01037 { 01038 #if MURMUR == 1 01039 h = murmur(h, 0, 10); 01040 h = murmur(h, 0, 17); 01041 #elif MURMUR == 2 01042 h ^= h >> 13; 01043 h *= MurmurMagic; 01044 h ^= h >> 15; 01045 #endif 01046 return h; 01047 } 01048 01049 #define murmur_step(h, k) murmur(h, k, 16) 01050 01051 #if MURMUR == 1 01052 #define murmur1(h) murmur_step(h, 16) 01053 #else 01054 #define murmur1(h) murmur_step(h, 24) 01055 #endif 01056 01057 st_index_t 01058 st_hash(const void *ptr, size_t len, st_index_t h) 01059 { 01060 const char *data = ptr; 01061 st_index_t t = 0; 01062 01063 h += 0xdeadbeef; 01064 01065 #define data_at(n) (st_index_t)((unsigned char)data[n]) 01066 #define UNALIGNED_ADD_4 UNALIGNED_ADD(2); UNALIGNED_ADD(1); UNALIGNED_ADD(0) 01067 #if SIZEOF_ST_INDEX_T > 4 01068 #define UNALIGNED_ADD_8 UNALIGNED_ADD(6); UNALIGNED_ADD(5); UNALIGNED_ADD(4); UNALIGNED_ADD(3); UNALIGNED_ADD_4 01069 #if SIZEOF_ST_INDEX_T > 8 01070 #define UNALIGNED_ADD_16 UNALIGNED_ADD(14); UNALIGNED_ADD(13); UNALIGNED_ADD(12); UNALIGNED_ADD(11); \ 01071 UNALIGNED_ADD(10); UNALIGNED_ADD(9); UNALIGNED_ADD(8); UNALIGNED_ADD(7); UNALIGNED_ADD_8 01072 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_16 01073 #endif 01074 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_8 01075 #else 01076 #define UNALIGNED_ADD_ALL UNALIGNED_ADD_4 01077 #endif 01078 if (len >= sizeof(st_index_t)) { 01079 #if !UNALIGNED_WORD_ACCESS 01080 int align = (int)((st_data_t)data % sizeof(st_index_t)); 01081 if (align) { 01082 st_index_t d = 0; 01083 int sl, sr, pack; 01084 01085 switch (align) { 01086 #ifdef WORDS_BIGENDIAN 01087 # define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \ 01088 t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 2) 01089 #else 01090 # define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \ 01091 t |= data_at(n) << CHAR_BIT*(n) 01092 #endif 01093 UNALIGNED_ADD_ALL; 01094 #undef UNALIGNED_ADD 01095 } 01096 01097 #ifdef WORDS_BIGENDIAN 01098 t >>= (CHAR_BIT * align) - CHAR_BIT; 01099 #else 01100 t <<= (CHAR_BIT * align); 01101 #endif 01102 01103 data += sizeof(st_index_t)-align; 01104 len -= sizeof(st_index_t)-align; 01105 01106 sl = CHAR_BIT * (SIZEOF_ST_INDEX_T-align); 01107 sr = CHAR_BIT * align; 01108 01109 while (len >= sizeof(st_index_t)) { 01110 d = *(st_index_t *)data; 01111 #ifdef WORDS_BIGENDIAN 01112 t = (t << sr) | (d >> sl); 01113 #else 01114 t = (t >> sr) | (d << sl); 01115 #endif 01116 h = murmur_step(h, t); 01117 t = d; 01118 data += sizeof(st_index_t); 01119 len -= sizeof(st_index_t); 01120 } 01121 01122 pack = len < (size_t)align ? (int)len : align; 01123 d = 0; 01124 switch (pack) { 01125 #ifdef WORDS_BIGENDIAN 01126 # define UNALIGNED_ADD(n) case (n) + 1: \ 01127 d |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1) 01128 #else 01129 # define UNALIGNED_ADD(n) case (n) + 1: \ 01130 d |= data_at(n) << CHAR_BIT*(n) 01131 #endif 01132 UNALIGNED_ADD_ALL; 01133 #undef UNALIGNED_ADD 01134 } 01135 #ifdef WORDS_BIGENDIAN 01136 t = (t << sr) | (d >> sl); 01137 #else 01138 t = (t >> sr) | (d << sl); 01139 #endif 01140 01141 #if MURMUR == 2 01142 if (len < (size_t)align) goto skip_tail; 01143 #endif 01144 h = murmur_step(h, t); 01145 data += pack; 01146 len -= pack; 01147 } 01148 else 01149 #endif 01150 { 01151 do { 01152 h = murmur_step(h, *(st_index_t *)data); 01153 data += sizeof(st_index_t); 01154 len -= sizeof(st_index_t); 01155 } while (len >= sizeof(st_index_t)); 01156 } 01157 } 01158 01159 t = 0; 01160 switch (len) { 01161 #ifdef WORDS_BIGENDIAN 01162 # define UNALIGNED_ADD(n) case (n) + 1: \ 01163 t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1) 01164 #else 01165 # define UNALIGNED_ADD(n) case (n) + 1: \ 01166 t |= data_at(n) << CHAR_BIT*(n) 01167 #endif 01168 UNALIGNED_ADD_ALL; 01169 #undef UNALIGNED_ADD 01170 #if MURMUR == 1 01171 h = murmur_step(h, t); 01172 #elif MURMUR == 2 01173 # if !UNALIGNED_WORD_ACCESS 01174 skip_tail: 01175 # endif 01176 h ^= t; 01177 h *= MurmurMagic; 01178 #endif 01179 } 01180 01181 return murmur_finish(h); 01182 } 01183 01184 st_index_t 01185 st_hash_uint32(st_index_t h, uint32_t i) 01186 { 01187 return murmur_step(h + i, 16); 01188 } 01189 01190 st_index_t 01191 st_hash_uint(st_index_t h, st_index_t i) 01192 { 01193 st_index_t v = 0; 01194 h += i; 01195 #ifdef WORDS_BIGENDIAN 01196 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8 01197 v = murmur1(v + (h >> 12*8)); 01198 #endif 01199 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8 01200 v = murmur1(v + (h >> 8*8)); 01201 #endif 01202 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8 01203 v = murmur1(v + (h >> 4*8)); 01204 #endif 01205 #endif 01206 v = murmur1(v + h); 01207 #ifndef WORDS_BIGENDIAN 01208 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8 01209 v = murmur1(v + (h >> 4*8)); 01210 #endif 01211 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8 01212 v = murmur1(v + (h >> 8*8)); 01213 #endif 01214 #if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8 01215 v = murmur1(v + (h >> 12*8)); 01216 #endif 01217 #endif 01218 return v; 01219 } 01220 01221 st_index_t 01222 st_hash_end(st_index_t h) 01223 { 01224 h = murmur_step(h, 10); 01225 h = murmur_step(h, 17); 01226 return h; 01227 } 01228 01229 #undef st_hash_start 01230 st_index_t 01231 st_hash_start(st_index_t h) 01232 { 01233 return h; 01234 } 01235 01236 static st_index_t 01237 strhash(st_data_t arg) 01238 { 01239 register const char *string = (const char *)arg; 01240 return st_hash(string, strlen(string), FNV1_32A_INIT); 01241 } 01242 #endif 01243 01244 int 01245 st_strcasecmp(const char *s1, const char *s2) 01246 { 01247 unsigned int c1, c2; 01248 01249 while (1) { 01250 c1 = (unsigned char)*s1++; 01251 c2 = (unsigned char)*s2++; 01252 if (c1 == '\0' || c2 == '\0') { 01253 if (c1 != '\0') return 1; 01254 if (c2 != '\0') return -1; 01255 return 0; 01256 } 01257 if ((unsigned int)(c1 - 'A') <= ('Z' - 'A')) c1 += 'a' - 'A'; 01258 if ((unsigned int)(c2 - 'A') <= ('Z' - 'A')) c2 += 'a' - 'A'; 01259 if (c1 != c2) { 01260 if (c1 > c2) 01261 return 1; 01262 else 01263 return -1; 01264 } 01265 } 01266 } 01267 01268 int 01269 st_strncasecmp(const char *s1, const char *s2, size_t n) 01270 { 01271 unsigned int c1, c2; 01272 01273 while (n--) { 01274 c1 = (unsigned char)*s1++; 01275 c2 = (unsigned char)*s2++; 01276 if (c1 == '\0' || c2 == '\0') { 01277 if (c1 != '\0') return 1; 01278 if (c2 != '\0') return -1; 01279 return 0; 01280 } 01281 if ((unsigned int)(c1 - 'A') <= ('Z' - 'A')) c1 += 'a' - 'A'; 01282 if ((unsigned int)(c2 - 'A') <= ('Z' - 'A')) c2 += 'a' - 'A'; 01283 if (c1 != c2) { 01284 if (c1 > c2) 01285 return 1; 01286 else 01287 return -1; 01288 } 01289 } 01290 return 0; 01291 } 01292 01293 static st_index_t 01294 strcasehash(st_data_t arg) 01295 { 01296 register const char *string = (const char *)arg; 01297 register st_index_t hval = FNV1_32A_INIT; 01298 01299 /* 01300 * FNV-1a hash each octet in the buffer 01301 */ 01302 while (*string) { 01303 unsigned int c = (unsigned char)*string++; 01304 if ((unsigned int)(c - 'A') <= ('Z' - 'A')) c += 'a' - 'A'; 01305 hval ^= c; 01306 01307 /* multiply by the 32 bit FNV magic prime mod 2^32 */ 01308 hval *= FNV_32_PRIME; 01309 } 01310 return hval; 01311 } 01312 01313 int 01314 st_numcmp(st_data_t x, st_data_t y) 01315 { 01316 return x != y; 01317 } 01318 01319 st_index_t 01320 st_numhash(st_data_t n) 01321 { 01322 return (st_index_t)n; 01323 } 01324
1.7.3