1347
|
1 /*
|
|
2 * This program is free software; you can redistribute it and/or modify
|
|
3 * it under the terms of the GNU General Public License as published by
|
|
4 * the Free Software Foundation; either version 2 of the License, or
|
|
5 * (at your option) any later version.
|
|
6 *
|
|
7 * This program is distributed in the hope that it will be useful,
|
|
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10 * GNU General Public License for more details.
|
|
11 *
|
|
12 * You should have received a copy of the GNU General Public License
|
|
13 * along with this program; if not, write to the Free Software
|
|
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
15 *
|
|
16 * Jabber
|
|
17 * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
|
|
18 */
|
|
19 #include <libxode.h>
|
|
20
|
|
21 /*****************************************************************************
|
|
22 * Internal type definitions
|
|
23 */
|
|
24
|
|
25 typedef struct tagHNODE
|
|
26 {
|
|
27 struct tagHNODE *next; /* next node in list */
|
|
28 const void *key; /* key pointer */
|
|
29 void *value; /* value pointer */
|
|
30 } HNODE;
|
|
31
|
|
32 #define SLAB_NUM_NODES 64 /* allocate this many nodes per slab */
|
|
33
|
|
34 typedef struct tagHSLAB
|
|
35 {
|
|
36 struct tagHSLAB *next; /* next slab pointer */
|
|
37 HNODE nodes[SLAB_NUM_NODES]; /* the actual nodes */
|
|
38 } HSLAB;
|
|
39
|
|
40 #define HASH_NUM_BUCKETS 509 /* should be a prime number; see Knuth */
|
|
41
|
|
42 typedef struct tagHASHTABLE_INTERNAL
|
|
43 {
|
|
44 unsigned long sig1; /* first signature word */
|
|
45 KEYHASHFUNC hash; /* hash function */
|
|
46 KEYCOMPAREFUNC cmp; /* comparison function */
|
|
47 int count; /* table entry count */
|
|
48 int bcount; /* bucket count */
|
|
49 HNODE **buckets; /* the hash buckets */
|
|
50 unsigned long sig2; /* second signature word */
|
|
51
|
|
52 } HASHTABLE_INTERNAL;
|
|
53
|
|
54 #define HASH_SIG1 0x68736148UL /* "Hash" */
|
|
55 #define HASH_SIG2 0x6F627245UL /* "Erbo" */
|
|
56
|
|
57 #define do_hash(tb,key) ((*((tb)->hash))(key) % ((tb)->bcount))
|
|
58
|
|
59 static HNODE *s_free_nodes = NULL; /* free nodes list */
|
|
60 static HSLAB *s_slabs = NULL; /* node slabs list */
|
|
61
|
|
62 /*****************************************************************************
|
|
63 * Internal functions
|
|
64 */
|
|
65
|
|
66 static HNODE *allocate_node(
|
|
67 const void *key, /* key pointer for this node */
|
|
68 void *value) /* value pointer for this node */
|
|
69 /*
|
|
70 allocate_node allocates a new hash node and fills it. Returns NULL if the
|
|
71 node could not be allocated.
|
|
72 */
|
|
73 {
|
|
74 HNODE *rc; /* return from this function */
|
|
75
|
|
76 if (!s_free_nodes)
|
|
77 { /* allocate a new slabful of nodes and chain them to make a new free list */
|
|
78 register int i; /* loop counter */
|
|
79 HSLAB *slab = (HSLAB *)malloc(sizeof(HSLAB));
|
|
80 if (!slab)
|
|
81 return NULL;
|
|
82 memset(slab,0,sizeof(HSLAB));
|
|
83 slab->next = s_slabs;
|
|
84 for (i=0; i<(SLAB_NUM_NODES-1); i++)
|
|
85 slab->nodes[i].next = &(slab->nodes[i+1]);
|
|
86 s_free_nodes = &(slab->nodes[0]);
|
|
87 s_slabs = slab;
|
|
88
|
|
89 } /* end if */
|
|
90
|
|
91 /* grab a node off the fron of the free list and fill it */
|
|
92 rc = s_free_nodes;
|
|
93 s_free_nodes = rc->next;
|
|
94 rc->next = NULL;
|
|
95 rc->key = key;
|
|
96 rc->value = value;
|
|
97 return rc;
|
|
98
|
|
99 } /* end allocate_node */
|
|
100
|
|
101 static void free_node(
|
|
102 HNODE *node) /* node to be freed */
|
|
103 /*
|
|
104 free_node returns a hash node to the list.
|
|
105 */
|
|
106 {
|
|
107 /* zap the node contents to avoid problems later */
|
|
108 memset(node,0,sizeof(HNODE));
|
|
109
|
|
110 /* chain it onto the free list */
|
|
111 node->next = s_free_nodes;
|
|
112 s_free_nodes = node;
|
|
113
|
|
114 } /* end free_node */
|
|
115
|
|
116 static HNODE *find_node(
|
|
117 HASHTABLE_INTERNAL *tab, /* pointer to hash table */
|
|
118 const void *key, /* key value to look up */
|
|
119 int bucket) /* bucket number (-1 to have function compute it) */
|
|
120 /*
|
|
121 find_node walks a hash bucket to find a node whose key matches the named key value.
|
|
122 Returns the node pointer, or NULL if it's not found.
|
|
123 */
|
|
124 {
|
|
125 register HNODE *p; /* search pointer/return from this function */
|
|
126
|
|
127 if (bucket<0) /* compute hash value if we don't know it already */
|
|
128 bucket = do_hash(tab,key);
|
|
129
|
|
130 /* search through the bucket contents */
|
|
131 for (p=tab->buckets[bucket]; p; p=p->next)
|
|
132 if ((*(tab->cmp))(key,p->key)==0)
|
|
133 return p; /* found! */
|
|
134
|
|
135 return NULL; /* not found */
|
|
136
|
|
137 } /* end find_node */
|
|
138
|
|
139 static HASHTABLE_INTERNAL *handle2ptr(
|
|
140 HASHTABLE tbl) /* hash table handle */
|
|
141 /*
|
|
142 handle2ptr converts a hash table handle into a pointer and checks its signatures
|
|
143 to make sure someone's not trying to pull a whizzer on this module.
|
|
144 */
|
|
145 {
|
|
146 register HASHTABLE_INTERNAL *rc = (HASHTABLE_INTERNAL *)tbl;
|
|
147 if ((rc->sig1==HASH_SIG1) && (rc->sig2==HASH_SIG2))
|
|
148 return rc; /* signatures match */
|
|
149 else
|
|
150 return NULL; /* yIkes! */
|
|
151 }
|
|
152
|
|
153 /*****************************************************************************
|
|
154 * External functions
|
|
155 */
|
|
156
|
|
157 HASHTABLE ghash_create(int buckets, KEYHASHFUNC hash, KEYCOMPAREFUNC cmp)
|
|
158 /*
|
|
159 Description:
|
|
160 Creates a new hash table.
|
|
161
|
|
162 Input:
|
|
163 Parameters:
|
|
164 buckets - Number of buckets to allocate for the hash table; this value
|
|
165 should be a prime number for maximum efficiency.
|
|
166 hash - Key hash code function to use.
|
|
167 cmp - Key comparison function to use.
|
|
168
|
|
169 Output:
|
|
170 Returns:
|
|
171 NULL - Table could not be allocated.
|
|
172 Other - Handle to the new hashtable.
|
|
173 */
|
|
174 {
|
|
175 HASHTABLE_INTERNAL *tab; /* new table structure */
|
|
176 char *allocated;
|
|
177
|
|
178 if (!hash || !cmp)
|
|
179 return NULL; /* bogus! */
|
|
180
|
|
181 if (buckets<=0)
|
|
182 buckets = HASH_NUM_BUCKETS;
|
|
183
|
|
184 /* allocate a hash table structure */
|
|
185 allocated = malloc(sizeof(HASHTABLE_INTERNAL) + (buckets * sizeof(HNODE *)));
|
|
186 if (!allocated)
|
|
187 return NULL; /* memory error */
|
|
188
|
|
189 /* fill the fields of the hash table */
|
|
190 tab = (HASHTABLE_INTERNAL *)allocated;
|
|
191 allocated += sizeof(HASHTABLE_INTERNAL);
|
|
192 memset(tab,0,sizeof(HASHTABLE_INTERNAL));
|
|
193 memset(allocated,0,buckets * sizeof(HNODE *));
|
|
194 tab->sig1 = HASH_SIG1;
|
|
195 tab->hash = hash;
|
|
196 tab->cmp = cmp;
|
|
197 tab->bcount = buckets;
|
|
198 tab->buckets = (HNODE **)allocated;
|
|
199 tab->sig2 = HASH_SIG2;
|
|
200
|
|
201 return (HASHTABLE)tab; /* Qa'pla! */
|
|
202
|
|
203 } /* end ghash_create */
|
|
204
|
|
205 void ghash_destroy(HASHTABLE tbl)
|
|
206 /*
|
|
207 Description:
|
|
208 Destroys a hash table.
|
|
209
|
|
210 Input:
|
|
211 Parameters:
|
|
212 tbl - Table to be destroyed.
|
|
213
|
|
214 Output:
|
|
215 Returns:
|
|
216 Nothing.
|
|
217 */
|
|
218 {
|
|
219 HASHTABLE_INTERNAL *tab; /* new table structure */
|
|
220 int i; /* loop counter */
|
|
221 HNODE *p, *p2; /* temporary pointers */
|
|
222
|
|
223 if (!tbl)
|
|
224 return; /* bogus! */
|
|
225
|
|
226 /* Convert the handle to a table pointer. */
|
|
227 tab = handle2ptr(tbl);
|
|
228 if (!tab)
|
|
229 return;
|
|
230
|
|
231 /* Nuke the nodes it contains. */
|
|
232 for (i=0; i<tab->bcount; i++)
|
|
233 { /* free the contents of each bucket */
|
|
234 p = tab->buckets[i];
|
|
235 while (p)
|
|
236 { /* free each node in turn */
|
|
237 p2 = p->next;
|
|
238 free_node(p);
|
|
239 p = p2;
|
|
240
|
|
241 } /* end while */
|
|
242
|
|
243 } /* end for */
|
|
244
|
|
245 free(tab); /* bye bye now! */
|
|
246
|
|
247 } /* end ghash_destroy */
|
|
248
|
|
249 void *ghash_get(HASHTABLE tbl, const void *key)
|
|
250 /*
|
|
251 Description:
|
|
252 Retrieves a value stored in the hash table.
|
|
253
|
|
254 Input:
|
|
255 Parameters:
|
|
256 tbl - The hash table to look in.
|
|
257 key - The key value to search on.
|
|
258
|
|
259 Output:
|
|
260 Returns:
|
|
261 NULL - Value not found.
|
|
262 Other - Value corresponding to the specified key.
|
|
263 */
|
|
264 {
|
|
265 HASHTABLE_INTERNAL *tab; /* internal table pointer */
|
|
266 HNODE *node; /* hash node */
|
|
267 void *rc = NULL; /* return from this function */
|
|
268
|
|
269 if (!tbl || !key)
|
|
270 return NULL; /* bogus! */
|
|
271
|
|
272 /* Convert the handle to a table pointer. */
|
|
273 tab = handle2ptr(tbl);
|
|
274 if (!tab)
|
|
275 return NULL; /* error */
|
|
276
|
|
277 /* Attempt to find the node. */
|
|
278 node = find_node(tab,key,-1);
|
|
279 if (node)
|
|
280 rc = node->value; /* found it! */
|
|
281
|
|
282 return rc;
|
|
283
|
|
284 } /* end ghash_get */
|
|
285
|
|
286 int ghash_put(HASHTABLE tbl, const void *key, void *value)
|
|
287 /*
|
|
288 Description:
|
|
289 Associates a key with a value in this hash table.
|
|
290
|
|
291 Input:
|
|
292 Parameters:
|
|
293 tbl - Hash table to add.
|
|
294 key - Key to use for the value in the table.
|
|
295 value - Value to add for this key.
|
|
296
|
|
297 Output:
|
|
298 Returns:
|
|
299 1 - Success.
|
|
300 0 - Failure.
|
|
301
|
|
302 Notes:
|
|
303 If the specified key is already in the hashtable, its value will be replaced.
|
|
304 */
|
|
305 {
|
|
306 HASHTABLE_INTERNAL *tab; /* internal table pointer */
|
|
307 int bucket; /* bucket value goes into */
|
|
308 HNODE *node; /* hash node */
|
|
309 int rc = 1; /* return from this function */
|
|
310
|
|
311 if (!tbl || !key || !value)
|
|
312 return 0; /* bogus! */
|
|
313
|
|
314 /* Convert the handle to a table pointer. */
|
|
315 tab = handle2ptr(tbl);
|
|
316 if (!tab)
|
|
317 return 0; /* error */
|
|
318
|
|
319
|
|
320 /* Compute the hash bucket and try to find an existing node. */
|
|
321 bucket = do_hash(tab,key);
|
|
322 node = find_node(tab,key,bucket);
|
|
323 if (!node)
|
|
324 { /* OK, try to allocate a new node. */
|
|
325 node = allocate_node(key,value);
|
|
326 if (node)
|
|
327 { /* Chain the new node into the hash table. */
|
|
328 node->next = tab->buckets[bucket];
|
|
329 tab->buckets[bucket] = node;
|
|
330 tab->count++;
|
|
331
|
|
332 } /* end if */
|
|
333 else /* allocation error */
|
|
334 rc = 0;
|
|
335
|
|
336 } /* end if */
|
|
337 else /* already in table - just reassign value */
|
|
338 node->value = value;
|
|
339
|
|
340 return rc;
|
|
341
|
|
342 } /* end ghash_put */
|
|
343
|
|
344 int ghash_remove(HASHTABLE tbl, const void *key)
|
|
345 /*
|
|
346 Description:
|
|
347 Removes an entry from a hash table, given its key.
|
|
348
|
|
349 Input:
|
|
350 Parameters:
|
|
351 tbl - Hash table to remove from.
|
|
352 key - Key of value to remove.
|
|
353
|
|
354 Output:
|
|
355 Returns:
|
|
356 1 - Success.
|
|
357 0 - Failure; key not present in hash table.
|
|
358 */
|
|
359 {
|
|
360 HASHTABLE_INTERNAL *tab; /* internal table pointer */
|
|
361 int bucket; /* bucket value goes into */
|
|
362 HNODE *node; /* hash node */
|
|
363 register HNODE *p; /* removal pointer */
|
|
364 int rc = 1; /* return from this function */
|
|
365
|
|
366 if (!tbl || !key)
|
|
367 return 0; /* bogus! */
|
|
368
|
|
369 /* Convert the handle to a table pointer. */
|
|
370 tab = handle2ptr(tbl);
|
|
371 if (!tab)
|
|
372 return 0; /* error */
|
|
373
|
|
374
|
|
375 /* Compute the hash bucket and try to find an existing node. */
|
|
376 bucket = do_hash(tab,key);
|
|
377 node = find_node(tab,key,bucket);
|
|
378 if (node)
|
|
379 { /* look to unchain it from the bucket it's in */
|
|
380 if (node==tab->buckets[bucket])
|
|
381 tab->buckets[bucket] = node->next; /* unchain at head */
|
|
382 else
|
|
383 { /* unchain in middle of list */
|
|
384 for (p=tab->buckets[bucket]; p->next!=node; p=p->next) ;
|
|
385 p->next = node->next;
|
|
386
|
|
387 } /* end else */
|
|
388
|
|
389 free_node(node); /* bye bye now! */
|
|
390 tab->count--;
|
|
391
|
|
392 } /* end if */
|
|
393 else /* node not found */
|
|
394 rc = 0;
|
|
395
|
|
396 return rc;
|
|
397
|
|
398 } /* end ghash_remove */
|
|
399
|
|
400 int ghash_walk(HASHTABLE tbl, TABLEWALKFUNC func, void *user_data)
|
|
401 /*
|
|
402 Description:
|
|
403 "Walks" through a hash table, calling a callback function for each element
|
|
404 stored in it.
|
|
405
|
|
406 Input:
|
|
407 Parameters:
|
|
408 tbl - Hash table to walk.
|
|
409 func - Function to be called for each node. It takes three parameters,
|
|
410 a user data pointer, a key value pointer, and a data value pointer.
|
|
411 It returns 0 to stop the enumeration or 1 to keep it going.
|
|
412 user_data - Value to use as the first parameter for the callback
|
|
413 function.
|
|
414
|
|
415 Output:
|
|
416 Returns:
|
|
417 0 - Error occurred.
|
|
418 Other - Number of nodes visited up to and including the one for which
|
|
419 the callback function returned 0, if it did; ranges from 1
|
|
420 to the number of nodes in the hashtable.
|
|
421 */
|
|
422 {
|
|
423 HASHTABLE_INTERNAL *tab; /* internal table pointer */
|
|
424 int i; /* loop counter */
|
|
425 int running = 1; /* we're still running */
|
|
426 int count = 0; /* number of nodes visited before stop node */
|
|
427 register HNODE *p, *p2; /* loop pointer */
|
|
428
|
|
429 if (!tbl || !func)
|
|
430 return -1; /* bogus values! */
|
|
431
|
|
432 /* Convert the handle to a table pointer. */
|
|
433 tab = handle2ptr(tbl);
|
|
434 if (!tab)
|
|
435 return -1; /* error */
|
|
436
|
|
437
|
|
438 for (i=0; running && (i<tab->bcount); i++)
|
|
439 { /* visit the contents of each bucket */
|
|
440 p = tab->buckets[i];
|
|
441 while (running && p)
|
|
442 { /* visit each node in turn */
|
|
443 p2 = p->next;
|
|
444 count++;
|
|
445 running = (*func)(user_data,p->key,p->value);
|
|
446 p = p2;
|
|
447
|
|
448 } /* end while */
|
|
449
|
|
450 } /* end for */
|
|
451
|
|
452 return count;
|
|
453
|
|
454 } /* end ghash_walk */
|
|
455
|
|
456 int str_hash_code(const char *s)
|
|
457 /*
|
|
458 Description:
|
|
459 Generates a hash code for a string. This function uses the ELF hashing
|
|
460 algorithm as reprinted in Andrew Binstock, "Hashing Rehashed," _Dr.
|
|
461 Dobb's Journal_, April 1996.
|
|
462
|
|
463 Input:
|
|
464 Parameters:
|
|
465 s - The string to be hashed.
|
|
466
|
|
467 Output:
|
|
468 Returns:
|
|
469 A hash code for the string.
|
|
470 */
|
|
471 {
|
|
472 /* ELF hash uses unsigned chars and unsigned arithmetic for portability */
|
|
473 const unsigned char *name = (const unsigned char *)s;
|
|
474 unsigned long h = 0, g;
|
|
475
|
|
476 if (!name)
|
|
477 return 0; /* anti-NULL guard not in the original */
|
|
478
|
|
479 while (*name)
|
|
480 { /* do some fancy bitwanking on the string */
|
|
481 h = (h << 4) + (unsigned long)(*name++);
|
|
482 if ((g = (h & 0xF0000000UL))!=0)
|
|
483 h ^= (g >> 24);
|
|
484 h &= ~g;
|
|
485
|
|
486 } /* end while */
|
|
487
|
|
488 return (int)h;
|
|
489
|
|
490 }
|