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