blob: b78bc2d4e0038c35be0768f56d2efdbe22e43e3c [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
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 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000017 * Author: breese@users.sourceforge.net
Owen Taylor3473f882001-02-23 17:55:21 +000018 */
19
Daniel Veillard34ce8be2002-03-18 19:37:11 +000020#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000021#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000022
23#include <string.h>
Daniel Veillarde57ec792003-09-10 10:50:59 +000024#include <libxml/parser.h>
Owen Taylor3473f882001-02-23 17:55:21 +000025#include <libxml/hash.h>
26#include <libxml/xmlmemory.h>
Daniel Veillarda10efa82001-04-18 13:09:01 +000027#include <libxml/xmlerror.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000028#include <libxml/globals.h>
Daniel Veillarda10efa82001-04-18 13:09:01 +000029
30#define MAX_HASH_LEN 8
31
32/* #define DEBUG_GROW */
Owen Taylor3473f882001-02-23 17:55:21 +000033
34/*
35 * A single entry in the hash table
36 */
37typedef struct _xmlHashEntry xmlHashEntry;
38typedef xmlHashEntry *xmlHashEntryPtr;
39struct _xmlHashEntry {
40 struct _xmlHashEntry *next;
41 xmlChar *name;
42 xmlChar *name2;
43 xmlChar *name3;
44 void *payload;
Daniel Veillardfdc91562002-07-01 21:52:03 +000045 int valid;
Owen Taylor3473f882001-02-23 17:55:21 +000046};
47
48/*
49 * The entire hash table
50 */
51struct _xmlHashTable {
Daniel Veillardfdc91562002-07-01 21:52:03 +000052 struct _xmlHashEntry *table;
Owen Taylor3473f882001-02-23 17:55:21 +000053 int size;
54 int nbElems;
Daniel Veillard316a5c32005-01-23 22:56:39 +000055 xmlDictPtr dict;
Owen Taylor3473f882001-02-23 17:55:21 +000056};
57
58/*
59 * xmlHashComputeKey:
60 * Calculate the hash key
61 */
62static unsigned long
Daniel Veillarda10efa82001-04-18 13:09:01 +000063xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
64 const xmlChar *name2, const xmlChar *name3) {
Owen Taylor3473f882001-02-23 17:55:21 +000065 unsigned long value = 0L;
66 char ch;
67
Daniel Veillarda10efa82001-04-18 13:09:01 +000068 if (name != NULL) {
69 value += 30 * (*name);
70 while ((ch = *name++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +000071 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +000072 }
73 }
74 if (name2 != NULL) {
75 while ((ch = *name2++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +000076 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +000077 }
78 }
79 if (name3 != NULL) {
80 while ((ch = *name3++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +000081 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +000082 }
Owen Taylor3473f882001-02-23 17:55:21 +000083 }
84 return (value % table->size);
85}
86
Daniel Veillarde57ec792003-09-10 10:50:59 +000087static unsigned long
88xmlHashComputeQKey(xmlHashTablePtr table,
Daniel Veillard8e36e6a2003-09-10 10:50:59 +000089 const xmlChar *prefix, const xmlChar *name,
90 const xmlChar *prefix2, const xmlChar *name2,
91 const xmlChar *prefix3, const xmlChar *name3) {
Daniel Veillarde57ec792003-09-10 10:50:59 +000092 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
Owen Taylor3473f882001-02-23 17:55:21 +0000136/**
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 */
144xmlHashTablePtr
145xmlHashCreate(int size) {
146 xmlHashTablePtr table;
147
148 if (size <= 0)
149 size = 256;
150
151 table = xmlMalloc(sizeof(xmlHashTable));
152 if (table) {
Daniel Veillard316a5c32005-01-23 22:56:39 +0000153 table->dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000154 table->size = size;
155 table->nbElems = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000156 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
Owen Taylor3473f882001-02-23 17:55:21 +0000157 if (table->table) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000158 memset(table->table, 0, size * sizeof(xmlHashEntry));
Owen Taylor3473f882001-02-23 17:55:21 +0000159 return(table);
160 }
161 xmlFree(table);
162 }
163 return(NULL);
164}
165
166/**
Daniel Veillard316a5c32005-01-23 22:56:39 +0000167 * 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 */
175xmlHashTablePtr
176xmlHashCreateDict(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/**
Daniel Veillarda10efa82001-04-18 13:09:01 +0000188 * 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 */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000196static int
Daniel Veillarda10efa82001-04-18 13:09:01 +0000197xmlHashGrow(xmlHashTablePtr table, int size) {
198 unsigned long key;
199 int oldsize, i;
200 xmlHashEntryPtr iter, next;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000201 struct _xmlHashEntry *oldtable;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000202#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
Daniel Veillardfdc91562002-07-01 21:52:03 +0000218 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000219 if (table->table == NULL) {
220 table->table = oldtable;
221 return(-1);
222 }
Daniel Veillardfdc91562002-07-01 21:52:03 +0000223 memset(table->table, 0, size * sizeof(xmlHashEntry));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000224 table->size = size;
225
Daniel Veillardfdc91562002-07-01 21:52:03 +0000226 /* 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 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000232 for (i = 0; i < oldsize; i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000233 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;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000243 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);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000252 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 }
Daniel Veillarda10efa82001-04-18 13:09:01 +0000260
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/**
Owen Taylor3473f882001-02-23 17:55:21 +0000280 * xmlHashFree:
281 * @table: the hash table
282 * @f: the deallocator function for items in the hash
283 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000284 * Free the hash @table and its contents. The userdata is
285 * deallocated with @f if provided.
Owen Taylor3473f882001-02-23 17:55:21 +0000286 */
287void
288xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
289 int i;
290 xmlHashEntryPtr iter;
291 xmlHashEntryPtr next;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000292 int inside_table = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000293 int nbElems;
Owen Taylor3473f882001-02-23 17:55:21 +0000294
295 if (table == NULL)
296 return;
297 if (table->table) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000298 nbElems = table->nbElems;
299 for(i = 0; (i < table->size) && (nbElems > 0); i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000300 iter = &(table->table[i]);
301 if (iter->valid == 0)
302 continue;
303 inside_table = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000304 while (iter) {
305 next = iter->next;
Daniel Veillarde991fe92003-10-29 11:18:37 +0000306 if ((f != NULL) && (iter->payload != NULL))
Daniel Veillarda10efa82001-04-18 13:09:01 +0000307 f(iter->payload, iter->name);
Daniel Veillard316a5c32005-01-23 22:56:39 +0000308 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 }
Owen Taylor3473f882001-02-23 17:55:21 +0000316 iter->payload = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000317 if (!inside_table)
318 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000319 nbElems--;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000320 inside_table = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000321 iter = next;
322 }
Owen Taylor3473f882001-02-23 17:55:21 +0000323 }
324 xmlFree(table->table);
325 }
Daniel Veillard316a5c32005-01-23 22:56:39 +0000326 if (table->dict)
327 xmlDictFree(table->dict);
Owen Taylor3473f882001-02-23 17:55:21 +0000328 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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000337 * Add the @userdata to the hash @table. This can later be retrieved
338 * by using the @name. Duplicate names generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000339 *
340 * Returns 0 the addition succeeded and -1 in case of error.
341 */
342int
343xmlHashAddEntry(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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000354 * Add the @userdata to the hash @table. This can later be retrieved
355 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000356 *
357 * Returns 0 the addition succeeded and -1 in case of error.
358 */
359int
360xmlHashAddEntry2(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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000372 * 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
Owen Taylor3473f882001-02-23 17:55:21 +0000374 * and freed with @f if found.
375 *
376 * Returns 0 the addition succeeded and -1 in case of error.
377 */
378int
379xmlHashUpdateEntry(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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000392 * 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
Owen Taylor3473f882001-02-23 17:55:21 +0000394 * be removed and freed with @f if found.
395 *
396 * Returns 0 the addition succeeded and -1 in case of error.
397 */
398int
399xmlHashUpdateEntry2(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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000410 * Find the userdata specified by the @name.
Owen Taylor3473f882001-02-23 17:55:21 +0000411 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000412 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000413 */
414void *
415xmlHashLookup(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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000425 * Find the userdata specified by the (@name, @name2) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000426 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000427 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000428 */
429void *
430xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
431 const xmlChar *name2) {
432 return(xmlHashLookup3(table, name, name2, NULL));
433}
434
435/**
Daniel Veillarde57ec792003-09-10 10:50:59 +0000436 * 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 */
445void *
446xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
447 const xmlChar *name) {
448 return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
449}
450
451/**
Daniel Veillard7a02cfe2003-09-25 12:18:34 +0000452 * xmlHashQLookup2:
Daniel Veillarde57ec792003-09-10 10:50:59 +0000453 * @table: the hash table
454 * @prefix: the prefix of the userdata
455 * @name: the name of the userdata
Daniel Veillard092643b2003-09-25 14:29:29 +0000456 * @prefix2: the second prefix of the userdata
Daniel Veillarde57ec792003-09-10 10:50:59 +0000457 * @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 */
463void *
464xmlHashQLookup2(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/**
Owen Taylor3473f882001-02-23 17:55:21 +0000471 * 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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000478 * Add the @userdata to the hash @table. This can later be retrieved
479 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
Owen Taylor3473f882001-02-23 17:55:21 +0000480 * errors.
481 *
482 * Returns 0 the addition succeeded and -1 in case of error.
483 */
484int
485xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
486 const xmlChar *name2, const xmlChar *name3,
487 void *userdata) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000488 unsigned long key, len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000489 xmlHashEntryPtr entry;
490 xmlHashEntryPtr insert;
491
Daniel Veillard316a5c32005-01-23 22:56:39 +0000492 if ((table == NULL) || (name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +0000493 return(-1);
494
495 /*
Daniel Veillard316a5c32005-01-23 22:56:39 +0000496 * 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 /*
Owen Taylor3473f882001-02-23 17:55:21 +0000517 * Check for duplicate and insertion location.
518 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000519 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000520 if (table->table[key].valid == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000521 insert = NULL;
522 } else {
Daniel Veillard316a5c32005-01-23 22:56:39 +0000523 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 }
Owen Taylor3473f882001-02-23 17:55:21 +0000545 if ((xmlStrEqual(insert->name, name)) &&
546 (xmlStrEqual(insert->name2, name2)) &&
547 (xmlStrEqual(insert->name3, name3)))
548 return(-1);
549 }
Owen Taylor3473f882001-02-23 17:55:21 +0000550 }
551
Daniel Veillardfdc91562002-07-01 21:52:03 +0000552 if (insert == NULL) {
553 entry = &(table->table[key]);
554 } else {
555 entry = xmlMalloc(sizeof(xmlHashEntry));
556 if (entry == NULL)
557 return(-1);
558 }
559
Daniel Veillard316a5c32005-01-23 22:56:39 +0000560 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 }
Owen Taylor3473f882001-02-23 17:55:21 +0000569 entry->payload = userdata;
570 entry->next = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000571 entry->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000572
573
Daniel Veillardfdc91562002-07-01 21:52:03 +0000574 if (insert != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +0000575 insert->next = entry;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000576
Owen Taylor3473f882001-02-23 17:55:21 +0000577 table->nbElems++;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000578
579 if (len > MAX_HASH_LEN)
580 xmlHashGrow(table, MAX_HASH_LEN * table->size);
581
Owen Taylor3473f882001-02-23 17:55:21 +0000582 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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000594 * 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
Owen Taylor3473f882001-02-23 17:55:21 +0000596 * will be removed and freed with @f if found.
597 *
598 * Returns 0 the addition succeeded and -1 in case of error.
599 */
600int
601xmlHashUpdateEntry3(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 /*
Daniel Veillard316a5c32005-01-23 22:56:39 +0000612 * 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 /*
Owen Taylor3473f882001-02-23 17:55:21 +0000633 * Check for duplicate and insertion location.
634 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000635 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000636 if (table->table[key].valid == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000637 insert = NULL;
638 } else {
Daniel Veillard316a5c32005-01-23 22:56:39 +0000639 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 }
Owen Taylor3473f882001-02-23 17:55:21 +0000671 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 }
Owen Taylor3473f882001-02-23 17:55:21 +0000680 }
681
Daniel Veillardfdc91562002-07-01 21:52:03 +0000682 if (insert == NULL) {
683 entry = &(table->table[key]);
684 } else {
685 entry = xmlMalloc(sizeof(xmlHashEntry));
686 if (entry == NULL)
687 return(-1);
688 }
689
Daniel Veillard316a5c32005-01-23 22:56:39 +0000690 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 }
Owen Taylor3473f882001-02-23 17:55:21 +0000699 entry->payload = userdata;
700 entry->next = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000701 entry->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000702 table->nbElems++;
703
704
Daniel Veillardfdc91562002-07-01 21:52:03 +0000705 if (insert != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000706 insert->next = entry;
707 }
708 return(0);
709}
710
711/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000712 * xmlHashLookup3:
Owen Taylor3473f882001-02-23 17:55:21 +0000713 * @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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000718 * Find the userdata specified by the (@name, @name2, @name3) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000719 *
720 * Returns the a pointer to the userdata
721 */
722void *
723xmlHashLookup3(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);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000732 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000733 if (table->table[key].valid == 0)
734 return(NULL);
Daniel Veillard316a5c32005-01-23 22:56:39 +0000735 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 }
Daniel Veillardfdc91562002-07-01 21:52:03 +0000743 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Owen Taylor3473f882001-02-23 17:55:21 +0000744 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
Daniel Veillarde57ec792003-09-10 10:50:59 +0000752/**
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 */
766void *
767xmlHashQLookup3(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
Daniel Veillard153120c2002-06-18 07:58:35 +0000791typedef struct {
792 xmlHashScanner hashscanner;
793 void *data;
794} stubData;
795
796static void
797stubHashScannerFull (void *payload, void *data, const xmlChar *name,
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000798 const xmlChar *name2 ATTRIBUTE_UNUSED,
799 const xmlChar *name3 ATTRIBUTE_UNUSED) {
Daniel Veillard153120c2002-06-18 07:58:35 +0000800 stubData *stubdata = (stubData *) data;
801 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
802}
803
Daniel Veillard01c13b52002-12-10 15:19:08 +0000804/**
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 */
Owen Taylor3473f882001-02-23 17:55:21 +0000812void
813xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
Daniel Veillard153120c2002-06-18 07:58:35 +0000814 stubData stubdata;
815 stubdata.data = data;
816 stubdata.hashscanner = f;
817 xmlHashScanFull (table, stubHashScannerFull, &stubdata);
Thomas Broyere8126242001-07-22 03:54:15 +0000818}
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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000826 * Scan the hash @table and applied @f to each value.
Thomas Broyere8126242001-07-22 03:54:15 +0000827 */
828void
829xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
Daniel Veillardac4118d2008-01-11 05:27:32 +0000830 int i, nb;
Owen Taylor3473f882001-02-23 17:55:21 +0000831 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++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000841 if (table->table[i].valid == 0)
842 continue;
843 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000844 while (iter) {
845 next = iter->next;
Daniel Veillardac4118d2008-01-11 05:27:32 +0000846 nb = table->nbElems;
Daniel Veillarde991fe92003-10-29 11:18:37 +0000847 if ((f != NULL) && (iter->payload != NULL))
Thomas Broyere8126242001-07-22 03:54:15 +0000848 f(iter->payload, data, iter->name,
849 iter->name2, iter->name3);
Daniel Veillardac4118d2008-01-11 05:27:32 +0000850 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;
Owen Taylor3473f882001-02-23 17:55:21 +0000861 }
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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000875 * Scan the hash @table and applied @f to each value matching
876 * (@name, @name2, @name3) tuple. If one of the names is null,
Owen Taylor3473f882001-02-23 17:55:21 +0000877 * the comparison is considered to match.
878 */
879void
880xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
881 const xmlChar *name2, const xmlChar *name3,
882 xmlHashScanner f, void *data) {
Thomas Broyere8126242001-07-22 03:54:15 +0000883 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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000896 * Scan the hash @table and applied @f to each value matching
897 * (@name, @name2, @name3) tuple. If one of the names is null,
Thomas Broyere8126242001-07-22 03:54:15 +0000898 * the comparison is considered to match.
899 */
900void
901xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
902 const xmlChar *name2, const xmlChar *name3,
903 xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000904 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++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000915 if (table->table[i].valid == 0)
916 continue;
917 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000918 while (iter) {
919 next = iter->next;
920 if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
921 ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
Daniel Veillarde991fe92003-10-29 11:18:37 +0000922 ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
923 (iter->payload != NULL)) {
Thomas Broyere8126242001-07-22 03:54:15 +0000924 f(iter->payload, data, iter->name,
925 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000926 }
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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000938 * Scan the hash @table and applied @f to each value.
Owen Taylor3473f882001-02-23 17:55:21 +0000939 *
940 * Returns the new table or NULL in case of error.
941 */
942xmlHashTablePtr
943xmlHashCopy(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++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000957 if (table->table[i].valid == 0)
958 continue;
959 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000960 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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000976 * Query the number of elements installed in the hash @table.
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000977 *
Owen Taylor3473f882001-02-23 17:55:21 +0000978 * Returns the number of elements in the hash table or
979 * -1 in case of error
980 */
981int
982xmlHashSize(xmlHashTablePtr table) {
983 if (table == NULL)
984 return(-1);
985 return(table->nbElems);
986}
987
988/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000989 * xmlHashRemoveEntry:
Owen Taylor3473f882001-02-23 17:55:21 +0000990 * @table: the hash table
991 * @name: the name of the userdata
992 * @f: the deallocator function for removed item (if any)
993 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000994 * Find the userdata specified by the @name and remove
995 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000996 * and freed with @f.
997 *
998 * Returns 0 if the removal succeeded and -1 in case of error or not found.
999 */
1000int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001001 xmlHashDeallocator f) {
1002 return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +00001003}
1004
1005/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00001006 * xmlHashRemoveEntry2:
Owen Taylor3473f882001-02-23 17:55:21 +00001007 * @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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001012 * 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
Owen Taylor3473f882001-02-23 17:55:21 +00001014 * and freed with @f.
1015 *
1016 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1017 */
Daniel Veillard01c13b52002-12-10 15:19:08 +00001018int
1019xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001020 const xmlChar *name2, xmlHashDeallocator f) {
1021 return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +00001022}
1023
1024/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001025 * xmlHashRemoveEntry3:
Owen Taylor3473f882001-02-23 17:55:21 +00001026 * @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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001032 * 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
Owen Taylor3473f882001-02-23 17:55:21 +00001034 * and freed with @f.
1035 *
1036 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1037 */
Daniel Veillard01c13b52002-12-10 15:19:08 +00001038int
1039xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001040 const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1041 unsigned long key;
1042 xmlHashEntryPtr entry;
1043 xmlHashEntryPtr prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001044
Daniel Veillarda10efa82001-04-18 13:09:01 +00001045 if (table == NULL || name == NULL)
1046 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001047
Daniel Veillarda10efa82001-04-18 13:09:01 +00001048 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001049 if (table->table[key].valid == 0) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001050 return(-1);
1051 } else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00001052 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001053 if (xmlStrEqual(entry->name, name) &&
1054 xmlStrEqual(entry->name2, name2) &&
1055 xmlStrEqual(entry->name3, name3)) {
Daniel Veillarde991fe92003-10-29 11:18:37 +00001056 if ((f != NULL) && (entry->payload != NULL))
Daniel Veillarda10efa82001-04-18 13:09:01 +00001057 f(entry->payload, entry->name);
1058 entry->payload = NULL;
Daniel Veillard316a5c32005-01-23 22:56:39 +00001059 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 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001067 if(prev) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001068 prev->next = entry->next;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001069 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 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001079 table->nbElems--;
1080 return(0);
1081 }
1082 prev = entry;
1083 }
1084 return(-1);
1085 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001086}
1087
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001088#define bottom_hash
1089#include "elfgcchack.h"