2 * hash.c: chained hash tables
4 * Reference: Your favorite introductory book on algorithms
6 * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
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.
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.
17 * Author: breese@users.sourceforge.net
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>
30 #define MAX_HASH_LEN 8
32 /* #define DEBUG_GROW */
35 * A single entry in the hash table
37 typedef struct _xmlHashEntry xmlHashEntry
;
38 typedef xmlHashEntry
*xmlHashEntryPtr
;
39 struct _xmlHashEntry
{
40 struct _xmlHashEntry
*next
;
49 * The entire hash table
51 struct _xmlHashTable
{
52 struct _xmlHashEntry
*table
;
60 * Calculate the hash key
63 xmlHashComputeKey(xmlHashTablePtr table
, const xmlChar
*name
,
64 const xmlChar
*name2
, const xmlChar
*name3
) {
65 unsigned long value
= 0L;
69 value
+= 30 * (*name
);
70 while ((ch
= *name
++) != 0) {
71 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
75 while ((ch
= *name2
++) != 0) {
76 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
80 while ((ch
= *name3
++) != 0) {
81 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
84 return (value
% table
->size
);
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;
96 value
+= 30 * (*prefix
);
98 value
+= 30 * (*name
);
100 if (prefix
!= NULL
) {
101 while ((ch
= *prefix
++) != 0) {
102 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
104 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)':');
107 while ((ch
= *name
++) != 0) {
108 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
111 if (prefix2
!= NULL
) {
112 while ((ch
= *prefix2
++) != 0) {
113 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
115 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)':');
118 while ((ch
= *name2
++) != 0) {
119 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
122 if (prefix3
!= NULL
) {
123 while ((ch
= *prefix3
++) != 0) {
124 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
126 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)':');
129 while ((ch
= *name3
++) != 0) {
130 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
133 return (value
% table
->size
);
138 * @size: the size of the hash table
140 * Create a new xmlHashTablePtr.
142 * Returns the newly created object, or NULL if an error occured.
145 xmlHashCreate(int size
) {
146 xmlHashTablePtr table
;
151 table
= xmlMalloc(sizeof(xmlHashTable
));
156 table
->table
= xmlMalloc(size
* sizeof(xmlHashEntry
));
158 memset(table
->table
, 0, size
* sizeof(xmlHashEntry
));
168 * @size: the size of the hash table
169 * @dict: a dictionary to use for the hash
171 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
173 * Returns the newly created object, or NULL if an error occured.
176 xmlHashCreateDict(int size
, xmlDictPtr dict
) {
177 xmlHashTablePtr table
;
179 table
= xmlHashCreate(size
);
182 xmlDictReference(dict
);
189 * @table: the hash table
190 * @size: the new size of the hash table
192 * resize the hash table
194 * Returns 0 in case of success, -1 in case of failure
197 xmlHashGrow(xmlHashTablePtr table
, int size
) {
200 xmlHashEntryPtr iter
, next
;
201 struct _xmlHashEntry
*oldtable
;
203 unsigned long nbElem
= 0;
213 oldsize
= table
->size
;
214 oldtable
= table
->table
;
215 if (oldtable
== NULL
)
218 table
->table
= xmlMalloc(size
* sizeof(xmlHashEntry
));
219 if (table
->table
== NULL
) {
220 table
->table
= oldtable
;
223 memset(table
->table
, 0, size
* sizeof(xmlHashEntry
));
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)
232 for (i
= 0; i
< oldsize
; i
++) {
233 if (oldtable
[i
].valid
== 0)
235 key
= xmlHashComputeKey(table
, oldtable
[i
].name
, oldtable
[i
].name2
,
237 memcpy(&(table
->table
[key
]), &(oldtable
[i
]), sizeof(xmlHashEntry
));
238 table
->table
[key
].next
= NULL
;
241 for (i
= 0; i
< oldsize
; i
++) {
242 iter
= oldtable
[i
].next
;
247 * put back the entry in the new table
250 key
= xmlHashComputeKey(table
, iter
->name
, iter
->name2
,
252 if (table
->table
[key
].valid
== 0) {
253 memcpy(&(table
->table
[key
]), iter
, sizeof(xmlHashEntry
));
254 table
->table
[key
].next
= NULL
;
257 iter
->next
= table
->table
[key
].next
;
258 table
->table
[key
].next
= iter
;
272 xmlGenericError(xmlGenericErrorContext
,
273 "xmlHashGrow : from %d to %d, %d elems\n", oldsize
, size
, nbElem
);
281 * @table: the hash table
282 * @f: the deallocator function for items in the hash
284 * Free the hash @table and its contents. The userdata is
285 * deallocated with @f if provided.
288 xmlHashFree(xmlHashTablePtr table
, xmlHashDeallocator f
) {
290 xmlHashEntryPtr iter
;
291 xmlHashEntryPtr next
;
292 int inside_table
= 0;
298 nbElems
= table
->nbElems
;
299 for(i
= 0; (i
< table
->size
) && (nbElems
> 0); i
++) {
300 iter
= &(table
->table
[i
]);
301 if (iter
->valid
== 0)
306 if ((f
!= NULL
) && (iter
->payload
!= NULL
))
307 f(iter
->payload
, iter
->name
);
308 if (table
->dict
== NULL
) {
312 xmlFree(iter
->name2
);
314 xmlFree(iter
->name3
);
316 iter
->payload
= NULL
;
324 xmlFree(table
->table
);
327 xmlDictFree(table
->dict
);
333 * @table: the hash table
334 * @name: the name of the userdata
335 * @userdata: a pointer to the userdata
337 * Add the @userdata to the hash @table. This can later be retrieved
338 * by using the @name. Duplicate names generate errors.
340 * Returns 0 the addition succeeded and -1 in case of error.
343 xmlHashAddEntry(xmlHashTablePtr table
, const xmlChar
*name
, void *userdata
) {
344 return(xmlHashAddEntry3(table
, name
, NULL
, NULL
, userdata
));
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
354 * Add the @userdata to the hash @table. This can later be retrieved
355 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
357 * Returns 0 the addition succeeded and -1 in case of error.
360 xmlHashAddEntry2(xmlHashTablePtr table
, const xmlChar
*name
,
361 const xmlChar
*name2
, void *userdata
) {
362 return(xmlHashAddEntry3(table
, name
, name2
, NULL
, userdata
));
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)
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.
376 * Returns 0 the addition succeeded and -1 in case of error.
379 xmlHashUpdateEntry(xmlHashTablePtr table
, const xmlChar
*name
,
380 void *userdata
, xmlHashDeallocator f
) {
381 return(xmlHashUpdateEntry3(table
, name
, NULL
, NULL
, userdata
, f
));
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)
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.
396 * Returns 0 the addition succeeded and -1 in case of error.
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
));
407 * @table: the hash table
408 * @name: the name of the userdata
410 * Find the userdata specified by the @name.
412 * Returns the pointer to the userdata
415 xmlHashLookup(xmlHashTablePtr table
, const xmlChar
*name
) {
416 return(xmlHashLookup3(table
, name
, NULL
, NULL
));
421 * @table: the hash table
422 * @name: the name of the userdata
423 * @name2: a second name of the userdata
425 * Find the userdata specified by the (@name, @name2) tuple.
427 * Returns the pointer to the userdata
430 xmlHashLookup2(xmlHashTablePtr table
, const xmlChar
*name
,
431 const xmlChar
*name2
) {
432 return(xmlHashLookup3(table
, name
, name2
, NULL
));
437 * @table: the hash table
438 * @prefix: the prefix of the userdata
439 * @name: the name of the userdata
441 * Find the userdata specified by the QName @prefix:@name/@name.
443 * Returns the pointer to the userdata
446 xmlHashQLookup(xmlHashTablePtr table
, const xmlChar
*prefix
,
447 const xmlChar
*name
) {
448 return(xmlHashQLookup3(table
, prefix
, name
, NULL
, NULL
, NULL
, NULL
));
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
459 * Find the userdata specified by the QNames tuple
461 * Returns the pointer to the userdata
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
));
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
478 * Add the @userdata to the hash @table. This can later be retrieved
479 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
482 * Returns 0 the addition succeeded and -1 in case of error.
485 xmlHashAddEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
486 const xmlChar
*name2
, const xmlChar
*name3
,
488 unsigned long key
, len
= 0;
489 xmlHashEntryPtr entry
;
490 xmlHashEntryPtr insert
;
492 if ((table
== NULL
) || (name
== NULL
))
496 * If using a dict internalize if needed
499 if (!xmlDictOwns(table
->dict
, name
)) {
500 name
= xmlDictLookup(table
->dict
, name
, -1);
504 if ((name2
!= NULL
) && (!xmlDictOwns(table
->dict
, name2
))) {
505 name2
= xmlDictLookup(table
->dict
, name2
, -1);
509 if ((name3
!= NULL
) && (!xmlDictOwns(table
->dict
, name3
))) {
510 name3
= xmlDictLookup(table
->dict
, name3
, -1);
517 * Check for duplicate and insertion location.
519 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
520 if (table
->table
[key
].valid
== 0) {
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
))
532 if ((insert
->name
== name
) &&
533 (insert
->name2
== name2
) &&
534 (insert
->name3
== name3
))
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
)))
545 if ((xmlStrEqual(insert
->name
, name
)) &&
546 (xmlStrEqual(insert
->name2
, name2
)) &&
547 (xmlStrEqual(insert
->name3
, name3
)))
552 if (insert
== NULL
) {
553 entry
= &(table
->table
[key
]);
555 entry
= xmlMalloc(sizeof(xmlHashEntry
));
560 if (table
->dict
!= NULL
) {
561 entry
->name
= (xmlChar
*) name
;
562 entry
->name2
= (xmlChar
*) name2
;
563 entry
->name3
= (xmlChar
*) name3
;
565 entry
->name
= xmlStrdup(name
);
566 entry
->name2
= xmlStrdup(name2
);
567 entry
->name3
= xmlStrdup(name3
);
569 entry
->payload
= userdata
;
575 insert
->next
= entry
;
579 if (len
> MAX_HASH_LEN
)
580 xmlHashGrow(table
, MAX_HASH_LEN
* table
->size
);
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)
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.
598 * Returns 0 the addition succeeded and -1 in case of error.
601 xmlHashUpdateEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
602 const xmlChar
*name2
, const xmlChar
*name3
,
603 void *userdata
, xmlHashDeallocator f
) {
605 xmlHashEntryPtr entry
;
606 xmlHashEntryPtr insert
;
608 if ((table
== NULL
) || name
== NULL
)
612 * If using a dict internalize if needed
615 if (!xmlDictOwns(table
->dict
, name
)) {
616 name
= xmlDictLookup(table
->dict
, name
, -1);
620 if ((name2
!= NULL
) && (!xmlDictOwns(table
->dict
, name2
))) {
621 name2
= xmlDictLookup(table
->dict
, name2
, -1);
625 if ((name3
!= NULL
) && (!xmlDictOwns(table
->dict
, name3
))) {
626 name3
= xmlDictLookup(table
->dict
, name3
, -1);
633 * Check for duplicate and insertion location.
635 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
636 if (table
->table
[key
].valid
== 0) {
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
)) {
646 f(insert
->payload
, insert
->name
);
647 insert
->payload
= userdata
;
651 if ((insert
->name
== name
) &&
652 (insert
->name2
== name2
) &&
653 (insert
->name3
== name3
)) {
655 f(insert
->payload
, insert
->name
);
656 insert
->payload
= userdata
;
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
))) {
666 f(insert
->payload
, insert
->name
);
667 insert
->payload
= userdata
;
671 if ((xmlStrEqual(insert
->name
, name
)) &&
672 (xmlStrEqual(insert
->name2
, name2
)) &&
673 (xmlStrEqual(insert
->name3
, name3
))) {
675 f(insert
->payload
, insert
->name
);
676 insert
->payload
= userdata
;
682 if (insert
== NULL
) {
683 entry
= &(table
->table
[key
]);
685 entry
= xmlMalloc(sizeof(xmlHashEntry
));
690 if (table
->dict
!= NULL
) {
691 entry
->name
= (xmlChar
*) name
;
692 entry
->name2
= (xmlChar
*) name2
;
693 entry
->name3
= (xmlChar
*) name3
;
695 entry
->name
= xmlStrdup(name
);
696 entry
->name2
= xmlStrdup(name2
);
697 entry
->name3
= xmlStrdup(name3
);
699 entry
->payload
= userdata
;
705 if (insert
!= NULL
) {
706 insert
->next
= entry
;
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
718 * Find the userdata specified by the (@name, @name2, @name3) tuple.
720 * Returns the a pointer to the userdata
723 xmlHashLookup3(xmlHashTablePtr table
, const xmlChar
*name
,
724 const xmlChar
*name2
, const xmlChar
*name3
) {
726 xmlHashEntryPtr entry
;
732 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
733 if (table
->table
[key
].valid
== 0)
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
);
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
);
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
762 * Find the userdata specified by the (@name, @name2, @name3) tuple.
764 * Returns the a pointer to the userdata
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
) {
772 xmlHashEntryPtr entry
;
778 key
= xmlHashComputeQKey(table
, prefix
, name
, prefix2
,
779 name2
, prefix3
, name3
);
780 if (table
->table
[key
].valid
== 0)
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
);
792 xmlHashScanner hashscanner
;
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
);
806 * @table: the hash table
807 * @f: the scanner function for items in the hash
808 * @data: extra data passed to f
810 * Scan the hash @table and applied @f to each value.
813 xmlHashScan(xmlHashTablePtr table
, xmlHashScanner f
, void *data
) {
815 stubdata
.data
= data
;
816 stubdata
.hashscanner
= f
;
817 xmlHashScanFull (table
, stubHashScannerFull
, &stubdata
);
822 * @table: the hash table
823 * @f: the scanner function for items in the hash
824 * @data: extra data passed to f
826 * Scan the hash @table and applied @f to each value.
829 xmlHashScanFull(xmlHashTablePtr table
, xmlHashScannerFull f
, void *data
) {
831 xmlHashEntryPtr iter
;
832 xmlHashEntryPtr next
;
840 for(i
= 0; i
< table
->size
; i
++) {
841 if (table
->table
[i
].valid
== 0)
843 iter
= &(table
->table
[i
]);
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)
855 if (table
->table
[i
].next
!= next
)
856 iter
= &(table
->table
[i
]);
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
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.
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
);
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
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.
901 xmlHashScanFull3(xmlHashTablePtr table
, const xmlChar
*name
,
902 const xmlChar
*name2
, const xmlChar
*name3
,
903 xmlHashScannerFull f
, void *data
) {
905 xmlHashEntryPtr iter
;
906 xmlHashEntryPtr next
;
914 for(i
= 0; i
< table
->size
; i
++) {
915 if (table
->table
[i
].valid
== 0)
917 iter
= &(table
->table
[i
]);
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
);
935 * @table: the hash table
936 * @f: the copier function for items in the hash
938 * Scan the hash @table and applied @f to each value.
940 * Returns the new table or NULL in case of error.
943 xmlHashCopy(xmlHashTablePtr table
, xmlHashCopier f
) {
945 xmlHashEntryPtr iter
;
946 xmlHashEntryPtr next
;
954 ret
= xmlHashCreate(table
->size
);
956 for(i
= 0; i
< table
->size
; i
++) {
957 if (table
->table
[i
].valid
== 0)
959 iter
= &(table
->table
[i
]);
962 xmlHashAddEntry3(ret
, iter
->name
, iter
->name2
,
963 iter
->name3
, f(iter
->payload
, iter
->name
));
968 ret
->nbElems
= table
->nbElems
;
974 * @table: the hash table
976 * Query the number of elements installed in the hash @table.
978 * Returns the number of elements in the hash table or
979 * -1 in case of error
982 xmlHashSize(xmlHashTablePtr table
) {
985 return(table
->nbElems
);
989 * xmlHashRemoveEntry:
990 * @table: the hash table
991 * @name: the name of the userdata
992 * @f: the deallocator function for removed item (if any)
994 * Find the userdata specified by the @name and remove
995 * it from the hash @table. Existing userdata for this tuple will be removed
998 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1000 int xmlHashRemoveEntry(xmlHashTablePtr table
, const xmlChar
*name
,
1001 xmlHashDeallocator f
) {
1002 return(xmlHashRemoveEntry3(table
, name
, NULL
, NULL
, f
));
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)
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.
1016 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1019 xmlHashRemoveEntry2(xmlHashTablePtr table
, const xmlChar
*name
,
1020 const xmlChar
*name2
, xmlHashDeallocator f
) {
1021 return(xmlHashRemoveEntry3(table
, name
, name2
, NULL
, f
));
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)
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.
1036 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1039 xmlHashRemoveEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
1040 const xmlChar
*name2
, const xmlChar
*name3
, xmlHashDeallocator f
) {
1042 xmlHashEntryPtr entry
;
1043 xmlHashEntryPtr prev
= NULL
;
1045 if (table
== NULL
|| name
== NULL
)
1048 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
1049 if (table
->table
[key
].valid
== 0) {
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
) {
1061 xmlFree(entry
->name
);
1063 xmlFree(entry
->name2
);
1065 xmlFree(entry
->name3
);
1068 prev
->next
= entry
->next
;
1071 if (entry
->next
== NULL
) {
1074 entry
= entry
->next
;
1075 memcpy(&(table
->table
[key
]), entry
, sizeof(xmlHashEntry
));
1089 #include "elfgcchack.h"