Annotation of XML/hash.c, revision 1.4
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);
91: if (f)
92: f(iter->payload);
93: iter->payload = NULL;
94: xmlFree(iter);
95: iter = next;
96: }
97: table->table[i] = NULL;
98: }
99: xmlFree(table->table);
100: }
101: xmlFree(table);
102: }
103:
104: /**
105: * xmlHashAddEntry:
106: * @table: the hash table
107: * @name: the name of the userdata
108: * @userdata: a pointer to the userdata
109: *
110: * Add the userdata to the hash table. This can later be retrieved
111: * by using the name. Duplicate names generate errors.
112: *
113: * Returns 0 the addition succeeded and -1 in case of error.
114: */
115: int
116: xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
1.3 veillard 117: return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
118: }
119:
120: /**
121: * xmlHashAddEntry2:
122: * @table: the hash table
123: * @name: the name of the userdata
124: * @name2: a second name of the userdata
125: * @userdata: a pointer to the userdata
126: *
127: * Add the userdata to the hash table. This can later be retrieved
128: * by using the (name, name2) tuple. Duplicate tuples generate errors.
129: *
130: * Returns 0 the addition succeeded and -1 in case of error.
131: */
132: int
133: xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
134: const xmlChar *name2, void *userdata) {
135: return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
136: }
137:
138: /**
139: * xmlHashUpdateEntry:
140: * @table: the hash table
141: * @name: the name of the userdata
142: * @userdata: a pointer to the userdata
143: * @f: the deallocator function for replaced item (if any)
144: *
145: * Add the userdata to the hash table. This can later be retrieved
146: * by using the name. Existing entry for this name will be removed
147: * and freed with @f if found.
148: *
149: * Returns 0 the addition succeeded and -1 in case of error.
150: */
151: int
152: xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
153: void *userdata, xmlHashDeallocator f) {
154: return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
155: }
156:
157: /**
158: * xmlHashUpdateEntry2:
159: * @table: the hash table
160: * @name: the name of the userdata
161: * @name2: a second name of the userdata
162: * @userdata: a pointer to the userdata
163: * @f: the deallocator function for replaced item (if any)
164: *
165: * Add the userdata to the hash table. This can later be retrieved
166: * by using the (name, name2) tuple. Existing entry for this tuple will
167: * be removed and freed with @f if found.
168: *
169: * Returns 0 the addition succeeded and -1 in case of error.
170: */
171: int
172: xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
173: const xmlChar *name2, void *userdata,
174: xmlHashDeallocator f) {
175: return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
176: }
177:
178: /**
179: * xmlHashLookup:
180: * @table: the hash table
181: * @name: the name of the userdata
182: *
183: * Find the userdata specified by the name.
184: *
185: * Returns the a pointer to the userdata
186: */
187: void *
188: xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
189: return(xmlHashLookup3(table, name, NULL, NULL));
190: }
191:
192: /**
193: * xmlHashLookup2:
194: * @table: the hash table
195: * @name: the name of the userdata
196: * @name2: a second name of the userdata
197: *
198: * Find the userdata specified by the (name, name2) tuple.
199: *
200: * Returns the a pointer to the userdata
201: */
202: void *
203: xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
204: const xmlChar *name2) {
205: return(xmlHashLookup3(table, name, name2, NULL));
206: }
207:
208: /**
209: * xmlHashAddEntry3:
210: * @table: the hash table
211: * @name: the name of the userdata
212: * @name2: a second name of the userdata
213: * @name3: a third name of the userdata
214: * @userdata: a pointer to the userdata
215: *
216: * Add the userdata to the hash table. This can later be retrieved
217: * by using the tuple (name, name2, name3). Duplicate entries generate
218: * errors.
219: *
220: * Returns 0 the addition succeeded and -1 in case of error.
221: */
222: int
223: xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
1.4 ! veillard 224: const xmlChar *name2, const xmlChar *name3,
! 225: void *userdata) {
1.1 veillard 226: unsigned long key;
227: xmlHashEntryPtr entry;
228: xmlHashEntryPtr insert;
229:
230: if ((table == NULL) || name == NULL)
231: return(-1);
232:
233: /*
234: * Check for duplicate and insertion location.
235: */
236: key = xmlHashComputeKey(table, name);
237: if (table->table[key] == NULL) {
238: insert = NULL;
239: } else {
240: for (insert = table->table[key]; insert->next != NULL;
241: insert = insert->next) {
1.3 veillard 242: if ((xmlStrEqual(insert->name, name)) &&
243: (xmlStrEqual(insert->name2, name2)) &&
244: (xmlStrEqual(insert->name3, name3)))
1.1 veillard 245: return(-1);
246: }
1.3 veillard 247: if ((xmlStrEqual(insert->name, name)) &&
248: (xmlStrEqual(insert->name2, name2)) &&
249: (xmlStrEqual(insert->name3, name3)))
1.1 veillard 250: return(-1);
251: }
252:
253: entry = xmlMalloc(sizeof(xmlHashEntry));
254: if (entry == NULL)
255: return(-1);
256: entry->name = xmlStrdup(name);
1.3 veillard 257: entry->name2 = xmlStrdup(name2);
258: entry->name3 = xmlStrdup(name3);
1.1 veillard 259: entry->payload = userdata;
260: entry->next = NULL;
261:
262:
263: if (insert == NULL) {
264: table->table[key] = entry;
265: } else {
266: insert->next = entry;
267: }
268: return(0);
269: }
270:
271: /**
1.3 veillard 272: * xmlHashUpdateEntry3:
1.1 veillard 273: * @table: the hash table
274: * @name: the name of the userdata
1.3 veillard 275: * @name2: a second name of the userdata
276: * @name3: a third name of the userdata
1.1 veillard 277: * @userdata: a pointer to the userdata
278: * @f: the deallocator function for replaced item (if any)
279: *
280: * Add the userdata to the hash table. This can later be retrieved
1.3 veillard 281: * by using the tuple (name, name2, name3). Existing entry for this tuple
282: * will be removed and freed with @f if found.
1.1 veillard 283: *
284: * Returns 0 the addition succeeded and -1 in case of error.
285: */
286: int
1.4 ! veillard 287: xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
1.3 veillard 288: const xmlChar *name2, const xmlChar *name3,
289: void *userdata, xmlHashDeallocator f) {
1.1 veillard 290: unsigned long key;
291: xmlHashEntryPtr entry;
292: xmlHashEntryPtr insert;
293:
294: if ((table == NULL) || name == NULL)
295: return(-1);
296:
297: /*
298: * Check for duplicate and insertion location.
299: */
300: key = xmlHashComputeKey(table, name);
301: if (table->table[key] == NULL) {
302: insert = NULL;
303: } else {
304: for (insert = table->table[key]; insert->next != NULL;
305: insert = insert->next) {
1.3 veillard 306: if ((xmlStrEqual(insert->name, name)) &&
307: (xmlStrEqual(insert->name2, name2)) &&
308: (xmlStrEqual(insert->name3, name3))) {
1.1 veillard 309: if (f)
310: f(insert->payload);
311: insert->payload = userdata;
312: return(0);
313: }
314: }
1.3 veillard 315: if ((xmlStrEqual(insert->name, name)) &&
316: (xmlStrEqual(insert->name2, name2)) &&
317: (xmlStrEqual(insert->name3, name3))) {
1.1 veillard 318: if (f)
319: f(insert->payload);
320: insert->payload = userdata;
321: return(0);
322: }
323: }
324:
325: entry = xmlMalloc(sizeof(xmlHashEntry));
326: if (entry == NULL)
327: return(-1);
328: entry->name = xmlStrdup(name);
1.3 veillard 329: entry->name2 = xmlStrdup(name2);
330: entry->name3 = xmlStrdup(name3);
1.1 veillard 331: entry->payload = userdata;
332: entry->next = NULL;
333:
334:
335: if (insert == NULL) {
336: table->table[key] = entry;
337: } else {
338: insert->next = entry;
339: }
340: return(0);
341: }
342:
343: /**
344: * xmlHashLookup:
345: * @table: the hash table
346: * @name: the name of the userdata
1.3 veillard 347: * @name2: a second name of the userdata
348: * @name3: a third name of the userdata
1.1 veillard 349: *
350: * Find the userdata specified by the name.
351: *
352: * Returns the a pointer to the userdata
353: */
354: void *
1.3 veillard 355: xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
356: const xmlChar *name2, const xmlChar *name3) {
1.1 veillard 357: unsigned long key;
358: xmlHashEntryPtr entry;
359:
360: if (table == NULL)
361: return(NULL);
362: if (name == NULL)
363: return(NULL);
364: key = xmlHashComputeKey(table, name);
365: for (entry = table->table[key]; entry != NULL; entry = entry->next) {
1.4 ! veillard 366: if ((xmlStrEqual(entry->name, name)) &&
! 367: (xmlStrEqual(entry->name2, name2)) &&
! 368: (xmlStrEqual(entry->name3, name3)))
1.1 veillard 369: return(entry->payload);
370: }
371: return(NULL);
372: }
1.2 veillard 373:
374: /**
375: * xmlHashScan:
376: * @table: the hash table
377: * @f: the scanner function for items in the hash
378: * @data: extra data passed to f
379: *
380: * Scan the hash table and applied f to each value.
381: */
382: void
383: xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
384: int i;
385: xmlHashEntryPtr iter;
386: xmlHashEntryPtr next;
387:
388: if (table == NULL)
389: return;
390: if (f == NULL)
391: return;
392:
393: if (table->table) {
394: for(i = 0; i < table->size; i++) {
395: iter = table->table[i];
396: while (iter) {
397: next = iter->next;
398: if (f)
399: f(iter->payload, data);
400: iter = next;
401: }
402: }
403: }
404: }
405:
406: /**
407: * xmlHashCopy:
408: * @table: the hash table
409: * @f: the copier function for items in the hash
410: *
411: * Scan the hash table and applied f to each value.
412: *
413: * Returns the new table or NULL in case of error.
414: */
415: xmlHashTablePtr
416: xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
417: int i;
418: xmlHashEntryPtr iter;
419: xmlHashEntryPtr next;
420: xmlHashTablePtr ret;
421:
422: if (table == NULL)
423: return(NULL);
424: if (f == NULL)
425: return(NULL);
426:
427: ret = xmlHashCreate(table->size);
428: if (table->table) {
429: for(i = 0; i < table->size; i++) {
430: iter = table->table[i];
431: while (iter) {
432: next = iter->next;
1.3 veillard 433: xmlHashAddEntry3(ret, iter->name, iter->name2,
434: iter->name3, f(iter));
1.2 veillard 435: iter = next;
436: }
437: }
438: }
439: return(ret);
440: }
441:
Webmaster