Annotation of embedaddon/php/ext/mbstring/oniguruma/st.c, revision 1.1
1.1 ! misho 1: /* This is a public domain general purpose hash table package written by Peter Moore @ UCB. */
! 2:
! 3: /* static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */
! 4:
! 5: #include "config.h"
! 6: #include <stdio.h>
! 7: #include <stdlib.h>
! 8: #include <string.h>
! 9:
! 10: #ifdef _WIN32
! 11: #include <malloc.h>
! 12: #endif
! 13:
! 14: #ifdef NOT_RUBY
! 15: #include "regint.h"
! 16: #else
! 17: #ifdef RUBY_PLATFORM
! 18: #define xmalloc ruby_xmalloc
! 19: #define xcalloc ruby_xcalloc
! 20: #define xrealloc ruby_xrealloc
! 21: #define xfree ruby_xfree
! 22:
! 23: void *xmalloc(long);
! 24: void *xcalloc(long, long);
! 25: void *xrealloc(void *, long);
! 26: void xfree(void *);
! 27: #endif
! 28: #endif
! 29:
! 30: #include "st.h"
! 31:
! 32: typedef struct st_table_entry st_table_entry;
! 33:
! 34: struct st_table_entry {
! 35: unsigned int hash;
! 36: st_data_t key;
! 37: st_data_t record;
! 38: st_table_entry *next;
! 39: };
! 40:
! 41: #define ST_DEFAULT_MAX_DENSITY 5
! 42: #define ST_DEFAULT_INIT_TABLE_SIZE 11
! 43:
! 44: /*
! 45: * DEFAULT_MAX_DENSITY is the default for the largest we allow the
! 46: * average number of items per bin before increasing the number of
! 47: * bins
! 48: *
! 49: * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins
! 50: * allocated initially
! 51: *
! 52: */
! 53:
! 54: static int numcmp(long, long);
! 55: static int numhash(long);
! 56: static struct st_hash_type type_numhash = {
! 57: numcmp,
! 58: numhash,
! 59: };
! 60:
! 61: /* extern int strcmp(const char *, const char *); */
! 62: static int strhash(const char *);
! 63: static struct st_hash_type type_strhash = {
! 64: strcmp,
! 65: strhash,
! 66: };
! 67:
! 68: static void rehash(st_table *);
! 69:
! 70: #define alloc(type) (type*)xmalloc((unsigned)sizeof(type))
! 71: #define Calloc(n,s) (char*)xcalloc((n),(s))
! 72:
! 73: #define EQUAL(table,x,y) ((x)==(y) || (*table->type->compare)((x),(y)) == 0)
! 74:
! 75: #define do_hash(key,table) (unsigned int)(*(table)->type->hash)((key))
! 76: #define do_hash_bin(key,table) (do_hash(key, table)%(table)->num_bins)
! 77:
! 78: /*
! 79: * MINSIZE is the minimum size of a dictionary.
! 80: */
! 81:
! 82: #define MINSIZE 8
! 83:
! 84: /*
! 85: Table of prime numbers 2^n+a, 2<=n<=30.
! 86: */
! 87: static const long primes[] = {
! 88: 8 + 3,
! 89: 16 + 3,
! 90: 32 + 5,
! 91: 64 + 3,
! 92: 128 + 3,
! 93: 256 + 27,
! 94: 512 + 9,
! 95: 1024 + 9,
! 96: 2048 + 5,
! 97: 4096 + 3,
! 98: 8192 + 27,
! 99: 16384 + 43,
! 100: 32768 + 3,
! 101: 65536 + 45,
! 102: 131072 + 29,
! 103: 262144 + 3,
! 104: 524288 + 21,
! 105: 1048576 + 7,
! 106: 2097152 + 17,
! 107: 4194304 + 15,
! 108: 8388608 + 9,
! 109: 16777216 + 43,
! 110: 33554432 + 35,
! 111: 67108864 + 15,
! 112: 134217728 + 29,
! 113: 268435456 + 3,
! 114: 536870912 + 11,
! 115: 1073741824 + 85,
! 116: 0
! 117: };
! 118:
! 119: static int
! 120: new_size(size)
! 121: int size;
! 122: {
! 123: int i;
! 124:
! 125: #if 0
! 126: for (i=3; i<31; i++) {
! 127: if ((1<<i) > size) return 1<<i;
! 128: }
! 129: return -1;
! 130: #else
! 131: int newsize;
! 132:
! 133: for (i = 0, newsize = MINSIZE;
! 134: i < (int )(sizeof(primes)/sizeof(primes[0]));
! 135: i++, newsize <<= 1)
! 136: {
! 137: if (newsize > size) return primes[i];
! 138: }
! 139: /* Ran out of polynomials */
! 140: return -1; /* should raise exception */
! 141: #endif
! 142: }
! 143:
! 144: #ifdef HASH_LOG
! 145: static int collision = 0;
! 146: static int init_st = 0;
! 147:
! 148: static void
! 149: stat_col()
! 150: {
! 151: FILE *f = fopen("/tmp/col", "w");
! 152: fprintf(f, "collision: %d\n", collision);
! 153: fclose(f);
! 154: }
! 155: #endif
! 156:
! 157: st_table*
! 158: st_init_table_with_size(type, size)
! 159: struct st_hash_type *type;
! 160: int size;
! 161: {
! 162: st_table *tbl;
! 163:
! 164: #ifdef HASH_LOG
! 165: if (init_st == 0) {
! 166: init_st = 1;
! 167: atexit(stat_col);
! 168: }
! 169: #endif
! 170:
! 171: size = new_size(size); /* round up to prime number */
! 172:
! 173: tbl = alloc(st_table);
! 174: tbl->type = type;
! 175: tbl->num_entries = 0;
! 176: tbl->num_bins = size;
! 177: tbl->bins = (st_table_entry **)Calloc(size, sizeof(st_table_entry*));
! 178:
! 179: return tbl;
! 180: }
! 181:
! 182: st_table*
! 183: st_init_table(type)
! 184: struct st_hash_type *type;
! 185: {
! 186: return st_init_table_with_size(type, 0);
! 187: }
! 188:
! 189: st_table*
! 190: st_init_numtable(void)
! 191: {
! 192: return st_init_table(&type_numhash);
! 193: }
! 194:
! 195: st_table*
! 196: st_init_numtable_with_size(size)
! 197: int size;
! 198: {
! 199: return st_init_table_with_size(&type_numhash, size);
! 200: }
! 201:
! 202: st_table*
! 203: st_init_strtable(void)
! 204: {
! 205: return st_init_table(&type_strhash);
! 206: }
! 207:
! 208: st_table*
! 209: st_init_strtable_with_size(size)
! 210: int size;
! 211: {
! 212: return st_init_table_with_size(&type_strhash, size);
! 213: }
! 214:
! 215: void
! 216: st_free_table(table)
! 217: st_table *table;
! 218: {
! 219: register st_table_entry *ptr, *next;
! 220: int i;
! 221:
! 222: for(i = 0; i < table->num_bins; i++) {
! 223: ptr = table->bins[i];
! 224: while (ptr != 0) {
! 225: next = ptr->next;
! 226: free(ptr);
! 227: ptr = next;
! 228: }
! 229: }
! 230: free(table->bins);
! 231: free(table);
! 232: }
! 233:
! 234: #define PTR_NOT_EQUAL(table, ptr, hash_val, key) \
! 235: ((ptr) != 0 && (ptr->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key)))
! 236:
! 237: #ifdef HASH_LOG
! 238: #define COLLISION collision++
! 239: #else
! 240: #define COLLISION
! 241: #endif
! 242:
! 243: #define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\
! 244: bin_pos = hash_val%(table)->num_bins;\
! 245: ptr = (table)->bins[bin_pos];\
! 246: if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {\
! 247: COLLISION;\
! 248: while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\
! 249: ptr = ptr->next;\
! 250: }\
! 251: ptr = ptr->next;\
! 252: }\
! 253: } while (0)
! 254:
! 255: int
! 256: st_lookup(table, key, value)
! 257: st_table *table;
! 258: register st_data_t key;
! 259: st_data_t *value;
! 260: {
! 261: unsigned int hash_val, bin_pos;
! 262: register st_table_entry *ptr;
! 263:
! 264: hash_val = do_hash(key, table);
! 265: FIND_ENTRY(table, ptr, hash_val, bin_pos);
! 266:
! 267: if (ptr == 0) {
! 268: return 0;
! 269: }
! 270: else {
! 271: if (value != 0) *value = ptr->record;
! 272: return 1;
! 273: }
! 274: }
! 275:
! 276: #define ADD_DIRECT(table, key, value, hash_val, bin_pos)\
! 277: do {\
! 278: st_table_entry *entry;\
! 279: if (table->num_entries/(table->num_bins) > ST_DEFAULT_MAX_DENSITY) {\
! 280: rehash(table);\
! 281: bin_pos = hash_val % table->num_bins;\
! 282: }\
! 283: \
! 284: entry = alloc(st_table_entry);\
! 285: \
! 286: entry->hash = hash_val;\
! 287: entry->key = key;\
! 288: entry->record = value;\
! 289: entry->next = table->bins[bin_pos];\
! 290: table->bins[bin_pos] = entry;\
! 291: table->num_entries++;\
! 292: } while (0)
! 293:
! 294: int
! 295: st_insert(table, key, value)
! 296: register st_table *table;
! 297: register st_data_t key;
! 298: st_data_t value;
! 299: {
! 300: unsigned int hash_val, bin_pos;
! 301: register st_table_entry *ptr;
! 302:
! 303: hash_val = do_hash(key, table);
! 304: FIND_ENTRY(table, ptr, hash_val, bin_pos);
! 305:
! 306: if (ptr == 0) {
! 307: ADD_DIRECT(table, key, value, hash_val, bin_pos);
! 308: return 0;
! 309: }
! 310: else {
! 311: ptr->record = value;
! 312: return 1;
! 313: }
! 314: }
! 315:
! 316: void
! 317: st_add_direct(table, key, value)
! 318: st_table *table;
! 319: st_data_t key;
! 320: st_data_t value;
! 321: {
! 322: unsigned int hash_val, bin_pos;
! 323:
! 324: hash_val = do_hash(key, table);
! 325: bin_pos = hash_val % table->num_bins;
! 326: ADD_DIRECT(table, key, value, hash_val, bin_pos);
! 327: }
! 328:
! 329: static void
! 330: rehash(table)
! 331: register st_table *table;
! 332: {
! 333: register st_table_entry *ptr, *next, **new_bins;
! 334: int i, old_num_bins = table->num_bins, new_num_bins;
! 335: unsigned int hash_val;
! 336:
! 337: new_num_bins = new_size(old_num_bins+1);
! 338: new_bins = (st_table_entry**)Calloc(new_num_bins, sizeof(st_table_entry*));
! 339:
! 340: for(i = 0; i < old_num_bins; i++) {
! 341: ptr = table->bins[i];
! 342: while (ptr != 0) {
! 343: next = ptr->next;
! 344: hash_val = ptr->hash % new_num_bins;
! 345: ptr->next = new_bins[hash_val];
! 346: new_bins[hash_val] = ptr;
! 347: ptr = next;
! 348: }
! 349: }
! 350: free(table->bins);
! 351: table->num_bins = new_num_bins;
! 352: table->bins = new_bins;
! 353: }
! 354:
! 355: st_table*
! 356: st_copy(old_table)
! 357: st_table *old_table;
! 358: {
! 359: st_table *new_table;
! 360: st_table_entry *ptr, *entry;
! 361: int i, num_bins = old_table->num_bins;
! 362:
! 363: new_table = alloc(st_table);
! 364: if (new_table == 0) {
! 365: return 0;
! 366: }
! 367:
! 368: *new_table = *old_table;
! 369: new_table->bins = (st_table_entry**)
! 370: Calloc((unsigned)num_bins, sizeof(st_table_entry*));
! 371:
! 372: if (new_table->bins == 0) {
! 373: free(new_table);
! 374: return 0;
! 375: }
! 376:
! 377: for(i = 0; i < num_bins; i++) {
! 378: new_table->bins[i] = 0;
! 379: ptr = old_table->bins[i];
! 380: while (ptr != 0) {
! 381: entry = alloc(st_table_entry);
! 382: if (entry == 0) {
! 383: free(new_table->bins);
! 384: free(new_table);
! 385: return 0;
! 386: }
! 387: *entry = *ptr;
! 388: entry->next = new_table->bins[i];
! 389: new_table->bins[i] = entry;
! 390: ptr = ptr->next;
! 391: }
! 392: }
! 393: return new_table;
! 394: }
! 395:
! 396: int
! 397: st_delete(table, key, value)
! 398: register st_table *table;
! 399: register st_data_t *key;
! 400: st_data_t *value;
! 401: {
! 402: unsigned int hash_val;
! 403: st_table_entry *tmp;
! 404: register st_table_entry *ptr;
! 405:
! 406: hash_val = do_hash_bin(*key, table);
! 407: ptr = table->bins[hash_val];
! 408:
! 409: if (ptr == 0) {
! 410: if (value != 0) *value = 0;
! 411: return 0;
! 412: }
! 413:
! 414: if (EQUAL(table, *key, ptr->key)) {
! 415: table->bins[hash_val] = ptr->next;
! 416: table->num_entries--;
! 417: if (value != 0) *value = ptr->record;
! 418: *key = ptr->key;
! 419: free(ptr);
! 420: return 1;
! 421: }
! 422:
! 423: for(; ptr->next != 0; ptr = ptr->next) {
! 424: if (EQUAL(table, ptr->next->key, *key)) {
! 425: tmp = ptr->next;
! 426: ptr->next = ptr->next->next;
! 427: table->num_entries--;
! 428: if (value != 0) *value = tmp->record;
! 429: *key = tmp->key;
! 430: free(tmp);
! 431: return 1;
! 432: }
! 433: }
! 434:
! 435: return 0;
! 436: }
! 437:
! 438: int
! 439: st_delete_safe(table, key, value, never)
! 440: register st_table *table;
! 441: register st_data_t *key;
! 442: st_data_t *value;
! 443: st_data_t never;
! 444: {
! 445: unsigned int hash_val;
! 446: register st_table_entry *ptr;
! 447:
! 448: hash_val = do_hash_bin(*key, table);
! 449: ptr = table->bins[hash_val];
! 450:
! 451: if (ptr == 0) {
! 452: if (value != 0) *value = 0;
! 453: return 0;
! 454: }
! 455:
! 456: for(; ptr != 0; ptr = ptr->next) {
! 457: if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) {
! 458: table->num_entries--;
! 459: *key = ptr->key;
! 460: if (value != 0) *value = ptr->record;
! 461: ptr->key = ptr->record = never;
! 462: return 1;
! 463: }
! 464: }
! 465:
! 466: return 0;
! 467: }
! 468:
! 469: static int
! 470: delete_never(key, value, never)
! 471: st_data_t key, value, never;
! 472: {
! 473: if (value == never) return ST_DELETE;
! 474: return ST_CONTINUE;
! 475: }
! 476:
! 477: void
! 478: st_cleanup_safe(table, never)
! 479: st_table *table;
! 480: st_data_t never;
! 481: {
! 482: int num_entries = table->num_entries;
! 483:
! 484: st_foreach(table, delete_never, never);
! 485: table->num_entries = num_entries;
! 486: }
! 487:
! 488: int
! 489: st_foreach(table, func, arg)
! 490: st_table *table;
! 491: int (*func)();
! 492: st_data_t arg;
! 493: {
! 494: st_table_entry *ptr, *last, *tmp;
! 495: enum st_retval retval;
! 496: int i;
! 497:
! 498: for(i = 0; i < table->num_bins; i++) {
! 499: last = 0;
! 500: for(ptr = table->bins[i]; ptr != 0;) {
! 501: retval = (*func)(ptr->key, ptr->record, arg);
! 502: switch (retval) {
! 503: case ST_CHECK: /* check if hash is modified during iteration */
! 504: tmp = 0;
! 505: if (i < table->num_bins) {
! 506: for (tmp = table->bins[i]; tmp; tmp=tmp->next) {
! 507: if (tmp == ptr) break;
! 508: }
! 509: }
! 510: if (!tmp) {
! 511: /* call func with error notice */
! 512: return 1;
! 513: }
! 514: /* fall through */
! 515: case ST_CONTINUE:
! 516: last = ptr;
! 517: ptr = ptr->next;
! 518: break;
! 519: case ST_STOP:
! 520: return 0;
! 521: case ST_DELETE:
! 522: tmp = ptr;
! 523: if (last == 0) {
! 524: table->bins[i] = ptr->next;
! 525: }
! 526: else {
! 527: last->next = ptr->next;
! 528: }
! 529: ptr = ptr->next;
! 530: free(tmp);
! 531: table->num_entries--;
! 532: }
! 533: }
! 534: }
! 535: return 0;
! 536: }
! 537:
! 538: static int
! 539: strhash(string)
! 540: register const char *string;
! 541: {
! 542: register int c;
! 543:
! 544: #ifdef HASH_ELFHASH
! 545: register unsigned int h = 0, g;
! 546:
! 547: while ((c = *string++) != '\0') {
! 548: h = ( h << 4 ) + c;
! 549: if ( g = h & 0xF0000000 )
! 550: h ^= g >> 24;
! 551: h &= ~g;
! 552: }
! 553: return h;
! 554: #elif HASH_PERL
! 555: register int val = 0;
! 556:
! 557: while ((c = *string++) != '\0') {
! 558: val += c;
! 559: val += (val << 10);
! 560: val ^= (val >> 6);
! 561: }
! 562: val += (val << 3);
! 563: val ^= (val >> 11);
! 564:
! 565: return val + (val << 15);
! 566: #else
! 567: register int val = 0;
! 568:
! 569: while ((c = *string++) != '\0') {
! 570: val = val*997 + c;
! 571: }
! 572:
! 573: return val + (val>>5);
! 574: #endif
! 575: }
! 576:
! 577: static int
! 578: numcmp(x, y)
! 579: long x, y;
! 580: {
! 581: return x != y;
! 582: }
! 583:
! 584: static int
! 585: numhash(n)
! 586: long n;
! 587: {
! 588: return n;
! 589: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>