Annotation of embedaddon/libxml2/hash.c, revision 1.1
1.1 ! misho 1: /*
! 2: * hash.c: chained hash tables
! 3: *
! 4: * Reference: Your favorite introductory book on algorithms
! 5: *
! 6: * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
! 7: *
! 8: * Permission to use, copy, modify, and distribute this software for any
! 9: * purpose with or without fee is hereby granted, provided that the above
! 10: * copyright notice and this permission notice appear in all copies.
! 11: *
! 12: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
! 13: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
! 14: * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
! 15: * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
! 16: *
! 17: * Author: breese@users.sourceforge.net
! 18: */
! 19:
! 20: #define IN_LIBXML
! 21: #include "libxml.h"
! 22:
! 23: #include <string.h>
! 24: #include <libxml/parser.h>
! 25: #include <libxml/hash.h>
! 26: #include <libxml/xmlmemory.h>
! 27: #include <libxml/xmlerror.h>
! 28: #include <libxml/globals.h>
! 29:
! 30: #define MAX_HASH_LEN 8
! 31:
! 32: /* #define DEBUG_GROW */
! 33:
! 34: /*
! 35: * A single entry in the hash table
! 36: */
! 37: typedef struct _xmlHashEntry xmlHashEntry;
! 38: typedef xmlHashEntry *xmlHashEntryPtr;
! 39: struct _xmlHashEntry {
! 40: struct _xmlHashEntry *next;
! 41: xmlChar *name;
! 42: xmlChar *name2;
! 43: xmlChar *name3;
! 44: void *payload;
! 45: int valid;
! 46: };
! 47:
! 48: /*
! 49: * The entire hash table
! 50: */
! 51: struct _xmlHashTable {
! 52: struct _xmlHashEntry *table;
! 53: int size;
! 54: int nbElems;
! 55: xmlDictPtr dict;
! 56: };
! 57:
! 58: /*
! 59: * xmlHashComputeKey:
! 60: * Calculate the hash key
! 61: */
! 62: static unsigned long
! 63: xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
! 64: const xmlChar *name2, const xmlChar *name3) {
! 65: unsigned long value = 0L;
! 66: char ch;
! 67:
! 68: if (name != NULL) {
! 69: value += 30 * (*name);
! 70: while ((ch = *name++) != 0) {
! 71: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
! 72: }
! 73: }
! 74: if (name2 != NULL) {
! 75: while ((ch = *name2++) != 0) {
! 76: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
! 77: }
! 78: }
! 79: if (name3 != NULL) {
! 80: while ((ch = *name3++) != 0) {
! 81: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
! 82: }
! 83: }
! 84: return (value % table->size);
! 85: }
! 86:
! 87: static unsigned long
! 88: xmlHashComputeQKey(xmlHashTablePtr table,
! 89: const xmlChar *prefix, const xmlChar *name,
! 90: const xmlChar *prefix2, const xmlChar *name2,
! 91: const xmlChar *prefix3, const xmlChar *name3) {
! 92: unsigned long value = 0L;
! 93: char ch;
! 94:
! 95: if (prefix != NULL)
! 96: value += 30 * (*prefix);
! 97: else
! 98: value += 30 * (*name);
! 99:
! 100: if (prefix != NULL) {
! 101: while ((ch = *prefix++) != 0) {
! 102: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
! 103: }
! 104: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
! 105: }
! 106: if (name != NULL) {
! 107: while ((ch = *name++) != 0) {
! 108: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
! 109: }
! 110: }
! 111: if (prefix2 != NULL) {
! 112: while ((ch = *prefix2++) != 0) {
! 113: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
! 114: }
! 115: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
! 116: }
! 117: if (name2 != NULL) {
! 118: while ((ch = *name2++) != 0) {
! 119: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
! 120: }
! 121: }
! 122: if (prefix3 != NULL) {
! 123: while ((ch = *prefix3++) != 0) {
! 124: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
! 125: }
! 126: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
! 127: }
! 128: if (name3 != NULL) {
! 129: while ((ch = *name3++) != 0) {
! 130: value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
! 131: }
! 132: }
! 133: return (value % table->size);
! 134: }
! 135:
! 136: /**
! 137: * xmlHashCreate:
! 138: * @size: the size of the hash table
! 139: *
! 140: * Create a new xmlHashTablePtr.
! 141: *
! 142: * Returns the newly created object, or NULL if an error occured.
! 143: */
! 144: xmlHashTablePtr
! 145: xmlHashCreate(int size) {
! 146: xmlHashTablePtr table;
! 147:
! 148: if (size <= 0)
! 149: size = 256;
! 150:
! 151: table = xmlMalloc(sizeof(xmlHashTable));
! 152: if (table) {
! 153: table->dict = NULL;
! 154: table->size = size;
! 155: table->nbElems = 0;
! 156: table->table = xmlMalloc(size * sizeof(xmlHashEntry));
! 157: if (table->table) {
! 158: memset(table->table, 0, size * sizeof(xmlHashEntry));
! 159: return(table);
! 160: }
! 161: xmlFree(table);
! 162: }
! 163: return(NULL);
! 164: }
! 165:
! 166: /**
! 167: * xmlHashCreateDict:
! 168: * @size: the size of the hash table
! 169: * @dict: a dictionary to use for the hash
! 170: *
! 171: * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
! 172: *
! 173: * Returns the newly created object, or NULL if an error occured.
! 174: */
! 175: xmlHashTablePtr
! 176: xmlHashCreateDict(int size, xmlDictPtr dict) {
! 177: xmlHashTablePtr table;
! 178:
! 179: table = xmlHashCreate(size);
! 180: if (table != NULL) {
! 181: table->dict = dict;
! 182: xmlDictReference(dict);
! 183: }
! 184: return(table);
! 185: }
! 186:
! 187: /**
! 188: * xmlHashGrow:
! 189: * @table: the hash table
! 190: * @size: the new size of the hash table
! 191: *
! 192: * resize the hash table
! 193: *
! 194: * Returns 0 in case of success, -1 in case of failure
! 195: */
! 196: static int
! 197: xmlHashGrow(xmlHashTablePtr table, int size) {
! 198: unsigned long key;
! 199: int oldsize, i;
! 200: xmlHashEntryPtr iter, next;
! 201: struct _xmlHashEntry *oldtable;
! 202: #ifdef DEBUG_GROW
! 203: unsigned long nbElem = 0;
! 204: #endif
! 205:
! 206: if (table == NULL)
! 207: return(-1);
! 208: if (size < 8)
! 209: return(-1);
! 210: if (size > 8 * 2048)
! 211: return(-1);
! 212:
! 213: oldsize = table->size;
! 214: oldtable = table->table;
! 215: if (oldtable == NULL)
! 216: return(-1);
! 217:
! 218: table->table = xmlMalloc(size * sizeof(xmlHashEntry));
! 219: if (table->table == NULL) {
! 220: table->table = oldtable;
! 221: return(-1);
! 222: }
! 223: memset(table->table, 0, size * sizeof(xmlHashEntry));
! 224: table->size = size;
! 225:
! 226: /* If the two loops are merged, there would be situations where
! 227: a new entry needs to allocated and data copied into it from
! 228: the main table. So instead, we run through the array twice, first
! 229: copying all the elements in the main array (where we can't get
! 230: conflicts) and then the rest, so we only free (and don't allocate)
! 231: */
! 232: for (i = 0; i < oldsize; i++) {
! 233: if (oldtable[i].valid == 0)
! 234: continue;
! 235: key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
! 236: oldtable[i].name3);
! 237: memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
! 238: table->table[key].next = NULL;
! 239: }
! 240:
! 241: for (i = 0; i < oldsize; i++) {
! 242: iter = oldtable[i].next;
! 243: while (iter) {
! 244: next = iter->next;
! 245:
! 246: /*
! 247: * put back the entry in the new table
! 248: */
! 249:
! 250: key = xmlHashComputeKey(table, iter->name, iter->name2,
! 251: iter->name3);
! 252: if (table->table[key].valid == 0) {
! 253: memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
! 254: table->table[key].next = NULL;
! 255: xmlFree(iter);
! 256: } else {
! 257: iter->next = table->table[key].next;
! 258: table->table[key].next = iter;
! 259: }
! 260:
! 261: #ifdef DEBUG_GROW
! 262: nbElem++;
! 263: #endif
! 264:
! 265: iter = next;
! 266: }
! 267: }
! 268:
! 269: xmlFree(oldtable);
! 270:
! 271: #ifdef DEBUG_GROW
! 272: xmlGenericError(xmlGenericErrorContext,
! 273: "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
! 274: #endif
! 275:
! 276: return(0);
! 277: }
! 278:
! 279: /**
! 280: * xmlHashFree:
! 281: * @table: the hash table
! 282: * @f: the deallocator function for items in the hash
! 283: *
! 284: * Free the hash @table and its contents. The userdata is
! 285: * deallocated with @f if provided.
! 286: */
! 287: void
! 288: xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
! 289: int i;
! 290: xmlHashEntryPtr iter;
! 291: xmlHashEntryPtr next;
! 292: int inside_table = 0;
! 293: int nbElems;
! 294:
! 295: if (table == NULL)
! 296: return;
! 297: if (table->table) {
! 298: nbElems = table->nbElems;
! 299: for(i = 0; (i < table->size) && (nbElems > 0); i++) {
! 300: iter = &(table->table[i]);
! 301: if (iter->valid == 0)
! 302: continue;
! 303: inside_table = 1;
! 304: while (iter) {
! 305: next = iter->next;
! 306: if ((f != NULL) && (iter->payload != NULL))
! 307: f(iter->payload, iter->name);
! 308: if (table->dict == NULL) {
! 309: if (iter->name)
! 310: xmlFree(iter->name);
! 311: if (iter->name2)
! 312: xmlFree(iter->name2);
! 313: if (iter->name3)
! 314: xmlFree(iter->name3);
! 315: }
! 316: iter->payload = NULL;
! 317: if (!inside_table)
! 318: xmlFree(iter);
! 319: nbElems--;
! 320: inside_table = 0;
! 321: iter = next;
! 322: }
! 323: }
! 324: xmlFree(table->table);
! 325: }
! 326: if (table->dict)
! 327: xmlDictFree(table->dict);
! 328: xmlFree(table);
! 329: }
! 330:
! 331: /**
! 332: * xmlHashAddEntry:
! 333: * @table: the hash table
! 334: * @name: the name of the userdata
! 335: * @userdata: a pointer to the userdata
! 336: *
! 337: * Add the @userdata to the hash @table. This can later be retrieved
! 338: * by using the @name. Duplicate names generate errors.
! 339: *
! 340: * Returns 0 the addition succeeded and -1 in case of error.
! 341: */
! 342: int
! 343: xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
! 344: return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
! 345: }
! 346:
! 347: /**
! 348: * xmlHashAddEntry2:
! 349: * @table: the hash table
! 350: * @name: the name of the userdata
! 351: * @name2: a second name of the userdata
! 352: * @userdata: a pointer to the userdata
! 353: *
! 354: * Add the @userdata to the hash @table. This can later be retrieved
! 355: * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
! 356: *
! 357: * Returns 0 the addition succeeded and -1 in case of error.
! 358: */
! 359: int
! 360: xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
! 361: const xmlChar *name2, void *userdata) {
! 362: return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
! 363: }
! 364:
! 365: /**
! 366: * xmlHashUpdateEntry:
! 367: * @table: the hash table
! 368: * @name: the name of the userdata
! 369: * @userdata: a pointer to the userdata
! 370: * @f: the deallocator function for replaced item (if any)
! 371: *
! 372: * Add the @userdata to the hash @table. This can later be retrieved
! 373: * by using the @name. Existing entry for this @name will be removed
! 374: * and freed with @f if found.
! 375: *
! 376: * Returns 0 the addition succeeded and -1 in case of error.
! 377: */
! 378: int
! 379: xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
! 380: void *userdata, xmlHashDeallocator f) {
! 381: return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
! 382: }
! 383:
! 384: /**
! 385: * xmlHashUpdateEntry2:
! 386: * @table: the hash table
! 387: * @name: the name of the userdata
! 388: * @name2: a second name of the userdata
! 389: * @userdata: a pointer to the userdata
! 390: * @f: the deallocator function for replaced item (if any)
! 391: *
! 392: * Add the @userdata to the hash @table. This can later be retrieved
! 393: * by using the (@name, @name2) tuple. Existing entry for this tuple will
! 394: * be removed and freed with @f if found.
! 395: *
! 396: * Returns 0 the addition succeeded and -1 in case of error.
! 397: */
! 398: int
! 399: xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
! 400: const xmlChar *name2, void *userdata,
! 401: xmlHashDeallocator f) {
! 402: return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
! 403: }
! 404:
! 405: /**
! 406: * xmlHashLookup:
! 407: * @table: the hash table
! 408: * @name: the name of the userdata
! 409: *
! 410: * Find the userdata specified by the @name.
! 411: *
! 412: * Returns the pointer to the userdata
! 413: */
! 414: void *
! 415: xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
! 416: return(xmlHashLookup3(table, name, NULL, NULL));
! 417: }
! 418:
! 419: /**
! 420: * xmlHashLookup2:
! 421: * @table: the hash table
! 422: * @name: the name of the userdata
! 423: * @name2: a second name of the userdata
! 424: *
! 425: * Find the userdata specified by the (@name, @name2) tuple.
! 426: *
! 427: * Returns the pointer to the userdata
! 428: */
! 429: void *
! 430: xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
! 431: const xmlChar *name2) {
! 432: return(xmlHashLookup3(table, name, name2, NULL));
! 433: }
! 434:
! 435: /**
! 436: * xmlHashQLookup:
! 437: * @table: the hash table
! 438: * @prefix: the prefix of the userdata
! 439: * @name: the name of the userdata
! 440: *
! 441: * Find the userdata specified by the QName @prefix:@name/@name.
! 442: *
! 443: * Returns the pointer to the userdata
! 444: */
! 445: void *
! 446: xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
! 447: const xmlChar *name) {
! 448: return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
! 449: }
! 450:
! 451: /**
! 452: * xmlHashQLookup2:
! 453: * @table: the hash table
! 454: * @prefix: the prefix of the userdata
! 455: * @name: the name of the userdata
! 456: * @prefix2: the second prefix of the userdata
! 457: * @name2: a second name of the userdata
! 458: *
! 459: * Find the userdata specified by the QNames tuple
! 460: *
! 461: * Returns the pointer to the userdata
! 462: */
! 463: void *
! 464: xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
! 465: const xmlChar *name, const xmlChar *prefix2,
! 466: const xmlChar *name2) {
! 467: return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
! 468: }
! 469:
! 470: /**
! 471: * xmlHashAddEntry3:
! 472: * @table: the hash table
! 473: * @name: the name of the userdata
! 474: * @name2: a second name of the userdata
! 475: * @name3: a third name of the userdata
! 476: * @userdata: a pointer to the userdata
! 477: *
! 478: * Add the @userdata to the hash @table. This can later be retrieved
! 479: * by using the tuple (@name, @name2, @name3). Duplicate entries generate
! 480: * errors.
! 481: *
! 482: * Returns 0 the addition succeeded and -1 in case of error.
! 483: */
! 484: int
! 485: xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
! 486: const xmlChar *name2, const xmlChar *name3,
! 487: void *userdata) {
! 488: unsigned long key, len = 0;
! 489: xmlHashEntryPtr entry;
! 490: xmlHashEntryPtr insert;
! 491:
! 492: if ((table == NULL) || (name == NULL))
! 493: return(-1);
! 494:
! 495: /*
! 496: * If using a dict internalize if needed
! 497: */
! 498: if (table->dict) {
! 499: if (!xmlDictOwns(table->dict, name)) {
! 500: name = xmlDictLookup(table->dict, name, -1);
! 501: if (name == NULL)
! 502: return(-1);
! 503: }
! 504: if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
! 505: name2 = xmlDictLookup(table->dict, name2, -1);
! 506: if (name2 == NULL)
! 507: return(-1);
! 508: }
! 509: if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
! 510: name3 = xmlDictLookup(table->dict, name3, -1);
! 511: if (name3 == NULL)
! 512: return(-1);
! 513: }
! 514: }
! 515:
! 516: /*
! 517: * Check for duplicate and insertion location.
! 518: */
! 519: key = xmlHashComputeKey(table, name, name2, name3);
! 520: if (table->table[key].valid == 0) {
! 521: insert = NULL;
! 522: } else {
! 523: if (table->dict) {
! 524: for (insert = &(table->table[key]); insert->next != NULL;
! 525: insert = insert->next) {
! 526: if ((insert->name == name) &&
! 527: (insert->name2 == name2) &&
! 528: (insert->name3 == name3))
! 529: return(-1);
! 530: len++;
! 531: }
! 532: if ((insert->name == name) &&
! 533: (insert->name2 == name2) &&
! 534: (insert->name3 == name3))
! 535: return(-1);
! 536: } else {
! 537: for (insert = &(table->table[key]); insert->next != NULL;
! 538: insert = insert->next) {
! 539: if ((xmlStrEqual(insert->name, name)) &&
! 540: (xmlStrEqual(insert->name2, name2)) &&
! 541: (xmlStrEqual(insert->name3, name3)))
! 542: return(-1);
! 543: len++;
! 544: }
! 545: if ((xmlStrEqual(insert->name, name)) &&
! 546: (xmlStrEqual(insert->name2, name2)) &&
! 547: (xmlStrEqual(insert->name3, name3)))
! 548: return(-1);
! 549: }
! 550: }
! 551:
! 552: if (insert == NULL) {
! 553: entry = &(table->table[key]);
! 554: } else {
! 555: entry = xmlMalloc(sizeof(xmlHashEntry));
! 556: if (entry == NULL)
! 557: return(-1);
! 558: }
! 559:
! 560: if (table->dict != NULL) {
! 561: entry->name = (xmlChar *) name;
! 562: entry->name2 = (xmlChar *) name2;
! 563: entry->name3 = (xmlChar *) name3;
! 564: } else {
! 565: entry->name = xmlStrdup(name);
! 566: entry->name2 = xmlStrdup(name2);
! 567: entry->name3 = xmlStrdup(name3);
! 568: }
! 569: entry->payload = userdata;
! 570: entry->next = NULL;
! 571: entry->valid = 1;
! 572:
! 573:
! 574: if (insert != NULL)
! 575: insert->next = entry;
! 576:
! 577: table->nbElems++;
! 578:
! 579: if (len > MAX_HASH_LEN)
! 580: xmlHashGrow(table, MAX_HASH_LEN * table->size);
! 581:
! 582: return(0);
! 583: }
! 584:
! 585: /**
! 586: * xmlHashUpdateEntry3:
! 587: * @table: the hash table
! 588: * @name: the name of the userdata
! 589: * @name2: a second name of the userdata
! 590: * @name3: a third name of the userdata
! 591: * @userdata: a pointer to the userdata
! 592: * @f: the deallocator function for replaced item (if any)
! 593: *
! 594: * Add the @userdata to the hash @table. This can later be retrieved
! 595: * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
! 596: * will be removed and freed with @f if found.
! 597: *
! 598: * Returns 0 the addition succeeded and -1 in case of error.
! 599: */
! 600: int
! 601: xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
! 602: const xmlChar *name2, const xmlChar *name3,
! 603: void *userdata, xmlHashDeallocator f) {
! 604: unsigned long key;
! 605: xmlHashEntryPtr entry;
! 606: xmlHashEntryPtr insert;
! 607:
! 608: if ((table == NULL) || name == NULL)
! 609: return(-1);
! 610:
! 611: /*
! 612: * If using a dict internalize if needed
! 613: */
! 614: if (table->dict) {
! 615: if (!xmlDictOwns(table->dict, name)) {
! 616: name = xmlDictLookup(table->dict, name, -1);
! 617: if (name == NULL)
! 618: return(-1);
! 619: }
! 620: if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
! 621: name2 = xmlDictLookup(table->dict, name2, -1);
! 622: if (name2 == NULL)
! 623: return(-1);
! 624: }
! 625: if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
! 626: name3 = xmlDictLookup(table->dict, name3, -1);
! 627: if (name3 == NULL)
! 628: return(-1);
! 629: }
! 630: }
! 631:
! 632: /*
! 633: * Check for duplicate and insertion location.
! 634: */
! 635: key = xmlHashComputeKey(table, name, name2, name3);
! 636: if (table->table[key].valid == 0) {
! 637: insert = NULL;
! 638: } else {
! 639: if (table ->dict) {
! 640: for (insert = &(table->table[key]); insert->next != NULL;
! 641: insert = insert->next) {
! 642: if ((insert->name == name) &&
! 643: (insert->name2 == name2) &&
! 644: (insert->name3 == name3)) {
! 645: if (f)
! 646: f(insert->payload, insert->name);
! 647: insert->payload = userdata;
! 648: return(0);
! 649: }
! 650: }
! 651: if ((insert->name == name) &&
! 652: (insert->name2 == name2) &&
! 653: (insert->name3 == name3)) {
! 654: if (f)
! 655: f(insert->payload, insert->name);
! 656: insert->payload = userdata;
! 657: return(0);
! 658: }
! 659: } else {
! 660: for (insert = &(table->table[key]); insert->next != NULL;
! 661: insert = insert->next) {
! 662: if ((xmlStrEqual(insert->name, name)) &&
! 663: (xmlStrEqual(insert->name2, name2)) &&
! 664: (xmlStrEqual(insert->name3, name3))) {
! 665: if (f)
! 666: f(insert->payload, insert->name);
! 667: insert->payload = userdata;
! 668: return(0);
! 669: }
! 670: }
! 671: if ((xmlStrEqual(insert->name, name)) &&
! 672: (xmlStrEqual(insert->name2, name2)) &&
! 673: (xmlStrEqual(insert->name3, name3))) {
! 674: if (f)
! 675: f(insert->payload, insert->name);
! 676: insert->payload = userdata;
! 677: return(0);
! 678: }
! 679: }
! 680: }
! 681:
! 682: if (insert == NULL) {
! 683: entry = &(table->table[key]);
! 684: } else {
! 685: entry = xmlMalloc(sizeof(xmlHashEntry));
! 686: if (entry == NULL)
! 687: return(-1);
! 688: }
! 689:
! 690: if (table->dict != NULL) {
! 691: entry->name = (xmlChar *) name;
! 692: entry->name2 = (xmlChar *) name2;
! 693: entry->name3 = (xmlChar *) name3;
! 694: } else {
! 695: entry->name = xmlStrdup(name);
! 696: entry->name2 = xmlStrdup(name2);
! 697: entry->name3 = xmlStrdup(name3);
! 698: }
! 699: entry->payload = userdata;
! 700: entry->next = NULL;
! 701: entry->valid = 1;
! 702: table->nbElems++;
! 703:
! 704:
! 705: if (insert != NULL) {
! 706: insert->next = entry;
! 707: }
! 708: return(0);
! 709: }
! 710:
! 711: /**
! 712: * xmlHashLookup3:
! 713: * @table: the hash table
! 714: * @name: the name of the userdata
! 715: * @name2: a second name of the userdata
! 716: * @name3: a third name of the userdata
! 717: *
! 718: * Find the userdata specified by the (@name, @name2, @name3) tuple.
! 719: *
! 720: * Returns the a pointer to the userdata
! 721: */
! 722: void *
! 723: xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
! 724: const xmlChar *name2, const xmlChar *name3) {
! 725: unsigned long key;
! 726: xmlHashEntryPtr entry;
! 727:
! 728: if (table == NULL)
! 729: return(NULL);
! 730: if (name == NULL)
! 731: return(NULL);
! 732: key = xmlHashComputeKey(table, name, name2, name3);
! 733: if (table->table[key].valid == 0)
! 734: return(NULL);
! 735: if (table->dict) {
! 736: for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
! 737: if ((entry->name == name) &&
! 738: (entry->name2 == name2) &&
! 739: (entry->name3 == name3))
! 740: return(entry->payload);
! 741: }
! 742: }
! 743: for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
! 744: if ((xmlStrEqual(entry->name, name)) &&
! 745: (xmlStrEqual(entry->name2, name2)) &&
! 746: (xmlStrEqual(entry->name3, name3)))
! 747: return(entry->payload);
! 748: }
! 749: return(NULL);
! 750: }
! 751:
! 752: /**
! 753: * xmlHashQLookup3:
! 754: * @table: the hash table
! 755: * @prefix: the prefix of the userdata
! 756: * @name: the name of the userdata
! 757: * @prefix2: the second prefix of the userdata
! 758: * @name2: a second name of the userdata
! 759: * @prefix3: the third prefix of the userdata
! 760: * @name3: a third name of the userdata
! 761: *
! 762: * Find the userdata specified by the (@name, @name2, @name3) tuple.
! 763: *
! 764: * Returns the a pointer to the userdata
! 765: */
! 766: void *
! 767: xmlHashQLookup3(xmlHashTablePtr table,
! 768: const xmlChar *prefix, const xmlChar *name,
! 769: const xmlChar *prefix2, const xmlChar *name2,
! 770: const xmlChar *prefix3, const xmlChar *name3) {
! 771: unsigned long key;
! 772: xmlHashEntryPtr entry;
! 773:
! 774: if (table == NULL)
! 775: return(NULL);
! 776: if (name == NULL)
! 777: return(NULL);
! 778: key = xmlHashComputeQKey(table, prefix, name, prefix2,
! 779: name2, prefix3, name3);
! 780: if (table->table[key].valid == 0)
! 781: return(NULL);
! 782: for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
! 783: if ((xmlStrQEqual(prefix, name, entry->name)) &&
! 784: (xmlStrQEqual(prefix2, name2, entry->name2)) &&
! 785: (xmlStrQEqual(prefix3, name3, entry->name3)))
! 786: return(entry->payload);
! 787: }
! 788: return(NULL);
! 789: }
! 790:
! 791: typedef struct {
! 792: xmlHashScanner hashscanner;
! 793: void *data;
! 794: } stubData;
! 795:
! 796: static void
! 797: stubHashScannerFull (void *payload, void *data, const xmlChar *name,
! 798: const xmlChar *name2 ATTRIBUTE_UNUSED,
! 799: const xmlChar *name3 ATTRIBUTE_UNUSED) {
! 800: stubData *stubdata = (stubData *) data;
! 801: stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
! 802: }
! 803:
! 804: /**
! 805: * xmlHashScan:
! 806: * @table: the hash table
! 807: * @f: the scanner function for items in the hash
! 808: * @data: extra data passed to f
! 809: *
! 810: * Scan the hash @table and applied @f to each value.
! 811: */
! 812: void
! 813: xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
! 814: stubData stubdata;
! 815: stubdata.data = data;
! 816: stubdata.hashscanner = f;
! 817: xmlHashScanFull (table, stubHashScannerFull, &stubdata);
! 818: }
! 819:
! 820: /**
! 821: * xmlHashScanFull:
! 822: * @table: the hash table
! 823: * @f: the scanner function for items in the hash
! 824: * @data: extra data passed to f
! 825: *
! 826: * Scan the hash @table and applied @f to each value.
! 827: */
! 828: void
! 829: xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
! 830: int i, nb;
! 831: xmlHashEntryPtr iter;
! 832: xmlHashEntryPtr next;
! 833:
! 834: if (table == NULL)
! 835: return;
! 836: if (f == NULL)
! 837: return;
! 838:
! 839: if (table->table) {
! 840: for(i = 0; i < table->size; i++) {
! 841: if (table->table[i].valid == 0)
! 842: continue;
! 843: iter = &(table->table[i]);
! 844: while (iter) {
! 845: next = iter->next;
! 846: nb = table->nbElems;
! 847: if ((f != NULL) && (iter->payload != NULL))
! 848: f(iter->payload, data, iter->name,
! 849: iter->name2, iter->name3);
! 850: if (nb != table->nbElems) {
! 851: /* table was modified by the callback, be careful */
! 852: if (iter == &(table->table[i])) {
! 853: if (table->table[i].valid == 0)
! 854: iter = NULL;
! 855: if (table->table[i].next != next)
! 856: iter = &(table->table[i]);
! 857: } else
! 858: iter = next;
! 859: } else
! 860: iter = next;
! 861: }
! 862: }
! 863: }
! 864: }
! 865:
! 866: /**
! 867: * xmlHashScan3:
! 868: * @table: the hash table
! 869: * @name: the name of the userdata or NULL
! 870: * @name2: a second name of the userdata or NULL
! 871: * @name3: a third name of the userdata or NULL
! 872: * @f: the scanner function for items in the hash
! 873: * @data: extra data passed to f
! 874: *
! 875: * Scan the hash @table and applied @f to each value matching
! 876: * (@name, @name2, @name3) tuple. If one of the names is null,
! 877: * the comparison is considered to match.
! 878: */
! 879: void
! 880: xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
! 881: const xmlChar *name2, const xmlChar *name3,
! 882: xmlHashScanner f, void *data) {
! 883: xmlHashScanFull3 (table, name, name2, name3,
! 884: (xmlHashScannerFull) f, data);
! 885: }
! 886:
! 887: /**
! 888: * xmlHashScanFull3:
! 889: * @table: the hash table
! 890: * @name: the name of the userdata or NULL
! 891: * @name2: a second name of the userdata or NULL
! 892: * @name3: a third name of the userdata or NULL
! 893: * @f: the scanner function for items in the hash
! 894: * @data: extra data passed to f
! 895: *
! 896: * Scan the hash @table and applied @f to each value matching
! 897: * (@name, @name2, @name3) tuple. If one of the names is null,
! 898: * the comparison is considered to match.
! 899: */
! 900: void
! 901: xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
! 902: const xmlChar *name2, const xmlChar *name3,
! 903: xmlHashScannerFull f, void *data) {
! 904: int i;
! 905: xmlHashEntryPtr iter;
! 906: xmlHashEntryPtr next;
! 907:
! 908: if (table == NULL)
! 909: return;
! 910: if (f == NULL)
! 911: return;
! 912:
! 913: if (table->table) {
! 914: for(i = 0; i < table->size; i++) {
! 915: if (table->table[i].valid == 0)
! 916: continue;
! 917: iter = &(table->table[i]);
! 918: while (iter) {
! 919: next = iter->next;
! 920: if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
! 921: ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
! 922: ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
! 923: (iter->payload != NULL)) {
! 924: f(iter->payload, data, iter->name,
! 925: iter->name2, iter->name3);
! 926: }
! 927: iter = next;
! 928: }
! 929: }
! 930: }
! 931: }
! 932:
! 933: /**
! 934: * xmlHashCopy:
! 935: * @table: the hash table
! 936: * @f: the copier function for items in the hash
! 937: *
! 938: * Scan the hash @table and applied @f to each value.
! 939: *
! 940: * Returns the new table or NULL in case of error.
! 941: */
! 942: xmlHashTablePtr
! 943: xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
! 944: int i;
! 945: xmlHashEntryPtr iter;
! 946: xmlHashEntryPtr next;
! 947: xmlHashTablePtr ret;
! 948:
! 949: if (table == NULL)
! 950: return(NULL);
! 951: if (f == NULL)
! 952: return(NULL);
! 953:
! 954: ret = xmlHashCreate(table->size);
! 955: if (table->table) {
! 956: for(i = 0; i < table->size; i++) {
! 957: if (table->table[i].valid == 0)
! 958: continue;
! 959: iter = &(table->table[i]);
! 960: while (iter) {
! 961: next = iter->next;
! 962: xmlHashAddEntry3(ret, iter->name, iter->name2,
! 963: iter->name3, f(iter->payload, iter->name));
! 964: iter = next;
! 965: }
! 966: }
! 967: }
! 968: ret->nbElems = table->nbElems;
! 969: return(ret);
! 970: }
! 971:
! 972: /**
! 973: * xmlHashSize:
! 974: * @table: the hash table
! 975: *
! 976: * Query the number of elements installed in the hash @table.
! 977: *
! 978: * Returns the number of elements in the hash table or
! 979: * -1 in case of error
! 980: */
! 981: int
! 982: xmlHashSize(xmlHashTablePtr table) {
! 983: if (table == NULL)
! 984: return(-1);
! 985: return(table->nbElems);
! 986: }
! 987:
! 988: /**
! 989: * xmlHashRemoveEntry:
! 990: * @table: the hash table
! 991: * @name: the name of the userdata
! 992: * @f: the deallocator function for removed item (if any)
! 993: *
! 994: * Find the userdata specified by the @name and remove
! 995: * it from the hash @table. Existing userdata for this tuple will be removed
! 996: * and freed with @f.
! 997: *
! 998: * Returns 0 if the removal succeeded and -1 in case of error or not found.
! 999: */
! 1000: int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
! 1001: xmlHashDeallocator f) {
! 1002: return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
! 1003: }
! 1004:
! 1005: /**
! 1006: * xmlHashRemoveEntry2:
! 1007: * @table: the hash table
! 1008: * @name: the name of the userdata
! 1009: * @name2: a second name of the userdata
! 1010: * @f: the deallocator function for removed item (if any)
! 1011: *
! 1012: * Find the userdata specified by the (@name, @name2) tuple and remove
! 1013: * it from the hash @table. Existing userdata for this tuple will be removed
! 1014: * and freed with @f.
! 1015: *
! 1016: * Returns 0 if the removal succeeded and -1 in case of error or not found.
! 1017: */
! 1018: int
! 1019: xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
! 1020: const xmlChar *name2, xmlHashDeallocator f) {
! 1021: return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
! 1022: }
! 1023:
! 1024: /**
! 1025: * xmlHashRemoveEntry3:
! 1026: * @table: the hash table
! 1027: * @name: the name of the userdata
! 1028: * @name2: a second name of the userdata
! 1029: * @name3: a third name of the userdata
! 1030: * @f: the deallocator function for removed item (if any)
! 1031: *
! 1032: * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
! 1033: * it from the hash @table. Existing userdata for this tuple will be removed
! 1034: * and freed with @f.
! 1035: *
! 1036: * Returns 0 if the removal succeeded and -1 in case of error or not found.
! 1037: */
! 1038: int
! 1039: xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
! 1040: const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
! 1041: unsigned long key;
! 1042: xmlHashEntryPtr entry;
! 1043: xmlHashEntryPtr prev = NULL;
! 1044:
! 1045: if (table == NULL || name == NULL)
! 1046: return(-1);
! 1047:
! 1048: key = xmlHashComputeKey(table, name, name2, name3);
! 1049: if (table->table[key].valid == 0) {
! 1050: return(-1);
! 1051: } else {
! 1052: for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
! 1053: if (xmlStrEqual(entry->name, name) &&
! 1054: xmlStrEqual(entry->name2, name2) &&
! 1055: xmlStrEqual(entry->name3, name3)) {
! 1056: if ((f != NULL) && (entry->payload != NULL))
! 1057: f(entry->payload, entry->name);
! 1058: entry->payload = NULL;
! 1059: if (table->dict == NULL) {
! 1060: if(entry->name)
! 1061: xmlFree(entry->name);
! 1062: if(entry->name2)
! 1063: xmlFree(entry->name2);
! 1064: if(entry->name3)
! 1065: xmlFree(entry->name3);
! 1066: }
! 1067: if(prev) {
! 1068: prev->next = entry->next;
! 1069: xmlFree(entry);
! 1070: } else {
! 1071: if (entry->next == NULL) {
! 1072: entry->valid = 0;
! 1073: } else {
! 1074: entry = entry->next;
! 1075: memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
! 1076: xmlFree(entry);
! 1077: }
! 1078: }
! 1079: table->nbElems--;
! 1080: return(0);
! 1081: }
! 1082: prev = entry;
! 1083: }
! 1084: return(-1);
! 1085: }
! 1086: }
! 1087:
! 1088: #define bottom_hash
! 1089: #include "elfgcchack.h"
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>