blob: f01e6b90db8e9f84231590a7cd105dcbdb863781 [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) {
69 /* value *= 31; */
70 value += (unsigned long)ch;
71 }
72 }
73 if (name2 != NULL) {
74 while ((ch = *name2++) != 0) {
75 /* value *= 31; */
76 value += (unsigned long)ch;
77 }
78 }
79 if (name3 != NULL) {
80 while ((ch = *name3++) != 0) {
81 /* value *= 31; */
82 value += (unsigned long)ch;
83 }
Owen Taylor3473f882001-02-23 17:55:21 +000084 }
85 return (value % table->size);
86}
87
88/**
89 * xmlHashCreate:
90 * @size: the size of the hash table
91 *
92 * Create a new xmlHashTablePtr.
93 *
94 * Returns the newly created object, or NULL if an error occured.
95 */
96xmlHashTablePtr
97xmlHashCreate(int size) {
98 xmlHashTablePtr table;
99
100 if (size <= 0)
101 size = 256;
102
103 table = xmlMalloc(sizeof(xmlHashTable));
104 if (table) {
105 table->size = size;
106 table->nbElems = 0;
Daniel Veillard314cfa02002-01-14 17:58:01 +0000107 table->table = xmlMalloc(size * sizeof(xmlHashEntryPtr));
Owen Taylor3473f882001-02-23 17:55:21 +0000108 if (table->table) {
Daniel Veillard314cfa02002-01-14 17:58:01 +0000109 memset(table->table, 0, size * sizeof(xmlHashEntryPtr));
Owen Taylor3473f882001-02-23 17:55:21 +0000110 return(table);
111 }
112 xmlFree(table);
113 }
114 return(NULL);
115}
116
117/**
Daniel Veillarda10efa82001-04-18 13:09:01 +0000118 * xmlHashGrow:
119 * @table: the hash table
120 * @size: the new size of the hash table
121 *
122 * resize the hash table
123 *
124 * Returns 0 in case of success, -1 in case of failure
125 */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000126static int
Daniel Veillarda10efa82001-04-18 13:09:01 +0000127xmlHashGrow(xmlHashTablePtr table, int size) {
128 unsigned long key;
129 int oldsize, i;
130 xmlHashEntryPtr iter, next;
131 struct _xmlHashEntry **oldtable;
132#ifdef DEBUG_GROW
133 unsigned long nbElem = 0;
134#endif
135
136 if (table == NULL)
137 return(-1);
138 if (size < 8)
139 return(-1);
140 if (size > 8 * 2048)
141 return(-1);
142
143 oldsize = table->size;
144 oldtable = table->table;
145 if (oldtable == NULL)
146 return(-1);
147
Daniel Veillard314cfa02002-01-14 17:58:01 +0000148 table->table = xmlMalloc(size * sizeof(xmlHashEntryPtr));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000149 if (table->table == NULL) {
150 table->table = oldtable;
151 return(-1);
152 }
Daniel Veillard314cfa02002-01-14 17:58:01 +0000153 memset(table->table, 0, size * sizeof(xmlHashEntryPtr));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000154 table->size = size;
155
156 for (i = 0; i < oldsize; i++) {
157 iter = oldtable[i];
158 while (iter) {
159 next = iter->next;
160
161 /*
162 * put back the entry in the new table
163 */
164
165 key = xmlHashComputeKey(table, iter->name, iter->name2,
166 iter->name3);
167 iter->next = table->table[key];
168 table->table[key] = iter;
169
170#ifdef DEBUG_GROW
171 nbElem++;
172#endif
173
174 iter = next;
175 }
176 }
177
178 xmlFree(oldtable);
179
180#ifdef DEBUG_GROW
181 xmlGenericError(xmlGenericErrorContext,
182 "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
183#endif
184
185 return(0);
186}
187
188/**
Owen Taylor3473f882001-02-23 17:55:21 +0000189 * xmlHashFree:
190 * @table: the hash table
191 * @f: the deallocator function for items in the hash
192 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000193 * Free the hash @table and its contents. The userdata is
194 * deallocated with @f if provided.
Owen Taylor3473f882001-02-23 17:55:21 +0000195 */
196void
197xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
198 int i;
199 xmlHashEntryPtr iter;
200 xmlHashEntryPtr next;
201
202 if (table == NULL)
203 return;
204 if (table->table) {
205 for(i = 0; i < table->size; i++) {
206 iter = table->table[i];
207 while (iter) {
208 next = iter->next;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000209 if (f)
210 f(iter->payload, iter->name);
Owen Taylor3473f882001-02-23 17:55:21 +0000211 if (iter->name)
212 xmlFree(iter->name);
213 if (iter->name2)
214 xmlFree(iter->name2);
215 if (iter->name3)
216 xmlFree(iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000217 iter->payload = NULL;
218 xmlFree(iter);
219 iter = next;
220 }
221 table->table[i] = NULL;
222 }
223 xmlFree(table->table);
224 }
225 xmlFree(table);
226}
227
228/**
229 * xmlHashAddEntry:
230 * @table: the hash table
231 * @name: the name of the userdata
232 * @userdata: a pointer to the userdata
233 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000234 * Add the @userdata to the hash @table. This can later be retrieved
235 * by using the @name. Duplicate names generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000236 *
237 * Returns 0 the addition succeeded and -1 in case of error.
238 */
239int
240xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
241 return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
242}
243
244/**
245 * xmlHashAddEntry2:
246 * @table: the hash table
247 * @name: the name of the userdata
248 * @name2: a second name of the userdata
249 * @userdata: a pointer to the userdata
250 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000251 * Add the @userdata to the hash @table. This can later be retrieved
252 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000253 *
254 * Returns 0 the addition succeeded and -1 in case of error.
255 */
256int
257xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
258 const xmlChar *name2, void *userdata) {
259 return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
260}
261
262/**
263 * xmlHashUpdateEntry:
264 * @table: the hash table
265 * @name: the name of the userdata
266 * @userdata: a pointer to the userdata
267 * @f: the deallocator function for replaced item (if any)
268 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000269 * Add the @userdata to the hash @table. This can later be retrieved
270 * by using the @name. Existing entry for this @name will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000271 * and freed with @f if found.
272 *
273 * Returns 0 the addition succeeded and -1 in case of error.
274 */
275int
276xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
277 void *userdata, xmlHashDeallocator f) {
278 return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
279}
280
281/**
282 * xmlHashUpdateEntry2:
283 * @table: the hash table
284 * @name: the name of the userdata
285 * @name2: a second name of the userdata
286 * @userdata: a pointer to the userdata
287 * @f: the deallocator function for replaced item (if any)
288 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000289 * Add the @userdata to the hash @table. This can later be retrieved
290 * by using the (@name, @name2) tuple. Existing entry for this tuple will
Owen Taylor3473f882001-02-23 17:55:21 +0000291 * be removed and freed with @f if found.
292 *
293 * Returns 0 the addition succeeded and -1 in case of error.
294 */
295int
296xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
297 const xmlChar *name2, void *userdata,
298 xmlHashDeallocator f) {
299 return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
300}
301
302/**
303 * xmlHashLookup:
304 * @table: the hash table
305 * @name: the name of the userdata
306 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000307 * Find the userdata specified by the @name.
Owen Taylor3473f882001-02-23 17:55:21 +0000308 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000309 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000310 */
311void *
312xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
313 return(xmlHashLookup3(table, name, NULL, NULL));
314}
315
316/**
317 * xmlHashLookup2:
318 * @table: the hash table
319 * @name: the name of the userdata
320 * @name2: a second name of the userdata
321 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000322 * Find the userdata specified by the (@name, @name2) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000323 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000324 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000325 */
326void *
327xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
328 const xmlChar *name2) {
329 return(xmlHashLookup3(table, name, name2, NULL));
330}
331
332/**
333 * xmlHashAddEntry3:
334 * @table: the hash table
335 * @name: the name of the userdata
336 * @name2: a second name of the userdata
337 * @name3: a third name of the userdata
338 * @userdata: a pointer to the userdata
339 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000340 * Add the @userdata to the hash @table. This can later be retrieved
341 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
Owen Taylor3473f882001-02-23 17:55:21 +0000342 * errors.
343 *
344 * Returns 0 the addition succeeded and -1 in case of error.
345 */
346int
347xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
348 const xmlChar *name2, const xmlChar *name3,
349 void *userdata) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000350 unsigned long key, len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000351 xmlHashEntryPtr entry;
352 xmlHashEntryPtr insert;
353
354 if ((table == NULL) || name == NULL)
355 return(-1);
356
357 /*
358 * Check for duplicate and insertion location.
359 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000360 key = xmlHashComputeKey(table, name, name2, name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000361 if (table->table[key] == NULL) {
362 insert = NULL;
363 } else {
364 for (insert = table->table[key]; insert->next != NULL;
365 insert = insert->next) {
366 if ((xmlStrEqual(insert->name, name)) &&
367 (xmlStrEqual(insert->name2, name2)) &&
368 (xmlStrEqual(insert->name3, name3)))
369 return(-1);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000370 len++;
Owen Taylor3473f882001-02-23 17:55:21 +0000371 }
372 if ((xmlStrEqual(insert->name, name)) &&
373 (xmlStrEqual(insert->name2, name2)) &&
374 (xmlStrEqual(insert->name3, name3)))
375 return(-1);
376 }
377
378 entry = xmlMalloc(sizeof(xmlHashEntry));
379 if (entry == NULL)
380 return(-1);
381 entry->name = xmlStrdup(name);
382 entry->name2 = xmlStrdup(name2);
383 entry->name3 = xmlStrdup(name3);
384 entry->payload = userdata;
385 entry->next = NULL;
386
387
388 if (insert == NULL) {
389 table->table[key] = entry;
390 } else {
391 insert->next = entry;
392 }
393 table->nbElems++;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000394
395 if (len > MAX_HASH_LEN)
396 xmlHashGrow(table, MAX_HASH_LEN * table->size);
397
Owen Taylor3473f882001-02-23 17:55:21 +0000398 return(0);
399}
400
401/**
402 * xmlHashUpdateEntry3:
403 * @table: the hash table
404 * @name: the name of the userdata
405 * @name2: a second name of the userdata
406 * @name3: a third name of the userdata
407 * @userdata: a pointer to the userdata
408 * @f: the deallocator function for replaced item (if any)
409 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000410 * Add the @userdata to the hash @table. This can later be retrieved
411 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
Owen Taylor3473f882001-02-23 17:55:21 +0000412 * will be removed and freed with @f if found.
413 *
414 * Returns 0 the addition succeeded and -1 in case of error.
415 */
416int
417xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
418 const xmlChar *name2, const xmlChar *name3,
419 void *userdata, xmlHashDeallocator f) {
420 unsigned long key;
421 xmlHashEntryPtr entry;
422 xmlHashEntryPtr insert;
423
424 if ((table == NULL) || name == NULL)
425 return(-1);
426
427 /*
428 * Check for duplicate and insertion location.
429 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000430 key = xmlHashComputeKey(table, name, name2, name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000431 if (table->table[key] == NULL) {
432 insert = NULL;
433 } else {
434 for (insert = table->table[key]; insert->next != NULL;
435 insert = insert->next) {
436 if ((xmlStrEqual(insert->name, name)) &&
437 (xmlStrEqual(insert->name2, name2)) &&
438 (xmlStrEqual(insert->name3, name3))) {
439 if (f)
440 f(insert->payload, insert->name);
441 insert->payload = userdata;
442 return(0);
443 }
444 }
445 if ((xmlStrEqual(insert->name, name)) &&
446 (xmlStrEqual(insert->name2, name2)) &&
447 (xmlStrEqual(insert->name3, name3))) {
448 if (f)
449 f(insert->payload, insert->name);
450 insert->payload = userdata;
451 return(0);
452 }
453 }
454
455 entry = xmlMalloc(sizeof(xmlHashEntry));
456 if (entry == NULL)
457 return(-1);
458 entry->name = xmlStrdup(name);
459 entry->name2 = xmlStrdup(name2);
460 entry->name3 = xmlStrdup(name3);
461 entry->payload = userdata;
462 entry->next = NULL;
463 table->nbElems++;
464
465
466 if (insert == NULL) {
467 table->table[key] = entry;
468 } else {
469 insert->next = entry;
470 }
471 return(0);
472}
473
474/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000475 * xmlHashLookup3:
Owen Taylor3473f882001-02-23 17:55:21 +0000476 * @table: the hash table
477 * @name: the name of the userdata
478 * @name2: a second name of the userdata
479 * @name3: a third name of the userdata
480 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000481 * Find the userdata specified by the (@name, @name2, @name3) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000482 *
483 * Returns the a pointer to the userdata
484 */
485void *
486xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
487 const xmlChar *name2, const xmlChar *name3) {
488 unsigned long key;
489 xmlHashEntryPtr entry;
490
491 if (table == NULL)
492 return(NULL);
493 if (name == NULL)
494 return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000495 key = xmlHashComputeKey(table, name, name2, name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000496 for (entry = table->table[key]; entry != NULL; entry = entry->next) {
497 if ((xmlStrEqual(entry->name, name)) &&
498 (xmlStrEqual(entry->name2, name2)) &&
499 (xmlStrEqual(entry->name3, name3)))
500 return(entry->payload);
501 }
502 return(NULL);
503}
504
505/**
506 * xmlHashScan:
507 * @table: the hash table
508 * @f: the scanner function for items in the hash
509 * @data: extra data passed to f
510 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000511 * Scan the hash @table and applied @f to each value.
Owen Taylor3473f882001-02-23 17:55:21 +0000512 */
513void
514xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
Thomas Broyere8126242001-07-22 03:54:15 +0000515 xmlHashScanFull (table, (xmlHashScannerFull) f, data);
516}
517
518/**
519 * xmlHashScanFull:
520 * @table: the hash table
521 * @f: the scanner function for items in the hash
522 * @data: extra data passed to f
523 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000524 * Scan the hash @table and applied @f to each value.
Thomas Broyere8126242001-07-22 03:54:15 +0000525 */
526void
527xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000528 int i;
529 xmlHashEntryPtr iter;
530 xmlHashEntryPtr next;
531
532 if (table == NULL)
533 return;
534 if (f == NULL)
535 return;
536
537 if (table->table) {
538 for(i = 0; i < table->size; i++) {
539 iter = table->table[i];
540 while (iter) {
541 next = iter->next;
542 if (f)
Thomas Broyere8126242001-07-22 03:54:15 +0000543 f(iter->payload, data, iter->name,
544 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000545 iter = next;
546 }
547 }
548 }
549}
550
551/**
552 * xmlHashScan3:
553 * @table: the hash table
554 * @name: the name of the userdata or NULL
555 * @name2: a second name of the userdata or NULL
556 * @name3: a third name of the userdata or NULL
557 * @f: the scanner function for items in the hash
558 * @data: extra data passed to f
559 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000560 * Scan the hash @table and applied @f to each value matching
561 * (@name, @name2, @name3) tuple. If one of the names is null,
Owen Taylor3473f882001-02-23 17:55:21 +0000562 * the comparison is considered to match.
563 */
564void
565xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
566 const xmlChar *name2, const xmlChar *name3,
567 xmlHashScanner f, void *data) {
Thomas Broyere8126242001-07-22 03:54:15 +0000568 xmlHashScanFull3 (table, name, name2, name3,
569 (xmlHashScannerFull) f, data);
570}
571
572/**
573 * xmlHashScanFull3:
574 * @table: the hash table
575 * @name: the name of the userdata or NULL
576 * @name2: a second name of the userdata or NULL
577 * @name3: a third name of the userdata or NULL
578 * @f: the scanner function for items in the hash
579 * @data: extra data passed to f
580 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000581 * Scan the hash @table and applied @f to each value matching
582 * (@name, @name2, @name3) tuple. If one of the names is null,
Thomas Broyere8126242001-07-22 03:54:15 +0000583 * the comparison is considered to match.
584 */
585void
586xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
587 const xmlChar *name2, const xmlChar *name3,
588 xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000589 int i;
590 xmlHashEntryPtr iter;
591 xmlHashEntryPtr next;
592
593 if (table == NULL)
594 return;
595 if (f == NULL)
596 return;
597
598 if (table->table) {
599 for(i = 0; i < table->size; i++) {
600 iter = table->table[i];
601 while (iter) {
602 next = iter->next;
603 if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
604 ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
605 ((name3 == NULL) || (xmlStrEqual(name3, iter->name3)))) {
Thomas Broyere8126242001-07-22 03:54:15 +0000606 f(iter->payload, data, iter->name,
607 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000608 }
609 iter = next;
610 }
611 }
612 }
613}
614
615/**
616 * xmlHashCopy:
617 * @table: the hash table
618 * @f: the copier function for items in the hash
619 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000620 * Scan the hash @table and applied @f to each value.
Owen Taylor3473f882001-02-23 17:55:21 +0000621 *
622 * Returns the new table or NULL in case of error.
623 */
624xmlHashTablePtr
625xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
626 int i;
627 xmlHashEntryPtr iter;
628 xmlHashEntryPtr next;
629 xmlHashTablePtr ret;
630
631 if (table == NULL)
632 return(NULL);
633 if (f == NULL)
634 return(NULL);
635
636 ret = xmlHashCreate(table->size);
637 if (table->table) {
638 for(i = 0; i < table->size; i++) {
639 iter = table->table[i];
640 while (iter) {
641 next = iter->next;
642 xmlHashAddEntry3(ret, iter->name, iter->name2,
643 iter->name3, f(iter->payload, iter->name));
644 iter = next;
645 }
646 }
647 }
648 ret->nbElems = table->nbElems;
649 return(ret);
650}
651
652/**
653 * xmlHashSize:
654 * @table: the hash table
655 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000656 * Query the number of elements installed in the hash @table.
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000657 *
Owen Taylor3473f882001-02-23 17:55:21 +0000658 * Returns the number of elements in the hash table or
659 * -1 in case of error
660 */
661int
662xmlHashSize(xmlHashTablePtr table) {
663 if (table == NULL)
664 return(-1);
665 return(table->nbElems);
666}
667
668/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000669 * xmlHashRemoveEntry:
Owen Taylor3473f882001-02-23 17:55:21 +0000670 * @table: the hash table
671 * @name: the name of the userdata
672 * @f: the deallocator function for removed item (if any)
673 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000674 * Find the userdata specified by the @name and remove
675 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000676 * and freed with @f.
677 *
678 * Returns 0 if the removal succeeded and -1 in case of error or not found.
679 */
680int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000681 xmlHashDeallocator f) {
682 return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +0000683}
684
685/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000686 * xmlHashRemoveEntry2:
Owen Taylor3473f882001-02-23 17:55:21 +0000687 * @table: the hash table
688 * @name: the name of the userdata
689 * @name2: a second name of the userdata
690 * @f: the deallocator function for removed item (if any)
691 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000692 * Find the userdata specified by the (@name, @name2) tuple and remove
693 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000694 * and freed with @f.
695 *
696 * Returns 0 if the removal succeeded and -1 in case of error or not found.
697 */
698int xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000699 const xmlChar *name2, xmlHashDeallocator f) {
700 return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +0000701}
702
703/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000704 * xmlHashRemoveEntry3
Owen Taylor3473f882001-02-23 17:55:21 +0000705 * @table: the hash table
706 * @name: the name of the userdata
707 * @name2: a second name of the userdata
708 * @name3: a third name of the userdata
709 * @f: the deallocator function for removed item (if any)
710 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000711 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
712 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000713 * and freed with @f.
714 *
715 * Returns 0 if the removal succeeded and -1 in case of error or not found.
716 */
717int xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000718 const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
719 unsigned long key;
720 xmlHashEntryPtr entry;
721 xmlHashEntryPtr prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000722
Daniel Veillarda10efa82001-04-18 13:09:01 +0000723 if (table == NULL || name == NULL)
724 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000725
Daniel Veillarda10efa82001-04-18 13:09:01 +0000726 key = xmlHashComputeKey(table, name, name2, name3);
727 if (table->table[key] == NULL) {
728 return(-1);
729 } else {
730 for (entry = table->table[key]; entry != NULL; entry = entry->next) {
731 if (xmlStrEqual(entry->name, name) &&
732 xmlStrEqual(entry->name2, name2) &&
733 xmlStrEqual(entry->name3, name3)) {
734 if(f)
735 f(entry->payload, entry->name);
736 entry->payload = NULL;
737 if(entry->name)
738 xmlFree(entry->name);
739 if(entry->name2)
740 xmlFree(entry->name2);
741 if(entry->name3)
742 xmlFree(entry->name3);
743 if(prev)
744 prev->next = entry->next;
745 else
746 table->table[key] = entry->next;
747 xmlFree(entry);
748 table->nbElems--;
749 return(0);
750 }
751 prev = entry;
752 }
753 return(-1);
754 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000755}
756