blob: f1bfb9265359e06f6cd43fd1612292d565635bfe [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>
24#include <libxml/hash.h>
25#include <libxml/xmlmemory.h>
26#include <libxml/parser.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;
45};
46
47/*
48 * The entire hash table
49 */
50struct _xmlHashTable {
51 struct _xmlHashEntry **table;
52 int size;
53 int nbElems;
54};
55
56/*
57 * xmlHashComputeKey:
58 * Calculate the hash key
59 */
60static unsigned long
Daniel Veillarda10efa82001-04-18 13:09:01 +000061xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
62 const xmlChar *name2, const xmlChar *name3) {
Owen Taylor3473f882001-02-23 17:55:21 +000063 unsigned long value = 0L;
64 char ch;
65
Daniel Veillarda10efa82001-04-18 13:09:01 +000066 if (name != NULL) {
67 value += 30 * (*name);
68 while ((ch = *name++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +000069 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +000070 }
71 }
72 if (name2 != NULL) {
73 while ((ch = *name2++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +000074 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +000075 }
76 }
77 if (name3 != NULL) {
78 while ((ch = *name3++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +000079 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +000080 }
Owen Taylor3473f882001-02-23 17:55:21 +000081 }
82 return (value % table->size);
83}
84
85/**
86 * xmlHashCreate:
87 * @size: the size of the hash table
88 *
89 * Create a new xmlHashTablePtr.
90 *
91 * Returns the newly created object, or NULL if an error occured.
92 */
93xmlHashTablePtr
94xmlHashCreate(int size) {
95 xmlHashTablePtr table;
96
97 if (size <= 0)
98 size = 256;
99
100 table = xmlMalloc(sizeof(xmlHashTable));
101 if (table) {
102 table->size = size;
103 table->nbElems = 0;
Daniel Veillard314cfa02002-01-14 17:58:01 +0000104 table->table = xmlMalloc(size * sizeof(xmlHashEntryPtr));
Owen Taylor3473f882001-02-23 17:55:21 +0000105 if (table->table) {
Daniel Veillard314cfa02002-01-14 17:58:01 +0000106 memset(table->table, 0, size * sizeof(xmlHashEntryPtr));
Owen Taylor3473f882001-02-23 17:55:21 +0000107 return(table);
108 }
109 xmlFree(table);
110 }
111 return(NULL);
112}
113
114/**
Daniel Veillarda10efa82001-04-18 13:09:01 +0000115 * xmlHashGrow:
116 * @table: the hash table
117 * @size: the new size of the hash table
118 *
119 * resize the hash table
120 *
121 * Returns 0 in case of success, -1 in case of failure
122 */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000123static int
Daniel Veillarda10efa82001-04-18 13:09:01 +0000124xmlHashGrow(xmlHashTablePtr table, int size) {
125 unsigned long key;
126 int oldsize, i;
127 xmlHashEntryPtr iter, next;
128 struct _xmlHashEntry **oldtable;
129#ifdef DEBUG_GROW
130 unsigned long nbElem = 0;
131#endif
132
133 if (table == NULL)
134 return(-1);
135 if (size < 8)
136 return(-1);
137 if (size > 8 * 2048)
138 return(-1);
139
140 oldsize = table->size;
141 oldtable = table->table;
142 if (oldtable == NULL)
143 return(-1);
144
Daniel Veillard314cfa02002-01-14 17:58:01 +0000145 table->table = xmlMalloc(size * sizeof(xmlHashEntryPtr));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000146 if (table->table == NULL) {
147 table->table = oldtable;
148 return(-1);
149 }
Daniel Veillard314cfa02002-01-14 17:58:01 +0000150 memset(table->table, 0, size * sizeof(xmlHashEntryPtr));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000151 table->size = size;
152
153 for (i = 0; i < oldsize; i++) {
154 iter = oldtable[i];
155 while (iter) {
156 next = iter->next;
157
158 /*
159 * put back the entry in the new table
160 */
161
162 key = xmlHashComputeKey(table, iter->name, iter->name2,
163 iter->name3);
164 iter->next = table->table[key];
165 table->table[key] = iter;
166
167#ifdef DEBUG_GROW
168 nbElem++;
169#endif
170
171 iter = next;
172 }
173 }
174
175 xmlFree(oldtable);
176
177#ifdef DEBUG_GROW
178 xmlGenericError(xmlGenericErrorContext,
179 "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
180#endif
181
182 return(0);
183}
184
185/**
Owen Taylor3473f882001-02-23 17:55:21 +0000186 * xmlHashFree:
187 * @table: the hash table
188 * @f: the deallocator function for items in the hash
189 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000190 * Free the hash @table and its contents. The userdata is
191 * deallocated with @f if provided.
Owen Taylor3473f882001-02-23 17:55:21 +0000192 */
193void
194xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
195 int i;
196 xmlHashEntryPtr iter;
197 xmlHashEntryPtr next;
198
199 if (table == NULL)
200 return;
201 if (table->table) {
202 for(i = 0; i < table->size; i++) {
203 iter = table->table[i];
204 while (iter) {
205 next = iter->next;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000206 if (f)
207 f(iter->payload, iter->name);
Owen Taylor3473f882001-02-23 17:55:21 +0000208 if (iter->name)
209 xmlFree(iter->name);
210 if (iter->name2)
211 xmlFree(iter->name2);
212 if (iter->name3)
213 xmlFree(iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000214 iter->payload = NULL;
215 xmlFree(iter);
216 iter = next;
217 }
218 table->table[i] = NULL;
219 }
220 xmlFree(table->table);
221 }
222 xmlFree(table);
223}
224
225/**
226 * xmlHashAddEntry:
227 * @table: the hash table
228 * @name: the name of the userdata
229 * @userdata: a pointer to the userdata
230 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000231 * Add the @userdata to the hash @table. This can later be retrieved
232 * by using the @name. Duplicate names generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000233 *
234 * Returns 0 the addition succeeded and -1 in case of error.
235 */
236int
237xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
238 return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
239}
240
241/**
242 * xmlHashAddEntry2:
243 * @table: the hash table
244 * @name: the name of the userdata
245 * @name2: a second name of the userdata
246 * @userdata: a pointer to the userdata
247 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000248 * Add the @userdata to the hash @table. This can later be retrieved
249 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000250 *
251 * Returns 0 the addition succeeded and -1 in case of error.
252 */
253int
254xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
255 const xmlChar *name2, void *userdata) {
256 return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
257}
258
259/**
260 * xmlHashUpdateEntry:
261 * @table: the hash table
262 * @name: the name of the userdata
263 * @userdata: a pointer to the userdata
264 * @f: the deallocator function for replaced item (if any)
265 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000266 * Add the @userdata to the hash @table. This can later be retrieved
267 * by using the @name. Existing entry for this @name will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000268 * and freed with @f if found.
269 *
270 * Returns 0 the addition succeeded and -1 in case of error.
271 */
272int
273xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
274 void *userdata, xmlHashDeallocator f) {
275 return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
276}
277
278/**
279 * xmlHashUpdateEntry2:
280 * @table: the hash table
281 * @name: the name of the userdata
282 * @name2: a second name of the userdata
283 * @userdata: a pointer to the userdata
284 * @f: the deallocator function for replaced item (if any)
285 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000286 * Add the @userdata to the hash @table. This can later be retrieved
287 * by using the (@name, @name2) tuple. Existing entry for this tuple will
Owen Taylor3473f882001-02-23 17:55:21 +0000288 * be removed and freed with @f if found.
289 *
290 * Returns 0 the addition succeeded and -1 in case of error.
291 */
292int
293xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
294 const xmlChar *name2, void *userdata,
295 xmlHashDeallocator f) {
296 return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
297}
298
299/**
300 * xmlHashLookup:
301 * @table: the hash table
302 * @name: the name of the userdata
303 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000304 * Find the userdata specified by the @name.
Owen Taylor3473f882001-02-23 17:55:21 +0000305 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000306 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000307 */
308void *
309xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
310 return(xmlHashLookup3(table, name, NULL, NULL));
311}
312
313/**
314 * xmlHashLookup2:
315 * @table: the hash table
316 * @name: the name of the userdata
317 * @name2: a second name of the userdata
318 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000319 * Find the userdata specified by the (@name, @name2) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000320 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000321 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000322 */
323void *
324xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
325 const xmlChar *name2) {
326 return(xmlHashLookup3(table, name, name2, NULL));
327}
328
329/**
330 * xmlHashAddEntry3:
331 * @table: the hash table
332 * @name: the name of the userdata
333 * @name2: a second name of the userdata
334 * @name3: a third 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 tuple (@name, @name2, @name3). Duplicate entries generate
Owen Taylor3473f882001-02-23 17:55:21 +0000339 * errors.
340 *
341 * Returns 0 the addition succeeded and -1 in case of error.
342 */
343int
344xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
345 const xmlChar *name2, const xmlChar *name3,
346 void *userdata) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000347 unsigned long key, len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000348 xmlHashEntryPtr entry;
349 xmlHashEntryPtr insert;
350
351 if ((table == NULL) || name == NULL)
352 return(-1);
353
354 /*
355 * Check for duplicate and insertion location.
356 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000357 key = xmlHashComputeKey(table, name, name2, name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000358 if (table->table[key] == NULL) {
359 insert = NULL;
360 } else {
361 for (insert = table->table[key]; insert->next != NULL;
362 insert = insert->next) {
363 if ((xmlStrEqual(insert->name, name)) &&
364 (xmlStrEqual(insert->name2, name2)) &&
365 (xmlStrEqual(insert->name3, name3)))
366 return(-1);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000367 len++;
Owen Taylor3473f882001-02-23 17:55:21 +0000368 }
369 if ((xmlStrEqual(insert->name, name)) &&
370 (xmlStrEqual(insert->name2, name2)) &&
371 (xmlStrEqual(insert->name3, name3)))
372 return(-1);
373 }
374
375 entry = xmlMalloc(sizeof(xmlHashEntry));
376 if (entry == NULL)
377 return(-1);
378 entry->name = xmlStrdup(name);
379 entry->name2 = xmlStrdup(name2);
380 entry->name3 = xmlStrdup(name3);
381 entry->payload = userdata;
382 entry->next = NULL;
383
384
385 if (insert == NULL) {
386 table->table[key] = entry;
387 } else {
388 insert->next = entry;
389 }
390 table->nbElems++;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000391
392 if (len > MAX_HASH_LEN)
393 xmlHashGrow(table, MAX_HASH_LEN * table->size);
394
Owen Taylor3473f882001-02-23 17:55:21 +0000395 return(0);
396}
397
398/**
399 * xmlHashUpdateEntry3:
400 * @table: the hash table
401 * @name: the name of the userdata
402 * @name2: a second name of the userdata
403 * @name3: a third name of the userdata
404 * @userdata: a pointer to the userdata
405 * @f: the deallocator function for replaced item (if any)
406 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000407 * Add the @userdata to the hash @table. This can later be retrieved
408 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
Owen Taylor3473f882001-02-23 17:55:21 +0000409 * will be removed and freed with @f if found.
410 *
411 * Returns 0 the addition succeeded and -1 in case of error.
412 */
413int
414xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
415 const xmlChar *name2, const xmlChar *name3,
416 void *userdata, xmlHashDeallocator f) {
417 unsigned long key;
418 xmlHashEntryPtr entry;
419 xmlHashEntryPtr insert;
420
421 if ((table == NULL) || name == NULL)
422 return(-1);
423
424 /*
425 * Check for duplicate and insertion location.
426 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000427 key = xmlHashComputeKey(table, name, name2, name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000428 if (table->table[key] == NULL) {
429 insert = NULL;
430 } else {
431 for (insert = table->table[key]; insert->next != NULL;
432 insert = insert->next) {
433 if ((xmlStrEqual(insert->name, name)) &&
434 (xmlStrEqual(insert->name2, name2)) &&
435 (xmlStrEqual(insert->name3, name3))) {
436 if (f)
437 f(insert->payload, insert->name);
438 insert->payload = userdata;
439 return(0);
440 }
441 }
442 if ((xmlStrEqual(insert->name, name)) &&
443 (xmlStrEqual(insert->name2, name2)) &&
444 (xmlStrEqual(insert->name3, name3))) {
445 if (f)
446 f(insert->payload, insert->name);
447 insert->payload = userdata;
448 return(0);
449 }
450 }
451
452 entry = xmlMalloc(sizeof(xmlHashEntry));
453 if (entry == NULL)
454 return(-1);
455 entry->name = xmlStrdup(name);
456 entry->name2 = xmlStrdup(name2);
457 entry->name3 = xmlStrdup(name3);
458 entry->payload = userdata;
459 entry->next = NULL;
460 table->nbElems++;
461
462
463 if (insert == NULL) {
464 table->table[key] = entry;
465 } else {
466 insert->next = entry;
467 }
468 return(0);
469}
470
471/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000472 * xmlHashLookup3:
Owen Taylor3473f882001-02-23 17:55:21 +0000473 * @table: the hash table
474 * @name: the name of the userdata
475 * @name2: a second name of the userdata
476 * @name3: a third name of the userdata
477 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000478 * Find the userdata specified by the (@name, @name2, @name3) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000479 *
480 * Returns the a pointer to the userdata
481 */
482void *
483xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
484 const xmlChar *name2, const xmlChar *name3) {
485 unsigned long key;
486 xmlHashEntryPtr entry;
487
488 if (table == NULL)
489 return(NULL);
490 if (name == NULL)
491 return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000492 key = xmlHashComputeKey(table, name, name2, name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000493 for (entry = table->table[key]; entry != NULL; entry = entry->next) {
494 if ((xmlStrEqual(entry->name, name)) &&
495 (xmlStrEqual(entry->name2, name2)) &&
496 (xmlStrEqual(entry->name3, name3)))
497 return(entry->payload);
498 }
499 return(NULL);
500}
501
502/**
503 * xmlHashScan:
504 * @table: the hash table
505 * @f: the scanner function for items in the hash
506 * @data: extra data passed to f
507 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000508 * Scan the hash @table and applied @f to each value.
Owen Taylor3473f882001-02-23 17:55:21 +0000509 */
Daniel Veillard153120c2002-06-18 07:58:35 +0000510typedef struct {
511 xmlHashScanner hashscanner;
512 void *data;
513} stubData;
514
515static void
516stubHashScannerFull (void *payload, void *data, const xmlChar *name,
517 const xmlChar *name2, const xmlChar *name3
518) {
519 stubData *stubdata = (stubData *) data;
520 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
521}
522
Owen Taylor3473f882001-02-23 17:55:21 +0000523void
524xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
Daniel Veillard153120c2002-06-18 07:58:35 +0000525 stubData stubdata;
526 stubdata.data = data;
527 stubdata.hashscanner = f;
528 xmlHashScanFull (table, stubHashScannerFull, &stubdata);
Thomas Broyere8126242001-07-22 03:54:15 +0000529}
530
531/**
532 * xmlHashScanFull:
533 * @table: the hash table
534 * @f: the scanner function for items in the hash
535 * @data: extra data passed to f
536 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000537 * Scan the hash @table and applied @f to each value.
Thomas Broyere8126242001-07-22 03:54:15 +0000538 */
539void
540xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000541 int i;
542 xmlHashEntryPtr iter;
543 xmlHashEntryPtr next;
544
545 if (table == NULL)
546 return;
547 if (f == NULL)
548 return;
549
550 if (table->table) {
551 for(i = 0; i < table->size; i++) {
552 iter = table->table[i];
553 while (iter) {
554 next = iter->next;
555 if (f)
Thomas Broyere8126242001-07-22 03:54:15 +0000556 f(iter->payload, data, iter->name,
557 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000558 iter = next;
559 }
560 }
561 }
562}
563
564/**
565 * xmlHashScan3:
566 * @table: the hash table
567 * @name: the name of the userdata or NULL
568 * @name2: a second name of the userdata or NULL
569 * @name3: a third name of the userdata or NULL
570 * @f: the scanner function for items in the hash
571 * @data: extra data passed to f
572 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000573 * Scan the hash @table and applied @f to each value matching
574 * (@name, @name2, @name3) tuple. If one of the names is null,
Owen Taylor3473f882001-02-23 17:55:21 +0000575 * the comparison is considered to match.
576 */
577void
578xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
579 const xmlChar *name2, const xmlChar *name3,
580 xmlHashScanner f, void *data) {
Thomas Broyere8126242001-07-22 03:54:15 +0000581 xmlHashScanFull3 (table, name, name2, name3,
582 (xmlHashScannerFull) f, data);
583}
584
585/**
586 * xmlHashScanFull3:
587 * @table: the hash table
588 * @name: the name of the userdata or NULL
589 * @name2: a second name of the userdata or NULL
590 * @name3: a third name of the userdata or NULL
591 * @f: the scanner function for items in the hash
592 * @data: extra data passed to f
593 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000594 * Scan the hash @table and applied @f to each value matching
595 * (@name, @name2, @name3) tuple. If one of the names is null,
Thomas Broyere8126242001-07-22 03:54:15 +0000596 * the comparison is considered to match.
597 */
598void
599xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
600 const xmlChar *name2, const xmlChar *name3,
601 xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000602 int i;
603 xmlHashEntryPtr iter;
604 xmlHashEntryPtr next;
605
606 if (table == NULL)
607 return;
608 if (f == NULL)
609 return;
610
611 if (table->table) {
612 for(i = 0; i < table->size; i++) {
613 iter = table->table[i];
614 while (iter) {
615 next = iter->next;
616 if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
617 ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
618 ((name3 == NULL) || (xmlStrEqual(name3, iter->name3)))) {
Thomas Broyere8126242001-07-22 03:54:15 +0000619 f(iter->payload, data, iter->name,
620 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000621 }
622 iter = next;
623 }
624 }
625 }
626}
627
628/**
629 * xmlHashCopy:
630 * @table: the hash table
631 * @f: the copier function for items in the hash
632 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000633 * Scan the hash @table and applied @f to each value.
Owen Taylor3473f882001-02-23 17:55:21 +0000634 *
635 * Returns the new table or NULL in case of error.
636 */
637xmlHashTablePtr
638xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
639 int i;
640 xmlHashEntryPtr iter;
641 xmlHashEntryPtr next;
642 xmlHashTablePtr ret;
643
644 if (table == NULL)
645 return(NULL);
646 if (f == NULL)
647 return(NULL);
648
649 ret = xmlHashCreate(table->size);
650 if (table->table) {
651 for(i = 0; i < table->size; i++) {
652 iter = table->table[i];
653 while (iter) {
654 next = iter->next;
655 xmlHashAddEntry3(ret, iter->name, iter->name2,
656 iter->name3, f(iter->payload, iter->name));
657 iter = next;
658 }
659 }
660 }
661 ret->nbElems = table->nbElems;
662 return(ret);
663}
664
665/**
666 * xmlHashSize:
667 * @table: the hash table
668 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000669 * Query the number of elements installed in the hash @table.
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000670 *
Owen Taylor3473f882001-02-23 17:55:21 +0000671 * Returns the number of elements in the hash table or
672 * -1 in case of error
673 */
674int
675xmlHashSize(xmlHashTablePtr table) {
676 if (table == NULL)
677 return(-1);
678 return(table->nbElems);
679}
680
681/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000682 * xmlHashRemoveEntry:
Owen Taylor3473f882001-02-23 17:55:21 +0000683 * @table: the hash table
684 * @name: the name of the userdata
685 * @f: the deallocator function for removed item (if any)
686 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000687 * Find the userdata specified by the @name and remove
688 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000689 * and freed with @f.
690 *
691 * Returns 0 if the removal succeeded and -1 in case of error or not found.
692 */
693int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000694 xmlHashDeallocator f) {
695 return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +0000696}
697
698/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000699 * xmlHashRemoveEntry2:
Owen Taylor3473f882001-02-23 17:55:21 +0000700 * @table: the hash table
701 * @name: the name of the userdata
702 * @name2: a second name of the userdata
703 * @f: the deallocator function for removed item (if any)
704 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000705 * Find the userdata specified by the (@name, @name2) tuple and remove
706 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000707 * and freed with @f.
708 *
709 * Returns 0 if the removal succeeded and -1 in case of error or not found.
710 */
711int xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000712 const xmlChar *name2, xmlHashDeallocator f) {
713 return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +0000714}
715
716/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000717 * xmlHashRemoveEntry3
Owen Taylor3473f882001-02-23 17:55:21 +0000718 * @table: the hash table
719 * @name: the name of the userdata
720 * @name2: a second name of the userdata
721 * @name3: a third name of the userdata
722 * @f: the deallocator function for removed item (if any)
723 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000724 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
725 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000726 * and freed with @f.
727 *
728 * Returns 0 if the removal succeeded and -1 in case of error or not found.
729 */
730int xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000731 const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
732 unsigned long key;
733 xmlHashEntryPtr entry;
734 xmlHashEntryPtr prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000735
Daniel Veillarda10efa82001-04-18 13:09:01 +0000736 if (table == NULL || name == NULL)
737 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000738
Daniel Veillarda10efa82001-04-18 13:09:01 +0000739 key = xmlHashComputeKey(table, name, name2, name3);
740 if (table->table[key] == NULL) {
741 return(-1);
742 } else {
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 if(f)
748 f(entry->payload, entry->name);
749 entry->payload = NULL;
750 if(entry->name)
751 xmlFree(entry->name);
752 if(entry->name2)
753 xmlFree(entry->name2);
754 if(entry->name3)
755 xmlFree(entry->name3);
756 if(prev)
757 prev->next = entry->next;
758 else
759 table->table[key] = entry->next;
760 xmlFree(entry);
761 table->nbElems--;
762 return(0);
763 }
764 prev = entry;
765 }
766 return(-1);
767 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000768}
769