blob: b4b865615530f81059690bbc8b232c7a2f835af1 [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;
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;
55};
56
57/*
58 * xmlHashComputeKey:
59 * Calculate the hash key
60 */
61static unsigned long
Daniel Veillarda10efa82001-04-18 13:09:01 +000062xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
63 const xmlChar *name2, const xmlChar *name3) {
Owen Taylor3473f882001-02-23 17:55:21 +000064 unsigned long value = 0L;
65 char ch;
66
Daniel Veillarda10efa82001-04-18 13:09:01 +000067 if (name != NULL) {
68 value += 30 * (*name);
69 while ((ch = *name++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +000070 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +000071 }
72 }
73 if (name2 != NULL) {
74 while ((ch = *name2++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +000075 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +000076 }
77 }
78 if (name3 != NULL) {
79 while ((ch = *name3++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +000080 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +000081 }
Owen Taylor3473f882001-02-23 17:55:21 +000082 }
83 return (value % table->size);
84}
85
86/**
87 * xmlHashCreate:
88 * @size: the size of the hash table
89 *
90 * Create a new xmlHashTablePtr.
91 *
92 * Returns the newly created object, or NULL if an error occured.
93 */
94xmlHashTablePtr
95xmlHashCreate(int size) {
96 xmlHashTablePtr table;
97
98 if (size <= 0)
99 size = 256;
100
101 table = xmlMalloc(sizeof(xmlHashTable));
102 if (table) {
103 table->size = size;
104 table->nbElems = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000105 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
Owen Taylor3473f882001-02-23 17:55:21 +0000106 if (table->table) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000107 memset(table->table, 0, size * sizeof(xmlHashEntry));
Owen Taylor3473f882001-02-23 17:55:21 +0000108 return(table);
109 }
110 xmlFree(table);
111 }
112 return(NULL);
113}
114
115/**
Daniel Veillarda10efa82001-04-18 13:09:01 +0000116 * xmlHashGrow:
117 * @table: the hash table
118 * @size: the new size of the hash table
119 *
120 * resize the hash table
121 *
122 * Returns 0 in case of success, -1 in case of failure
123 */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000124static int
Daniel Veillarda10efa82001-04-18 13:09:01 +0000125xmlHashGrow(xmlHashTablePtr table, int size) {
126 unsigned long key;
127 int oldsize, i;
128 xmlHashEntryPtr iter, next;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000129 struct _xmlHashEntry *oldtable;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000130#ifdef DEBUG_GROW
131 unsigned long nbElem = 0;
132#endif
133
134 if (table == NULL)
135 return(-1);
136 if (size < 8)
137 return(-1);
138 if (size > 8 * 2048)
139 return(-1);
140
141 oldsize = table->size;
142 oldtable = table->table;
143 if (oldtable == NULL)
144 return(-1);
145
Daniel Veillardfdc91562002-07-01 21:52:03 +0000146 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000147 if (table->table == NULL) {
148 table->table = oldtable;
149 return(-1);
150 }
Daniel Veillardfdc91562002-07-01 21:52:03 +0000151 memset(table->table, 0, size * sizeof(xmlHashEntry));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000152 table->size = size;
153
Daniel Veillardfdc91562002-07-01 21:52:03 +0000154 /* If the two loops are merged, there would be situations where
155 a new entry needs to allocated and data copied into it from
156 the main table. So instead, we run through the array twice, first
157 copying all the elements in the main array (where we can't get
158 conflicts) and then the rest, so we only free (and don't allocate)
159 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000160 for (i = 0; i < oldsize; i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000161 if (oldtable[i].valid == 0)
162 continue;
163 key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
164 oldtable[i].name3);
165 memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
166 table->table[key].next = NULL;
167 }
168
169 for (i = 0; i < oldsize; i++) {
170 iter = oldtable[i].next;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000171 while (iter) {
172 next = iter->next;
173
174 /*
175 * put back the entry in the new table
176 */
177
178 key = xmlHashComputeKey(table, iter->name, iter->name2,
179 iter->name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000180 if (table->table[key].valid == 0) {
181 memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
182 table->table[key].next = NULL;
183 xmlFree(iter);
184 } else {
185 iter->next = table->table[key].next;
186 table->table[key].next = iter;
187 }
Daniel Veillarda10efa82001-04-18 13:09:01 +0000188
189#ifdef DEBUG_GROW
190 nbElem++;
191#endif
192
193 iter = next;
194 }
195 }
196
197 xmlFree(oldtable);
198
199#ifdef DEBUG_GROW
200 xmlGenericError(xmlGenericErrorContext,
201 "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
202#endif
203
204 return(0);
205}
206
207/**
Owen Taylor3473f882001-02-23 17:55:21 +0000208 * xmlHashFree:
209 * @table: the hash table
210 * @f: the deallocator function for items in the hash
211 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000212 * Free the hash @table and its contents. The userdata is
213 * deallocated with @f if provided.
Owen Taylor3473f882001-02-23 17:55:21 +0000214 */
215void
216xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
217 int i;
218 xmlHashEntryPtr iter;
219 xmlHashEntryPtr next;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000220 int inside_table = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000221 int nbElems;
Owen Taylor3473f882001-02-23 17:55:21 +0000222
223 if (table == NULL)
224 return;
225 if (table->table) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000226 nbElems = table->nbElems;
227 for(i = 0; (i < table->size) && (nbElems > 0); i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000228 iter = &(table->table[i]);
229 if (iter->valid == 0)
230 continue;
231 inside_table = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000232 while (iter) {
233 next = iter->next;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000234 if (f)
235 f(iter->payload, iter->name);
Owen Taylor3473f882001-02-23 17:55:21 +0000236 if (iter->name)
237 xmlFree(iter->name);
238 if (iter->name2)
239 xmlFree(iter->name2);
240 if (iter->name3)
241 xmlFree(iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000242 iter->payload = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000243 if (!inside_table)
244 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000245 nbElems--;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000246 inside_table = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000247 iter = next;
248 }
Daniel Veillardfdc91562002-07-01 21:52:03 +0000249 inside_table = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000250 }
251 xmlFree(table->table);
252 }
253 xmlFree(table);
254}
255
256/**
257 * xmlHashAddEntry:
258 * @table: the hash table
259 * @name: the name of the userdata
260 * @userdata: a pointer to the userdata
261 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000262 * Add the @userdata to the hash @table. This can later be retrieved
263 * by using the @name. Duplicate names generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000264 *
265 * Returns 0 the addition succeeded and -1 in case of error.
266 */
267int
268xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
269 return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
270}
271
272/**
273 * xmlHashAddEntry2:
274 * @table: the hash table
275 * @name: the name of the userdata
276 * @name2: a second name of the userdata
277 * @userdata: a pointer to the userdata
278 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000279 * Add the @userdata to the hash @table. This can later be retrieved
280 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000281 *
282 * Returns 0 the addition succeeded and -1 in case of error.
283 */
284int
285xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
286 const xmlChar *name2, void *userdata) {
287 return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
288}
289
290/**
291 * xmlHashUpdateEntry:
292 * @table: the hash table
293 * @name: the name of the userdata
294 * @userdata: a pointer to the userdata
295 * @f: the deallocator function for replaced item (if any)
296 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000297 * Add the @userdata to the hash @table. This can later be retrieved
298 * by using the @name. Existing entry for this @name will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000299 * and freed with @f if found.
300 *
301 * Returns 0 the addition succeeded and -1 in case of error.
302 */
303int
304xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
305 void *userdata, xmlHashDeallocator f) {
306 return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
307}
308
309/**
310 * xmlHashUpdateEntry2:
311 * @table: the hash table
312 * @name: the name of the userdata
313 * @name2: a second name of the userdata
314 * @userdata: a pointer to the userdata
315 * @f: the deallocator function for replaced item (if any)
316 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000317 * Add the @userdata to the hash @table. This can later be retrieved
318 * by using the (@name, @name2) tuple. Existing entry for this tuple will
Owen Taylor3473f882001-02-23 17:55:21 +0000319 * be removed and freed with @f if found.
320 *
321 * Returns 0 the addition succeeded and -1 in case of error.
322 */
323int
324xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
325 const xmlChar *name2, void *userdata,
326 xmlHashDeallocator f) {
327 return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
328}
329
330/**
331 * xmlHashLookup:
332 * @table: the hash table
333 * @name: the name of the userdata
334 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000335 * Find the userdata specified by the @name.
Owen Taylor3473f882001-02-23 17:55:21 +0000336 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000337 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000338 */
339void *
340xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
341 return(xmlHashLookup3(table, name, NULL, NULL));
342}
343
344/**
345 * xmlHashLookup2:
346 * @table: the hash table
347 * @name: the name of the userdata
348 * @name2: a second name of the userdata
349 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000350 * Find the userdata specified by the (@name, @name2) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000351 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000352 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000353 */
354void *
355xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
356 const xmlChar *name2) {
357 return(xmlHashLookup3(table, name, name2, NULL));
358}
359
360/**
361 * xmlHashAddEntry3:
362 * @table: the hash table
363 * @name: the name of the userdata
364 * @name2: a second name of the userdata
365 * @name3: a third name of the userdata
366 * @userdata: a pointer to the userdata
367 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000368 * Add the @userdata to the hash @table. This can later be retrieved
369 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
Owen Taylor3473f882001-02-23 17:55:21 +0000370 * errors.
371 *
372 * Returns 0 the addition succeeded and -1 in case of error.
373 */
374int
375xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
376 const xmlChar *name2, const xmlChar *name3,
377 void *userdata) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000378 unsigned long key, len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000379 xmlHashEntryPtr entry;
380 xmlHashEntryPtr insert;
381
382 if ((table == NULL) || name == NULL)
383 return(-1);
384
385 /*
386 * Check for duplicate and insertion location.
387 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000388 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000389 if (table->table[key].valid == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000390 insert = NULL;
391 } else {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000392 for (insert = &(table->table[key]); insert->next != NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000393 insert = insert->next) {
394 if ((xmlStrEqual(insert->name, name)) &&
395 (xmlStrEqual(insert->name2, name2)) &&
396 (xmlStrEqual(insert->name3, name3)))
397 return(-1);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000398 len++;
Owen Taylor3473f882001-02-23 17:55:21 +0000399 }
400 if ((xmlStrEqual(insert->name, name)) &&
401 (xmlStrEqual(insert->name2, name2)) &&
402 (xmlStrEqual(insert->name3, name3)))
403 return(-1);
404 }
405
Daniel Veillardfdc91562002-07-01 21:52:03 +0000406 if (insert == NULL) {
407 entry = &(table->table[key]);
408 } else {
409 entry = xmlMalloc(sizeof(xmlHashEntry));
410 if (entry == NULL)
411 return(-1);
412 }
413
Owen Taylor3473f882001-02-23 17:55:21 +0000414 entry->name = xmlStrdup(name);
415 entry->name2 = xmlStrdup(name2);
416 entry->name3 = xmlStrdup(name3);
417 entry->payload = userdata;
418 entry->next = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000419 entry->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000420
421
Daniel Veillardfdc91562002-07-01 21:52:03 +0000422 if (insert != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +0000423 insert->next = entry;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000424
Owen Taylor3473f882001-02-23 17:55:21 +0000425 table->nbElems++;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000426
427 if (len > MAX_HASH_LEN)
428 xmlHashGrow(table, MAX_HASH_LEN * table->size);
429
Owen Taylor3473f882001-02-23 17:55:21 +0000430 return(0);
431}
432
433/**
434 * xmlHashUpdateEntry3:
435 * @table: the hash table
436 * @name: the name of the userdata
437 * @name2: a second name of the userdata
438 * @name3: a third name of the userdata
439 * @userdata: a pointer to the userdata
440 * @f: the deallocator function for replaced item (if any)
441 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000442 * Add the @userdata to the hash @table. This can later be retrieved
443 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
Owen Taylor3473f882001-02-23 17:55:21 +0000444 * will be removed and freed with @f if found.
445 *
446 * Returns 0 the addition succeeded and -1 in case of error.
447 */
448int
449xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
450 const xmlChar *name2, const xmlChar *name3,
451 void *userdata, xmlHashDeallocator f) {
452 unsigned long key;
453 xmlHashEntryPtr entry;
454 xmlHashEntryPtr insert;
455
456 if ((table == NULL) || name == NULL)
457 return(-1);
458
459 /*
460 * Check for duplicate and insertion location.
461 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000462 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000463 if (table->table[key].valid == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000464 insert = NULL;
465 } else {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000466 for (insert = &(table->table[key]); insert->next != NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000467 insert = insert->next) {
468 if ((xmlStrEqual(insert->name, name)) &&
469 (xmlStrEqual(insert->name2, name2)) &&
470 (xmlStrEqual(insert->name3, name3))) {
471 if (f)
472 f(insert->payload, insert->name);
473 insert->payload = userdata;
474 return(0);
475 }
476 }
477 if ((xmlStrEqual(insert->name, name)) &&
478 (xmlStrEqual(insert->name2, name2)) &&
479 (xmlStrEqual(insert->name3, name3))) {
480 if (f)
481 f(insert->payload, insert->name);
482 insert->payload = userdata;
483 return(0);
484 }
485 }
486
Daniel Veillardfdc91562002-07-01 21:52:03 +0000487 if (insert == NULL) {
488 entry = &(table->table[key]);
489 } else {
490 entry = xmlMalloc(sizeof(xmlHashEntry));
491 if (entry == NULL)
492 return(-1);
493 }
494
Owen Taylor3473f882001-02-23 17:55:21 +0000495 entry->name = xmlStrdup(name);
496 entry->name2 = xmlStrdup(name2);
497 entry->name3 = xmlStrdup(name3);
498 entry->payload = userdata;
499 entry->next = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000500 entry->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000501 table->nbElems++;
502
503
Daniel Veillardfdc91562002-07-01 21:52:03 +0000504 if (insert != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000505 insert->next = entry;
506 }
507 return(0);
508}
509
510/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000511 * xmlHashLookup3:
Owen Taylor3473f882001-02-23 17:55:21 +0000512 * @table: the hash table
513 * @name: the name of the userdata
514 * @name2: a second name of the userdata
515 * @name3: a third name of the userdata
516 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000517 * Find the userdata specified by the (@name, @name2, @name3) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000518 *
519 * Returns the a pointer to the userdata
520 */
521void *
522xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
523 const xmlChar *name2, const xmlChar *name3) {
524 unsigned long key;
525 xmlHashEntryPtr entry;
526
527 if (table == NULL)
528 return(NULL);
529 if (name == NULL)
530 return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000531 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000532 if (table->table[key].valid == 0)
533 return(NULL);
534 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Owen Taylor3473f882001-02-23 17:55:21 +0000535 if ((xmlStrEqual(entry->name, name)) &&
536 (xmlStrEqual(entry->name2, name2)) &&
537 (xmlStrEqual(entry->name3, name3)))
538 return(entry->payload);
539 }
540 return(NULL);
541}
542
Daniel Veillard153120c2002-06-18 07:58:35 +0000543typedef struct {
544 xmlHashScanner hashscanner;
545 void *data;
546} stubData;
547
548static void
549stubHashScannerFull (void *payload, void *data, const xmlChar *name,
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000550 const xmlChar *name2 ATTRIBUTE_UNUSED,
551 const xmlChar *name3 ATTRIBUTE_UNUSED) {
Daniel Veillard153120c2002-06-18 07:58:35 +0000552 stubData *stubdata = (stubData *) data;
553 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
554}
555
Daniel Veillard01c13b52002-12-10 15:19:08 +0000556/**
557 * xmlHashScan:
558 * @table: the hash table
559 * @f: the scanner function for items in the hash
560 * @data: extra data passed to f
561 *
562 * Scan the hash @table and applied @f to each value.
563 */
Owen Taylor3473f882001-02-23 17:55:21 +0000564void
565xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
Daniel Veillard153120c2002-06-18 07:58:35 +0000566 stubData stubdata;
567 stubdata.data = data;
568 stubdata.hashscanner = f;
569 xmlHashScanFull (table, stubHashScannerFull, &stubdata);
Thomas Broyere8126242001-07-22 03:54:15 +0000570}
571
572/**
573 * xmlHashScanFull:
574 * @table: the hash table
575 * @f: the scanner function for items in the hash
576 * @data: extra data passed to f
577 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000578 * Scan the hash @table and applied @f to each value.
Thomas Broyere8126242001-07-22 03:54:15 +0000579 */
580void
581xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000582 int i;
583 xmlHashEntryPtr iter;
584 xmlHashEntryPtr next;
585
586 if (table == NULL)
587 return;
588 if (f == NULL)
589 return;
590
591 if (table->table) {
592 for(i = 0; i < table->size; i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000593 if (table->table[i].valid == 0)
594 continue;
595 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000596 while (iter) {
597 next = iter->next;
598 if (f)
Thomas Broyere8126242001-07-22 03:54:15 +0000599 f(iter->payload, data, iter->name,
600 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000601 iter = next;
602 }
603 }
604 }
605}
606
607/**
608 * xmlHashScan3:
609 * @table: the hash table
610 * @name: the name of the userdata or NULL
611 * @name2: a second name of the userdata or NULL
612 * @name3: a third name of the userdata or NULL
613 * @f: the scanner function for items in the hash
614 * @data: extra data passed to f
615 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000616 * Scan the hash @table and applied @f to each value matching
617 * (@name, @name2, @name3) tuple. If one of the names is null,
Owen Taylor3473f882001-02-23 17:55:21 +0000618 * the comparison is considered to match.
619 */
620void
621xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
622 const xmlChar *name2, const xmlChar *name3,
623 xmlHashScanner f, void *data) {
Thomas Broyere8126242001-07-22 03:54:15 +0000624 xmlHashScanFull3 (table, name, name2, name3,
625 (xmlHashScannerFull) f, data);
626}
627
628/**
629 * xmlHashScanFull3:
630 * @table: the hash table
631 * @name: the name of the userdata or NULL
632 * @name2: a second name of the userdata or NULL
633 * @name3: a third name of the userdata or NULL
634 * @f: the scanner function for items in the hash
635 * @data: extra data passed to f
636 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000637 * Scan the hash @table and applied @f to each value matching
638 * (@name, @name2, @name3) tuple. If one of the names is null,
Thomas Broyere8126242001-07-22 03:54:15 +0000639 * the comparison is considered to match.
640 */
641void
642xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
643 const xmlChar *name2, const xmlChar *name3,
644 xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000645 int i;
646 xmlHashEntryPtr iter;
647 xmlHashEntryPtr next;
648
649 if (table == NULL)
650 return;
651 if (f == NULL)
652 return;
653
654 if (table->table) {
655 for(i = 0; i < table->size; i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000656 if (table->table[i].valid == 0)
657 continue;
658 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000659 while (iter) {
660 next = iter->next;
661 if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
662 ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
663 ((name3 == NULL) || (xmlStrEqual(name3, iter->name3)))) {
Thomas Broyere8126242001-07-22 03:54:15 +0000664 f(iter->payload, data, iter->name,
665 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000666 }
667 iter = next;
668 }
669 }
670 }
671}
672
673/**
674 * xmlHashCopy:
675 * @table: the hash table
676 * @f: the copier function for items in the hash
677 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000678 * Scan the hash @table and applied @f to each value.
Owen Taylor3473f882001-02-23 17:55:21 +0000679 *
680 * Returns the new table or NULL in case of error.
681 */
682xmlHashTablePtr
683xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
684 int i;
685 xmlHashEntryPtr iter;
686 xmlHashEntryPtr next;
687 xmlHashTablePtr ret;
688
689 if (table == NULL)
690 return(NULL);
691 if (f == NULL)
692 return(NULL);
693
694 ret = xmlHashCreate(table->size);
695 if (table->table) {
696 for(i = 0; i < table->size; i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000697 if (table->table[i].valid == 0)
698 continue;
699 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000700 while (iter) {
701 next = iter->next;
702 xmlHashAddEntry3(ret, iter->name, iter->name2,
703 iter->name3, f(iter->payload, iter->name));
704 iter = next;
705 }
706 }
707 }
708 ret->nbElems = table->nbElems;
709 return(ret);
710}
711
712/**
713 * xmlHashSize:
714 * @table: the hash table
715 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000716 * Query the number of elements installed in the hash @table.
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000717 *
Owen Taylor3473f882001-02-23 17:55:21 +0000718 * Returns the number of elements in the hash table or
719 * -1 in case of error
720 */
721int
722xmlHashSize(xmlHashTablePtr table) {
723 if (table == NULL)
724 return(-1);
725 return(table->nbElems);
726}
727
728/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000729 * xmlHashRemoveEntry:
Owen Taylor3473f882001-02-23 17:55:21 +0000730 * @table: the hash table
731 * @name: the name of the userdata
732 * @f: the deallocator function for removed item (if any)
733 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000734 * Find the userdata specified by the @name and remove
735 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000736 * and freed with @f.
737 *
738 * Returns 0 if the removal succeeded and -1 in case of error or not found.
739 */
740int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000741 xmlHashDeallocator f) {
742 return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +0000743}
744
745/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000746 * xmlHashRemoveEntry2:
Owen Taylor3473f882001-02-23 17:55:21 +0000747 * @table: the hash table
748 * @name: the name of the userdata
749 * @name2: a second name of the userdata
750 * @f: the deallocator function for removed item (if any)
751 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000752 * Find the userdata specified by the (@name, @name2) tuple and remove
753 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000754 * and freed with @f.
755 *
756 * Returns 0 if the removal succeeded and -1 in case of error or not found.
757 */
Daniel Veillard01c13b52002-12-10 15:19:08 +0000758int
759xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000760 const xmlChar *name2, xmlHashDeallocator f) {
761 return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +0000762}
763
764/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000765 * xmlHashRemoveEntry3:
Owen Taylor3473f882001-02-23 17:55:21 +0000766 * @table: the hash table
767 * @name: the name of the userdata
768 * @name2: a second name of the userdata
769 * @name3: a third name of the userdata
770 * @f: the deallocator function for removed item (if any)
771 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000772 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
773 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000774 * and freed with @f.
775 *
776 * Returns 0 if the removal succeeded and -1 in case of error or not found.
777 */
Daniel Veillard01c13b52002-12-10 15:19:08 +0000778int
779xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000780 const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
781 unsigned long key;
782 xmlHashEntryPtr entry;
783 xmlHashEntryPtr prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000784
Daniel Veillarda10efa82001-04-18 13:09:01 +0000785 if (table == NULL || name == NULL)
786 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000787
Daniel Veillarda10efa82001-04-18 13:09:01 +0000788 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000789 if (table->table[key].valid == 0) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000790 return(-1);
791 } else {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000792 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000793 if (xmlStrEqual(entry->name, name) &&
794 xmlStrEqual(entry->name2, name2) &&
795 xmlStrEqual(entry->name3, name3)) {
796 if(f)
797 f(entry->payload, entry->name);
798 entry->payload = NULL;
799 if(entry->name)
800 xmlFree(entry->name);
801 if(entry->name2)
802 xmlFree(entry->name2);
803 if(entry->name3)
804 xmlFree(entry->name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000805 if(prev) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000806 prev->next = entry->next;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000807 xmlFree(entry);
808 } else {
809 if (entry->next == NULL) {
810 entry->valid = 0;
811 } else {
812 entry = entry->next;
813 memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
814 xmlFree(entry);
815 }
816 }
Daniel Veillarda10efa82001-04-18 13:09:01 +0000817 table->nbElems--;
818 return(0);
819 }
820 prev = entry;
821 }
822 return(-1);
823 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000824}
825