Annotation of embedaddon/libxml2/hash.c, revision 1.1.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>