Annotation of XML/hash.c, revision 1.8
1.1 veillard 1: /*
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: *
17: * Author: bjorn.reese@systematic.dk
18: */
19:
1.8 ! veillard 20: #include <string.h>
1.1 veillard 21: #include <libxml/hash.h>
22: #include <libxml/xmlmemory.h>
23: #include <libxml/parser.h>
24:
25: /*
1.7 veillard 26: * A single entry in the hash table
27: */
28: typedef struct _xmlHashEntry xmlHashEntry;
29: typedef xmlHashEntry *xmlHashEntryPtr;
30: struct _xmlHashEntry {
31: struct _xmlHashEntry *next;
32: xmlChar *name;
33: xmlChar *name2;
34: xmlChar *name3;
35: void *payload;
36: };
37:
38: /*
39: * The entire hash table
40: */
41: struct _xmlHashTable {
42: struct _xmlHashEntry **table;
43: int size;
44: };
45:
46: /*
1.1 veillard 47: * xmlHashComputeKey:
48: * Calculate the hash key
49: */
50: static unsigned long
51: xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *string) {
52: unsigned long value = 0L;
53: char ch;
54:
55: while ((ch = *string++) != 0) {
56: /* value *= 31; */
57: value += (unsigned long)ch;
58: }
59: return (value % table->size);
60: }
61:
62: /**
63: * xmlHashCreate:
64: * @size: the size of the hash table
65: *
66: * Create a new xmlHashTablePtr.
67: *
68: * Returns the newly created object, or NULL if an error occured.
69: */
70: xmlHashTablePtr
71: xmlHashCreate(int size) {
72: xmlHashTablePtr table;
73:
74: if (size <= 0)
75: size = 256;
76:
77: table = xmlMalloc(sizeof(xmlHashTable));
78: if (table) {
79: table->size = size;
80: table->table = xmlMalloc(size * sizeof(xmlHashEntry));
81: if (table->table) {
82: memset(table->table, 0, size * sizeof(xmlHashEntry));
83: return(table);
84: }
85: xmlFree(table);
86: }
87: return(NULL);
88: }
89:
90: /**
91: * xmlHashFree:
92: * @table: the hash table
93: * @f: the deallocator function for items in the hash
94: *
95: * Free the hash table and its contents. The userdata is
96: * deallocated with f if provided.
97: */
98: void
99: xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
100: int i;
101: xmlHashEntryPtr iter;
102: xmlHashEntryPtr next;
103:
104: if (table == NULL)
105: return;
106: if (table->table) {
107: for(i = 0; i < table->size; i++) {
108: iter = table->table[i];
109: while (iter) {
110: next = iter->next;
111: if (iter->name)
112: xmlFree(iter->name);
1.5 veillard 113: if (iter->name2)
114: xmlFree(iter->name2);
115: if (iter->name3)
116: xmlFree(iter->name3);
1.1 veillard 117: if (f)
1.6 veillard 118: f(iter->payload, iter->name);
1.1 veillard 119: iter->payload = NULL;
120: xmlFree(iter);
121: iter = next;
122: }
123: table->table[i] = NULL;
124: }
125: xmlFree(table->table);
126: }
127: xmlFree(table);
128: }
129:
130: /**
131: * xmlHashAddEntry:
132: * @table: the hash table
133: * @name: the name of the userdata
134: * @userdata: a pointer to the userdata
135: *
136: * Add the userdata to the hash table. This can later be retrieved
137: * by using the name. Duplicate names generate errors.
138: *
139: * Returns 0 the addition succeeded and -1 in case of error.
140: */
141: int
142: xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
1.3 veillard 143: return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
144: }
145:
146: /**
147: * xmlHashAddEntry2:
148: * @table: the hash table
149: * @name: the name of the userdata
150: * @name2: a second name of the userdata
151: * @userdata: a pointer to the userdata
152: *
153: * Add the userdata to the hash table. This can later be retrieved
154: * by using the (name, name2) tuple. Duplicate tuples generate errors.
155: *
156: * Returns 0 the addition succeeded and -1 in case of error.
157: */
158: int
159: xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
160: const xmlChar *name2, void *userdata) {
161: return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
162: }
163:
164: /**
165: * xmlHashUpdateEntry:
166: * @table: the hash table
167: * @name: the name of the userdata
168: * @userdata: a pointer to the userdata
169: * @f: the deallocator function for replaced item (if any)
170: *
171: * Add the userdata to the hash table. This can later be retrieved
172: * by using the name. Existing entry for this name will be removed
173: * and freed with @f if found.
174: *
175: * Returns 0 the addition succeeded and -1 in case of error.
176: */
177: int
178: xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
179: void *userdata, xmlHashDeallocator f) {
180: return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
181: }
182:
183: /**
184: * xmlHashUpdateEntry2:
185: * @table: the hash table
186: * @name: the name of the userdata
187: * @name2: a second name of the userdata
188: * @userdata: a pointer to the userdata
189: * @f: the deallocator function for replaced item (if any)
190: *
191: * Add the userdata to the hash table. This can later be retrieved
192: * by using the (name, name2) tuple. Existing entry for this tuple will
193: * be removed and freed with @f if found.
194: *
195: * Returns 0 the addition succeeded and -1 in case of error.
196: */
197: int
198: xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
199: const xmlChar *name2, void *userdata,
200: xmlHashDeallocator f) {
201: return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
202: }
203:
204: /**
205: * xmlHashLookup:
206: * @table: the hash table
207: * @name: the name of the userdata
208: *
209: * Find the userdata specified by the name.
210: *
211: * Returns the a pointer to the userdata
212: */
213: void *
214: xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
215: return(xmlHashLookup3(table, name, NULL, NULL));
216: }
217:
218: /**
219: * xmlHashLookup2:
220: * @table: the hash table
221: * @name: the name of the userdata
222: * @name2: a second name of the userdata
223: *
224: * Find the userdata specified by the (name, name2) tuple.
225: *
226: * Returns the a pointer to the userdata
227: */
228: void *
229: xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
230: const xmlChar *name2) {
231: return(xmlHashLookup3(table, name, name2, NULL));
232: }
233:
234: /**
235: * xmlHashAddEntry3:
236: * @table: the hash table
237: * @name: the name of the userdata
238: * @name2: a second name of the userdata
239: * @name3: a third name of the userdata
240: * @userdata: a pointer to the userdata
241: *
242: * Add the userdata to the hash table. This can later be retrieved
243: * by using the tuple (name, name2, name3). Duplicate entries generate
244: * errors.
245: *
246: * Returns 0 the addition succeeded and -1 in case of error.
247: */
248: int
249: xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
1.4 veillard 250: const xmlChar *name2, const xmlChar *name3,
251: void *userdata) {
1.1 veillard 252: unsigned long key;
253: xmlHashEntryPtr entry;
254: xmlHashEntryPtr insert;
255:
256: if ((table == NULL) || name == NULL)
257: return(-1);
258:
259: /*
260: * Check for duplicate and insertion location.
261: */
262: key = xmlHashComputeKey(table, name);
263: if (table->table[key] == NULL) {
264: insert = NULL;
265: } else {
266: for (insert = table->table[key]; insert->next != NULL;
267: insert = insert->next) {
1.3 veillard 268: if ((xmlStrEqual(insert->name, name)) &&
269: (xmlStrEqual(insert->name2, name2)) &&
270: (xmlStrEqual(insert->name3, name3)))
1.1 veillard 271: return(-1);
272: }
1.3 veillard 273: if ((xmlStrEqual(insert->name, name)) &&
274: (xmlStrEqual(insert->name2, name2)) &&
275: (xmlStrEqual(insert->name3, name3)))
1.1 veillard 276: return(-1);
277: }
278:
279: entry = xmlMalloc(sizeof(xmlHashEntry));
280: if (entry == NULL)
281: return(-1);
282: entry->name = xmlStrdup(name);
1.3 veillard 283: entry->name2 = xmlStrdup(name2);
284: entry->name3 = xmlStrdup(name3);
1.1 veillard 285: entry->payload = userdata;
286: entry->next = NULL;
287:
288:
289: if (insert == NULL) {
290: table->table[key] = entry;
291: } else {
292: insert->next = entry;
293: }
294: return(0);
295: }
296:
297: /**
1.3 veillard 298: * xmlHashUpdateEntry3:
1.1 veillard 299: * @table: the hash table
300: * @name: the name of the userdata
1.3 veillard 301: * @name2: a second name of the userdata
302: * @name3: a third name of the userdata
1.1 veillard 303: * @userdata: a pointer to the userdata
304: * @f: the deallocator function for replaced item (if any)
305: *
306: * Add the userdata to the hash table. This can later be retrieved
1.3 veillard 307: * by using the tuple (name, name2, name3). Existing entry for this tuple
308: * will be removed and freed with @f if found.
1.1 veillard 309: *
310: * Returns 0 the addition succeeded and -1 in case of error.
311: */
312: int
1.4 veillard 313: xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
1.3 veillard 314: const xmlChar *name2, const xmlChar *name3,
315: void *userdata, xmlHashDeallocator f) {
1.1 veillard 316: unsigned long key;
317: xmlHashEntryPtr entry;
318: xmlHashEntryPtr insert;
319:
320: if ((table == NULL) || name == NULL)
321: return(-1);
322:
323: /*
324: * Check for duplicate and insertion location.
325: */
326: key = xmlHashComputeKey(table, name);
327: if (table->table[key] == NULL) {
328: insert = NULL;
329: } else {
330: for (insert = table->table[key]; insert->next != NULL;
331: insert = insert->next) {
1.3 veillard 332: if ((xmlStrEqual(insert->name, name)) &&
333: (xmlStrEqual(insert->name2, name2)) &&
334: (xmlStrEqual(insert->name3, name3))) {
1.1 veillard 335: if (f)
1.6 veillard 336: f(insert->payload, insert->name);
1.1 veillard 337: insert->payload = userdata;
338: return(0);
339: }
340: }
1.3 veillard 341: if ((xmlStrEqual(insert->name, name)) &&
342: (xmlStrEqual(insert->name2, name2)) &&
343: (xmlStrEqual(insert->name3, name3))) {
1.1 veillard 344: if (f)
1.6 veillard 345: f(insert->payload, insert->name);
1.1 veillard 346: insert->payload = userdata;
347: return(0);
348: }
349: }
350:
351: entry = xmlMalloc(sizeof(xmlHashEntry));
352: if (entry == NULL)
353: return(-1);
354: entry->name = xmlStrdup(name);
1.3 veillard 355: entry->name2 = xmlStrdup(name2);
356: entry->name3 = xmlStrdup(name3);
1.1 veillard 357: entry->payload = userdata;
358: entry->next = NULL;
359:
360:
361: if (insert == NULL) {
362: table->table[key] = entry;
363: } else {
364: insert->next = entry;
365: }
366: return(0);
367: }
368:
369: /**
370: * xmlHashLookup:
371: * @table: the hash table
372: * @name: the name of the userdata
1.3 veillard 373: * @name2: a second name of the userdata
374: * @name3: a third name of the userdata
1.1 veillard 375: *
1.5 veillard 376: * Find the userdata specified by the (name, name2, name3) tuple.
1.1 veillard 377: *
378: * Returns the a pointer to the userdata
379: */
380: void *
1.3 veillard 381: xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
382: const xmlChar *name2, const xmlChar *name3) {
1.1 veillard 383: unsigned long key;
384: xmlHashEntryPtr entry;
385:
386: if (table == NULL)
387: return(NULL);
388: if (name == NULL)
389: return(NULL);
390: key = xmlHashComputeKey(table, name);
391: for (entry = table->table[key]; entry != NULL; entry = entry->next) {
1.4 veillard 392: if ((xmlStrEqual(entry->name, name)) &&
393: (xmlStrEqual(entry->name2, name2)) &&
394: (xmlStrEqual(entry->name3, name3)))
1.1 veillard 395: return(entry->payload);
396: }
397: return(NULL);
398: }
1.2 veillard 399:
400: /**
401: * xmlHashScan:
402: * @table: the hash table
403: * @f: the scanner function for items in the hash
404: * @data: extra data passed to f
405: *
406: * Scan the hash table and applied f to each value.
407: */
408: void
409: xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
410: int i;
411: xmlHashEntryPtr iter;
412: xmlHashEntryPtr next;
413:
414: if (table == NULL)
415: return;
416: if (f == NULL)
417: return;
418:
419: if (table->table) {
420: for(i = 0; i < table->size; i++) {
421: iter = table->table[i];
422: while (iter) {
423: next = iter->next;
424: if (f)
1.6 veillard 425: f(iter->payload, data, iter->name);
1.5 veillard 426: iter = next;
427: }
428: }
429: }
430: }
431:
432: /**
433: * xmlHashScan3:
434: * @table: the hash table
435: * @name: the name of the userdata or NULL
436: * @name2: a second name of the userdata or NULL
437: * @name3: a third name of the userdata or NULL
438: * @f: the scanner function for items in the hash
439: * @data: extra data passed to f
440: *
441: * Scan the hash table and applied f to each value matching
442: * (name, name2, name3) tuple. If one of the names is null,
443: * the comparison is considered to match.
444: */
445: void
446: xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
447: const xmlChar *name2, const xmlChar *name3,
448: xmlHashScanner f, void *data) {
449: int i;
450: xmlHashEntryPtr iter;
451: xmlHashEntryPtr next;
452:
453: if (table == NULL)
454: return;
455: if (f == NULL)
456: return;
457:
458: if (table->table) {
459: for(i = 0; i < table->size; i++) {
460: iter = table->table[i];
461: while (iter) {
462: next = iter->next;
463: if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
464: ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
465: ((name3 == NULL) || (xmlStrEqual(name3, iter->name3)))) {
1.6 veillard 466: f(iter->payload, data, iter->name);
1.5 veillard 467: }
1.2 veillard 468: iter = next;
469: }
470: }
471: }
472: }
473:
474: /**
475: * xmlHashCopy:
476: * @table: the hash table
477: * @f: the copier function for items in the hash
478: *
479: * Scan the hash table and applied f to each value.
480: *
481: * Returns the new table or NULL in case of error.
482: */
483: xmlHashTablePtr
484: xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
485: int i;
486: xmlHashEntryPtr iter;
487: xmlHashEntryPtr next;
488: xmlHashTablePtr ret;
489:
490: if (table == NULL)
491: return(NULL);
492: if (f == NULL)
493: return(NULL);
494:
495: ret = xmlHashCreate(table->size);
496: if (table->table) {
497: for(i = 0; i < table->size; i++) {
498: iter = table->table[i];
499: while (iter) {
500: next = iter->next;
1.3 veillard 501: xmlHashAddEntry3(ret, iter->name, iter->name2,
1.6 veillard 502: iter->name3, f(iter->payload, iter->name));
1.2 veillard 503: iter = next;
504: }
505: }
506: }
507: return(ret);
508: }
509:
Webmaster