2 * dict.c: dictionary of reusable strings, just used to avoid allocation
3 * and freeing operations.
5 * Copyright (C) 2003 Daniel Veillard.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
16 * Author: daniel@veillard.com
26 #ifdef HAVE_INTTYPES_H
29 typedef unsigned __int32
uint32_t;
32 #include <libxml/tree.h>
33 #include <libxml/dict.h>
34 #include <libxml/xmlmemory.h>
35 #include <libxml/xmlerror.h>
36 #include <libxml/globals.h>
38 /* #define DEBUG_GROW */
39 /* #define DICT_DEBUG_PATTERNS */
41 #define MAX_HASH_LEN 3
42 #define MIN_DICT_SIZE 128
43 #define MAX_DICT_HASH 8 * 2048
47 #define xmlDictComputeKey(dict, name, len) \
48 (((dict)->size == MIN_DICT_SIZE) ? \
49 xmlDictComputeFastKey(name, len) : \
50 xmlDictComputeBigKey(name, len))
52 #define xmlDictComputeQKey(dict, prefix, plen, name, len) \
53 (((prefix) == NULL) ? \
54 (xmlDictComputeKey(dict, name, len)) : \
55 (((dict)->size == MIN_DICT_SIZE) ? \
56 xmlDictComputeFastQKey(prefix, plen, name, len) : \
57 xmlDictComputeBigQKey(prefix, plen, name, len)))
59 #else /* !WITH_BIG_KEY */
60 #define xmlDictComputeKey(dict, name, len) \
61 xmlDictComputeFastKey(name, len)
62 #define xmlDictComputeQKey(dict, prefix, plen, name, len) \
63 xmlDictComputeFastQKey(prefix, plen, name, len)
64 #endif /* WITH_BIG_KEY */
67 * An entry in the dictionnary
69 typedef struct _xmlDictEntry xmlDictEntry
;
70 typedef xmlDictEntry
*xmlDictEntryPtr
;
71 struct _xmlDictEntry
{
72 struct _xmlDictEntry
*next
;
79 typedef struct _xmlDictStrings xmlDictStrings
;
80 typedef xmlDictStrings
*xmlDictStringsPtr
;
81 struct _xmlDictStrings
{
82 xmlDictStringsPtr next
;
90 * The entire dictionnary
95 struct _xmlDictEntry
*dict
;
98 xmlDictStringsPtr strings
;
100 struct _xmlDict
*subdict
;
104 * A mutex for modifying the reference counter for shared
107 static xmlRMutexPtr xmlDictMutex
= NULL
;
110 * Whether the dictionary mutex was initialized.
112 static int xmlDictInitialized
= 0;
117 * Do the dictionary mutex initialization.
118 * this function is not thread safe, initialization should
119 * preferably be done once at startup
121 static int xmlInitializeDict(void) {
122 if (xmlDictInitialized
)
125 if ((xmlDictMutex
= xmlNewRMutex()) == NULL
)
128 xmlDictInitialized
= 1;
135 * Free the dictionary mutex.
138 xmlDictCleanup(void) {
139 if (!xmlDictInitialized
)
142 xmlFreeRMutex(xmlDictMutex
);
144 xmlDictInitialized
= 0;
149 * @dict: the dictionnary
150 * @name: the name of the userdata
151 * @len: the length of the name, if -1 it is recomputed
153 * Add the string to the array[s]
155 * Returns the pointer of the local string, or NULL in case of error.
157 static const xmlChar
*
158 xmlDictAddString(xmlDictPtr dict
, const xmlChar
*name
, int namelen
) {
159 xmlDictStringsPtr pool
;
161 int size
= 0; /* + sizeof(_xmlDictStrings) == 1024 */
163 #ifdef DICT_DEBUG_PATTERNS
164 fprintf(stderr
, "-");
166 pool
= dict
->strings
;
167 while (pool
!= NULL
) {
168 if (pool
->end
- pool
->free
> namelen
)
170 if (pool
->size
> size
) size
= pool
->size
;
174 * Not found, need to allocate
177 if (size
== 0) size
= 1000;
178 else size
*= 4; /* exponential growth */
179 if (size
< 4 * namelen
)
180 size
= 4 * namelen
; /* just in case ! */
181 pool
= (xmlDictStringsPtr
) xmlMalloc(sizeof(xmlDictStrings
) + size
);
186 pool
->free
= &pool
->array
[0];
187 pool
->end
= &pool
->array
[size
];
188 pool
->next
= dict
->strings
;
189 dict
->strings
= pool
;
190 #ifdef DICT_DEBUG_PATTERNS
191 fprintf(stderr
, "+");
196 memcpy(pool
->free
, name
, namelen
);
197 pool
->free
+= namelen
;
205 * @dict: the dictionnary
206 * @prefix: the prefix of the userdata
207 * @plen: the prefix length
208 * @name: the name of the userdata
209 * @len: the length of the name, if -1 it is recomputed
211 * Add the QName to the array[s]
213 * Returns the pointer of the local string, or NULL in case of error.
215 static const xmlChar
*
216 xmlDictAddQString(xmlDictPtr dict
, const xmlChar
*prefix
, int plen
,
217 const xmlChar
*name
, int namelen
)
219 xmlDictStringsPtr pool
;
221 int size
= 0; /* + sizeof(_xmlDictStrings) == 1024 */
223 if (prefix
== NULL
) return(xmlDictAddString(dict
, name
, namelen
));
225 #ifdef DICT_DEBUG_PATTERNS
226 fprintf(stderr
, "=");
228 pool
= dict
->strings
;
229 while (pool
!= NULL
) {
230 if (pool
->end
- pool
->free
> namelen
+ plen
+ 1)
232 if (pool
->size
> size
) size
= pool
->size
;
236 * Not found, need to allocate
239 if (size
== 0) size
= 1000;
240 else size
*= 4; /* exponential growth */
241 if (size
< 4 * (namelen
+ plen
+ 1))
242 size
= 4 * (namelen
+ plen
+ 1); /* just in case ! */
243 pool
= (xmlDictStringsPtr
) xmlMalloc(sizeof(xmlDictStrings
) + size
);
248 pool
->free
= &pool
->array
[0];
249 pool
->end
= &pool
->array
[size
];
250 pool
->next
= dict
->strings
;
251 dict
->strings
= pool
;
252 #ifdef DICT_DEBUG_PATTERNS
253 fprintf(stderr
, "+");
258 memcpy(pool
->free
, prefix
, plen
);
260 *(pool
->free
++) = ':';
261 memcpy(pool
->free
, name
, namelen
);
262 pool
->free
+= namelen
;
270 * xmlDictComputeBigKey:
272 * Calculate a hash key using a good hash function that works well for
273 * larger hash table sizes.
275 * Hash function by "One-at-a-Time Hash" see
276 * http://burtleburtle.net/bob/hash/doobs.html
280 xmlDictComputeBigKey(const xmlChar
* data
, int namelen
) {
284 if (namelen
<= 0 || data
== NULL
) return(0);
288 for (i
= 0;i
< namelen
; i
++) {
290 hash
+= (hash
<< 10);
294 hash
^= (hash
>> 11);
295 hash
+= (hash
<< 15);
301 * xmlDictComputeBigQKey:
303 * Calculate a hash key for two strings using a good hash function
304 * that works well for larger hash table sizes.
306 * Hash function by "One-at-a-Time Hash" see
307 * http://burtleburtle.net/bob/hash/doobs.html
309 * Neither of the two strings must be NULL.
312 xmlDictComputeBigQKey(const xmlChar
*prefix
, int plen
,
313 const xmlChar
*name
, int len
)
320 for (i
= 0;i
< plen
; i
++) {
322 hash
+= (hash
<< 10);
326 hash
+= (hash
<< 10);
329 for (i
= 0;i
< len
; i
++) {
331 hash
+= (hash
<< 10);
335 hash
^= (hash
>> 11);
336 hash
+= (hash
<< 15);
340 #endif /* WITH_BIG_KEY */
343 * xmlDictComputeFastKey:
345 * Calculate a hash key using a fast hash function that works well
346 * for low hash table fill.
349 xmlDictComputeFastKey(const xmlChar
*name
, int namelen
) {
350 unsigned long value
= 0L;
352 if (name
== NULL
) return(0);
356 value
+= name
[namelen
- 1];
360 case 10: value
+= name
[9];
361 case 9: value
+= name
[8];
362 case 8: value
+= name
[7];
363 case 7: value
+= name
[6];
364 case 6: value
+= name
[5];
365 case 5: value
+= name
[4];
366 case 4: value
+= name
[3];
367 case 3: value
+= name
[2];
368 case 2: value
+= name
[1];
375 * xmlDictComputeFastQKey:
377 * Calculate a hash key for two strings using a fast hash function
378 * that works well for low hash table fill.
380 * Neither of the two strings must be NULL.
383 xmlDictComputeFastQKey(const xmlChar
*prefix
, int plen
,
384 const xmlChar
*name
, int len
)
386 unsigned long value
= 0L;
389 value
+= 30 * (unsigned long) ':';
391 value
+= 30 * (*prefix
);
394 value
+= name
[len
- (plen
+ 1 + 1)];
400 case 10: value
+= prefix
[9];
401 case 9: value
+= prefix
[8];
402 case 8: value
+= prefix
[7];
403 case 7: value
+= prefix
[6];
404 case 6: value
+= prefix
[5];
405 case 5: value
+= prefix
[4];
406 case 4: value
+= prefix
[3];
407 case 3: value
+= prefix
[2];
408 case 2: value
+= prefix
[1];
409 case 1: value
+= prefix
[0];
414 value
+= (unsigned long) ':';
418 case 10: value
+= name
[9];
419 case 9: value
+= name
[8];
420 case 8: value
+= name
[7];
421 case 7: value
+= name
[6];
422 case 6: value
+= name
[5];
423 case 5: value
+= name
[4];
424 case 4: value
+= name
[3];
425 case 3: value
+= name
[2];
426 case 2: value
+= name
[1];
427 case 1: value
+= name
[0];
436 * Create a new dictionary
438 * Returns the newly created dictionnary, or NULL if an error occured.
441 xmlDictCreate(void) {
444 if (!xmlDictInitialized
)
445 if (!xmlInitializeDict())
448 #ifdef DICT_DEBUG_PATTERNS
449 fprintf(stderr
, "C");
452 dict
= xmlMalloc(sizeof(xmlDict
));
454 dict
->ref_counter
= 1;
456 dict
->size
= MIN_DICT_SIZE
;
458 dict
->dict
= xmlMalloc(MIN_DICT_SIZE
* sizeof(xmlDictEntry
));
459 dict
->strings
= NULL
;
460 dict
->subdict
= NULL
;
462 memset(dict
->dict
, 0, MIN_DICT_SIZE
* sizeof(xmlDictEntry
));
472 * @sub: an existing dictionnary
474 * Create a new dictionary, inheriting strings from the read-only
475 * dictionnary @sub. On lookup, strings are first searched in the
476 * new dictionnary, then in @sub, and if not found are created in the
479 * Returns the newly created dictionnary, or NULL if an error occured.
482 xmlDictCreateSub(xmlDictPtr sub
) {
483 xmlDictPtr dict
= xmlDictCreate();
485 if ((dict
!= NULL
) && (sub
!= NULL
)) {
486 #ifdef DICT_DEBUG_PATTERNS
487 fprintf(stderr
, "R");
490 xmlDictReference(dict
->subdict
);
497 * @dict: the dictionnary
499 * Increment the reference counter of a dictionary
501 * Returns 0 in case of success and -1 in case of error
504 xmlDictReference(xmlDictPtr dict
) {
505 if (!xmlDictInitialized
)
506 if (!xmlInitializeDict())
509 if (dict
== NULL
) return -1;
510 xmlRMutexLock(xmlDictMutex
);
512 xmlRMutexUnlock(xmlDictMutex
);
518 * @dict: the dictionnary
519 * @size: the new size of the dictionnary
521 * resize the dictionnary
523 * Returns 0 in case of success, -1 in case of failure
526 xmlDictGrow(xmlDictPtr dict
, int size
) {
527 unsigned long key
, okey
;
529 xmlDictEntryPtr iter
, next
;
530 struct _xmlDictEntry
*olddict
;
532 unsigned long nbElem
= 0;
544 #ifdef DICT_DEBUG_PATTERNS
545 fprintf(stderr
, "*");
548 oldsize
= dict
->size
;
549 olddict
= dict
->dict
;
552 if (oldsize
== MIN_DICT_SIZE
)
555 dict
->dict
= xmlMalloc(size
* sizeof(xmlDictEntry
));
556 if (dict
->dict
== NULL
) {
557 dict
->dict
= olddict
;
560 memset(dict
->dict
, 0, size
* sizeof(xmlDictEntry
));
563 /* If the two loops are merged, there would be situations where
564 a new entry needs to allocated and data copied into it from
565 the main dict. It is nicer to run through the array twice, first
566 copying all the elements in the main array (less probability of
567 allocate) and then the rest, so we only free in the second loop.
569 for (i
= 0; i
< oldsize
; i
++) {
570 if (olddict
[i
].valid
== 0)
574 okey
= olddict
[i
].okey
;
576 okey
= xmlDictComputeKey(dict
, olddict
[i
].name
, olddict
[i
].len
);
577 key
= okey
% dict
->size
;
579 if (dict
->dict
[key
].valid
== 0) {
580 memcpy(&(dict
->dict
[key
]), &(olddict
[i
]), sizeof(xmlDictEntry
));
581 dict
->dict
[key
].next
= NULL
;
582 dict
->dict
[key
].okey
= okey
;
584 xmlDictEntryPtr entry
;
586 entry
= xmlMalloc(sizeof(xmlDictEntry
));
588 entry
->name
= olddict
[i
].name
;
589 entry
->len
= olddict
[i
].len
;
591 entry
->next
= dict
->dict
[key
].next
;
593 dict
->dict
[key
].next
= entry
;
596 * we don't have much ways to alert from herei
597 * result is loosing an entry and unicity garantee
607 for (i
= 0; i
< oldsize
; i
++) {
608 iter
= olddict
[i
].next
;
613 * put back the entry in the new dict
619 okey
= xmlDictComputeKey(dict
, iter
->name
, iter
->len
);
620 key
= okey
% dict
->size
;
621 if (dict
->dict
[key
].valid
== 0) {
622 memcpy(&(dict
->dict
[key
]), iter
, sizeof(xmlDictEntry
));
623 dict
->dict
[key
].next
= NULL
;
624 dict
->dict
[key
].valid
= 1;
625 dict
->dict
[key
].okey
= okey
;
628 iter
->next
= dict
->dict
[key
].next
;
630 dict
->dict
[key
].next
= iter
;
644 xmlGenericError(xmlGenericErrorContext
,
645 "xmlDictGrow : from %d to %d, %d elems\n", oldsize
, size
, nbElem
);
653 * @dict: the dictionnary
655 * Free the hash @dict and its contents. The userdata is
656 * deallocated with @f if provided.
659 xmlDictFree(xmlDictPtr dict
) {
661 xmlDictEntryPtr iter
;
662 xmlDictEntryPtr next
;
664 xmlDictStringsPtr pool
, nextp
;
669 if (!xmlDictInitialized
)
670 if (!xmlInitializeDict())
673 /* decrement the counter, it may be shared by a parser and docs */
674 xmlRMutexLock(xmlDictMutex
);
676 if (dict
->ref_counter
> 0) {
677 xmlRMutexUnlock(xmlDictMutex
);
681 xmlRMutexUnlock(xmlDictMutex
);
683 if (dict
->subdict
!= NULL
) {
684 xmlDictFree(dict
->subdict
);
688 for(i
= 0; ((i
< dict
->size
) && (dict
->nbElems
> 0)); i
++) {
689 iter
= &(dict
->dict
[i
]);
690 if (iter
->valid
== 0)
704 pool
= dict
->strings
;
705 while (pool
!= NULL
) {
715 * @dict: the dictionnary
716 * @name: the name of the userdata
717 * @len: the length of the name, if -1 it is recomputed
719 * Add the @name to the dictionnary @dict if not present.
721 * Returns the internal copy of the name or NULL in case of internal error
724 xmlDictLookup(xmlDictPtr dict
, const xmlChar
*name
, int len
) {
725 unsigned long key
, okey
, nbi
= 0;
726 xmlDictEntryPtr entry
;
727 xmlDictEntryPtr insert
;
730 if ((dict
== NULL
) || (name
== NULL
))
734 len
= strlen((const char *) name
);
737 * Check for duplicate and insertion location.
739 okey
= xmlDictComputeKey(dict
, name
, len
);
740 key
= okey
% dict
->size
;
741 if (dict
->dict
[key
].valid
== 0) {
744 for (insert
= &(dict
->dict
[key
]); insert
->next
!= NULL
;
745 insert
= insert
->next
) {
747 if ((insert
->okey
== okey
) && (insert
->len
== len
)) {
748 if (!memcmp(insert
->name
, name
, len
))
749 return(insert
->name
);
752 if ((insert
->okey
== okey
) && (insert
->len
== len
) &&
753 (!xmlStrncmp(insert
->name
, name
, len
)))
754 return(insert
->name
);
759 if ((insert
->okey
== okey
) && (insert
->len
== len
)) {
760 if (!memcmp(insert
->name
, name
, len
))
761 return(insert
->name
);
764 if ((insert
->okey
== okey
) && (insert
->len
== len
) &&
765 (!xmlStrncmp(insert
->name
, name
, len
)))
766 return(insert
->name
);
773 /* we cannot always reuse the same okey for the subdict */
774 if (((dict
->size
== MIN_DICT_SIZE
) &&
775 (dict
->subdict
->size
!= MIN_DICT_SIZE
)) ||
776 ((dict
->size
!= MIN_DICT_SIZE
) &&
777 (dict
->subdict
->size
== MIN_DICT_SIZE
)))
778 skey
= xmlDictComputeKey(dict
->subdict
, name
, len
);
782 key
= skey
% dict
->subdict
->size
;
783 if (dict
->subdict
->dict
[key
].valid
!= 0) {
786 for (tmp
= &(dict
->subdict
->dict
[key
]); tmp
->next
!= NULL
;
789 if ((tmp
->okey
== skey
) && (tmp
->len
== len
)) {
790 if (!memcmp(tmp
->name
, name
, len
))
794 if ((tmp
->okey
== skey
) && (tmp
->len
== len
) &&
795 (!xmlStrncmp(tmp
->name
, name
, len
)))
801 if ((tmp
->okey
== skey
) && (tmp
->len
== len
)) {
802 if (!memcmp(tmp
->name
, name
, len
))
806 if ((tmp
->okey
== skey
) && (tmp
->len
== len
) &&
807 (!xmlStrncmp(tmp
->name
, name
, len
)))
811 key
= okey
% dict
->size
;
814 ret
= xmlDictAddString(dict
, name
, len
);
817 if (insert
== NULL
) {
818 entry
= &(dict
->dict
[key
]);
820 entry
= xmlMalloc(sizeof(xmlDictEntry
));
832 insert
->next
= entry
;
836 if ((nbi
> MAX_HASH_LEN
) &&
837 (dict
->size
<= ((MAX_DICT_HASH
/ 2) / MAX_HASH_LEN
))) {
838 if (xmlDictGrow(dict
, MAX_HASH_LEN
* 2 * dict
->size
) != 0)
841 /* Note that entry may have been freed at this point by xmlDictGrow */
848 * @dict: the dictionnary
849 * @name: the name of the userdata
850 * @len: the length of the name, if -1 it is recomputed
852 * Check if the @name exists in the dictionnary @dict.
854 * Returns the internal copy of the name or NULL if not found.
857 xmlDictExists(xmlDictPtr dict
, const xmlChar
*name
, int len
) {
858 unsigned long key
, okey
, nbi
= 0;
859 xmlDictEntryPtr insert
;
861 if ((dict
== NULL
) || (name
== NULL
))
865 len
= strlen((const char *) name
);
868 * Check for duplicate and insertion location.
870 okey
= xmlDictComputeKey(dict
, name
, len
);
871 key
= okey
% dict
->size
;
872 if (dict
->dict
[key
].valid
== 0) {
875 for (insert
= &(dict
->dict
[key
]); insert
->next
!= NULL
;
876 insert
= insert
->next
) {
878 if ((insert
->okey
== okey
) && (insert
->len
== len
)) {
879 if (!memcmp(insert
->name
, name
, len
))
880 return(insert
->name
);
883 if ((insert
->okey
== okey
) && (insert
->len
== len
) &&
884 (!xmlStrncmp(insert
->name
, name
, len
)))
885 return(insert
->name
);
890 if ((insert
->okey
== okey
) && (insert
->len
== len
)) {
891 if (!memcmp(insert
->name
, name
, len
))
892 return(insert
->name
);
895 if ((insert
->okey
== okey
) && (insert
->len
== len
) &&
896 (!xmlStrncmp(insert
->name
, name
, len
)))
897 return(insert
->name
);
904 /* we cannot always reuse the same okey for the subdict */
905 if (((dict
->size
== MIN_DICT_SIZE
) &&
906 (dict
->subdict
->size
!= MIN_DICT_SIZE
)) ||
907 ((dict
->size
!= MIN_DICT_SIZE
) &&
908 (dict
->subdict
->size
== MIN_DICT_SIZE
)))
909 skey
= xmlDictComputeKey(dict
->subdict
, name
, len
);
913 key
= skey
% dict
->subdict
->size
;
914 if (dict
->subdict
->dict
[key
].valid
!= 0) {
917 for (tmp
= &(dict
->subdict
->dict
[key
]); tmp
->next
!= NULL
;
920 if ((tmp
->okey
== skey
) && (tmp
->len
== len
)) {
921 if (!memcmp(tmp
->name
, name
, len
))
925 if ((tmp
->okey
== skey
) && (tmp
->len
== len
) &&
926 (!xmlStrncmp(tmp
->name
, name
, len
)))
932 if ((tmp
->okey
== skey
) && (tmp
->len
== len
)) {
933 if (!memcmp(tmp
->name
, name
, len
))
937 if ((tmp
->okey
== skey
) && (tmp
->len
== len
) &&
938 (!xmlStrncmp(tmp
->name
, name
, len
)))
950 * @dict: the dictionnary
951 * @prefix: the prefix
954 * Add the QName @prefix:@name to the hash @dict if not present.
956 * Returns the internal copy of the QName or NULL in case of internal error
959 xmlDictQLookup(xmlDictPtr dict
, const xmlChar
*prefix
, const xmlChar
*name
) {
960 unsigned long okey
, key
, nbi
= 0;
961 xmlDictEntryPtr entry
;
962 xmlDictEntryPtr insert
;
966 if ((dict
== NULL
) || (name
== NULL
))
969 return(xmlDictLookup(dict
, name
, -1));
971 l
= len
= strlen((const char *) name
);
972 plen
= strlen((const char *) prefix
);
976 * Check for duplicate and insertion location.
978 okey
= xmlDictComputeQKey(dict
, prefix
, plen
, name
, l
);
979 key
= okey
% dict
->size
;
980 if (dict
->dict
[key
].valid
== 0) {
983 for (insert
= &(dict
->dict
[key
]); insert
->next
!= NULL
;
984 insert
= insert
->next
) {
985 if ((insert
->okey
== okey
) && (insert
->len
== len
) &&
986 (xmlStrQEqual(prefix
, name
, insert
->name
)))
987 return(insert
->name
);
990 if ((insert
->okey
== okey
) && (insert
->len
== len
) &&
991 (xmlStrQEqual(prefix
, name
, insert
->name
)))
992 return(insert
->name
);
998 /* we cannot always reuse the same okey for the subdict */
999 if (((dict
->size
== MIN_DICT_SIZE
) &&
1000 (dict
->subdict
->size
!= MIN_DICT_SIZE
)) ||
1001 ((dict
->size
!= MIN_DICT_SIZE
) &&
1002 (dict
->subdict
->size
== MIN_DICT_SIZE
)))
1003 skey
= xmlDictComputeQKey(dict
->subdict
, prefix
, plen
, name
, l
);
1007 key
= skey
% dict
->subdict
->size
;
1008 if (dict
->subdict
->dict
[key
].valid
!= 0) {
1009 xmlDictEntryPtr tmp
;
1010 for (tmp
= &(dict
->subdict
->dict
[key
]); tmp
->next
!= NULL
;
1012 if ((tmp
->okey
== skey
) && (tmp
->len
== len
) &&
1013 (xmlStrQEqual(prefix
, name
, tmp
->name
)))
1017 if ((tmp
->okey
== skey
) && (tmp
->len
== len
) &&
1018 (xmlStrQEqual(prefix
, name
, tmp
->name
)))
1021 key
= okey
% dict
->size
;
1024 ret
= xmlDictAddQString(dict
, prefix
, plen
, name
, l
);
1027 if (insert
== NULL
) {
1028 entry
= &(dict
->dict
[key
]);
1030 entry
= xmlMalloc(sizeof(xmlDictEntry
));
1041 insert
->next
= entry
;
1045 if ((nbi
> MAX_HASH_LEN
) &&
1046 (dict
->size
<= ((MAX_DICT_HASH
/ 2) / MAX_HASH_LEN
)))
1047 xmlDictGrow(dict
, MAX_HASH_LEN
* 2 * dict
->size
);
1048 /* Note that entry may have been freed at this point by xmlDictGrow */
1055 * @dict: the dictionnary
1058 * check if a string is owned by the disctionary
1060 * Returns 1 if true, 0 if false and -1 in case of error
1061 * -1 in case of error
1064 xmlDictOwns(xmlDictPtr dict
, const xmlChar
*str
) {
1065 xmlDictStringsPtr pool
;
1067 if ((dict
== NULL
) || (str
== NULL
))
1069 pool
= dict
->strings
;
1070 while (pool
!= NULL
) {
1071 if ((str
>= &pool
->array
[0]) && (str
<= pool
->free
))
1076 return(xmlDictOwns(dict
->subdict
, str
));
1082 * @dict: the dictionnary
1084 * Query the number of elements installed in the hash @dict.
1086 * Returns the number of elements in the dictionnary or
1087 * -1 in case of error
1090 xmlDictSize(xmlDictPtr dict
) {
1094 return(dict
->nbElems
+ dict
->subdict
->nbElems
);
1095 return(dict
->nbElems
);
1100 #include "elfgcchack.h"