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