hash.m4c revision 1.1.1.1 1 1.1 christos /*
2 1.1 christos * Copyright (c) 1984 through 2008, William LeFebvre
3 1.1 christos * All rights reserved.
4 1.1 christos *
5 1.1 christos * Redistribution and use in source and binary forms, with or without
6 1.1 christos * modification, are permitted provided that the following conditions are met:
7 1.1 christos *
8 1.1 christos * * Redistributions of source code must retain the above copyright
9 1.1 christos * notice, this list of conditions and the following disclaimer.
10 1.1 christos *
11 1.1 christos * * Redistributions in binary form must reproduce the above
12 1.1 christos * copyright notice, this list of conditions and the following disclaimer
13 1.1 christos * in the documentation and/or other materials provided with the
14 1.1 christos * distribution.
15 1.1 christos *
16 1.1 christos * * Neither the name of William LeFebvre nor the names of other
17 1.1 christos * contributors may be used to endorse or promote products derived from
18 1.1 christos * this software without specific prior written permission.
19 1.1 christos *
20 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 1.1 christos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 1.1 christos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 1.1 christos * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 1.1 christos * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 1.1 christos * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 1.1 christos * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 1.1 christos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 1.1 christos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 1.1 christos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 1.1 christos * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 1.1 christos */
32 1.1 christos
33 1.1 christos /* hash.m4c */
34 1.1 christos
35 1.1 christos /* The file hash.c is generated from hash.m4c via the preprocessor M4 */
36 1.1 christos
37 1.1 christos /*
38 1.1 christos * Hash table functions: init, add, lookup, first, next, sizeinfo.
39 1.1 christos * This is a conventional "bucket hash". The key is hashed in to a number
40 1.1 christos * less than or equal to the number of buckets and the result is used
41 1.1 christos * to index in to the array of buckets. Each bucket is a linked list
42 1.1 christos * that contains all the key/value pairs which hashed to that index.
43 1.1 christos */
44 1.1 christos
45 1.1 christos #include "config.h"
46 1.1 christos
47 1.1 christos #if STDC_HEADERS
48 1.1 christos #include <string.h>
49 1.1 christos #include <stdlib.h>
50 1.1 christos #define memzero(a, b) memset((a), 0, (b))
51 1.1 christos #else /* !STDC_HEADERS */
52 1.1 christos #ifdef HAVE_MEMCPY
53 1.1 christos #define memzero(a, b) memset((a), 0, (b))
54 1.1 christos #else
55 1.1 christos #define memcpy(a, b, c) bcopy((b), (a), (c))
56 1.1 christos #define memzero(a, b) bzero((a), (b))
57 1.1 christos #define memcmp(a, b, c) bcmp((a), (b), (c))
58 1.1 christos #endif /* HAVE_MEMCPY */
59 1.1 christos #ifdef HAVE_STRINGS_H
60 1.1 christos #include <strings.h>
61 1.1 christos #else
62 1.1 christos #ifdef HAVE_STRING_H
63 1.1 christos #include <string.h>
64 1.1 christos #endif
65 1.1 christos #endif
66 1.1 christos void *malloc();
67 1.1 christos void free();
68 1.1 christos char *strdup();
69 1.1 christos #endif /* !STDC_HEADERS */
70 1.1 christos
71 1.1 christos /* After all that there are still some systems that don't have NULL defined */
72 1.1 christos #ifndef NULL
73 1.1 christos #define NULL 0
74 1.1 christos #endif
75 1.1 christos
76 1.1 christos #ifdef HAVE_MATH_H
77 1.1 christos #include <math.h>
78 1.1 christos #endif
79 1.1 christos
80 1.1 christos #if !HAVE_PID_T
81 1.1 christos typedef long pid_t;
82 1.1 christos #endif
83 1.1 christos #if !HAVE_ID_T
84 1.1 christos typedef long id_t;
85 1.1 christos #endif
86 1.1 christos
87 1.1 christos #include "hash.h"
88 1.1 christos
89 1.1 christos dnl # The m4 code uses MALLOC, FREE, and STRDUP for dynamic allocation.
90 1.1 christos dnl # You can change what these get mapped to here:
91 1.1 christos
92 1.1 christos define(`MALLOC', `malloc($1)')
93 1.1 christos define(`FREE', `free($1)')
94 1.1 christos define(`STRDUP', `strdup($1)')
95 1.1 christos
96 1.1 christos static int
97 1.1 christos next_prime(int x)
98 1.1 christos
99 1.1 christos {
100 1.1 christos double i, j;
101 1.1 christos int f;
102 1.1 christos
103 1.1 christos i = x;
104 1.1 christos while (i++)
105 1.1 christos {
106 1.1 christos f=1;
107 1.1 christos for (j=2; j<i; j++)
108 1.1 christos {
109 1.1 christos if ((i/j)==floor(i/j))
110 1.1 christos {
111 1.1 christos f=0;
112 1.1 christos break;
113 1.1 christos }
114 1.1 christos }
115 1.1 christos if (f)
116 1.1 christos {
117 1.1 christos return (int)i;
118 1.1 christos }
119 1.1 christos }
120 1.1 christos return 1;
121 1.1 christos }
122 1.1 christos
123 1.1 christos /* string hashes */
124 1.1 christos
125 1.1 christos static int
126 1.1 christos string_hash(hash_table *ht, char *key)
127 1.1 christos
128 1.1 christos {
129 1.1 christos unsigned long s = 0;
130 1.1 christos unsigned char ch;
131 1.1 christos int shifting = 24;
132 1.1 christos
133 1.1 christos while ((ch = (unsigned char)*key++) != '\0')
134 1.1 christos {
135 1.1 christos if (shifting == 0)
136 1.1 christos {
137 1.1 christos s = s + ch;
138 1.1 christos shifting = 24;
139 1.1 christos }
140 1.1 christos else
141 1.1 christos {
142 1.1 christos s = s + (ch << shifting);
143 1.1 christos shifting -= 8;
144 1.1 christos }
145 1.1 christos }
146 1.1 christos
147 1.1 christos return (s % ht->num_buckets);
148 1.1 christos }
149 1.1 christos
150 1.1 christos void ll_init(llist *q)
151 1.1 christos
152 1.1 christos {
153 1.1 christos q->head = NULL;
154 1.1 christos q->count = 0;
155 1.1 christos }
156 1.1 christos
157 1.1 christos llistitem *ll_newitem(int size)
158 1.1 christos
159 1.1 christos {
160 1.1 christos llistitem *qi;
161 1.1 christos
162 1.1 christos qi = (llistitem *)MALLOC(sizeof(llistitem) + size);
163 1.1 christos qi->datum = ((void *)qi + sizeof(llistitem));
164 1.1 christos return qi;
165 1.1 christos }
166 1.1 christos
167 1.1 christos void ll_freeitem(llistitem *li)
168 1.1 christos
169 1.1 christos {
170 1.1 christos FREE(li);
171 1.1 christos }
172 1.1 christos
173 1.1 christos void ll_add(llist *q, llistitem *new)
174 1.1 christos
175 1.1 christos {
176 1.1 christos new->next = q->head;
177 1.1 christos q->head = new;
178 1.1 christos q->count++;
179 1.1 christos }
180 1.1 christos
181 1.1 christos void ll_extract(llist *q, llistitem *qi, llistitem *last)
182 1.1 christos
183 1.1 christos {
184 1.1 christos if (last == NULL)
185 1.1 christos {
186 1.1 christos q->head = qi->next;
187 1.1 christos }
188 1.1 christos else
189 1.1 christos {
190 1.1 christos last->next = qi->next;
191 1.1 christos }
192 1.1 christos qi->next = NULL;
193 1.1 christos q->count--;
194 1.1 christos }
195 1.1 christos
196 1.1 christos #define LL_FIRST(q) ((q)->head)
197 1.1 christos llistitem *
198 1.1 christos ll_first(llist *q)
199 1.1 christos
200 1.1 christos {
201 1.1 christos return q->head;
202 1.1 christos }
203 1.1 christos
204 1.1 christos #define LL_NEXT(q, qi) ((qi) != NULL ? (qi)->next : NULL)
205 1.1 christos llistitem *
206 1.1 christos ll_next(llist *q, llistitem *qi)
207 1.1 christos
208 1.1 christos {
209 1.1 christos return (qi != NULL ? qi->next : NULL);
210 1.1 christos }
211 1.1 christos
212 1.1 christos #define LL_ISEMPTY(ll) ((ll)->count == 0)
213 1.1 christos int
214 1.1 christos ll_isempty(llist *ll)
215 1.1 christos
216 1.1 christos {
217 1.1 christos return (ll->count == 0);
218 1.1 christos }
219 1.1 christos
220 1.1 christos /*
221 1.1 christos * hash_table *hash_create(int num)
222 1.1 christos *
223 1.1 christos * Creates a hash table structure with at least "num" buckets.
224 1.1 christos */
225 1.1 christos
226 1.1 christos hash_table *
227 1.1 christos hash_create(int num)
228 1.1 christos
229 1.1 christos {
230 1.1 christos hash_table *result;
231 1.1 christos bucket_t *b;
232 1.1 christos int bytes;
233 1.1 christos int i;
234 1.1 christos
235 1.1 christos /* create the resultant structure */
236 1.1 christos result = (hash_table *)MALLOC(sizeof(hash_table));
237 1.1 christos
238 1.1 christos /* adjust bucket count to be prime */
239 1.1 christos num = next_prime(num);
240 1.1 christos
241 1.1 christos /* create the buckets */
242 1.1 christos bytes = sizeof(bucket_t) * num;
243 1.1 christos result->buckets = b = (bucket_t *)MALLOC(bytes);
244 1.1 christos result->num_buckets = num;
245 1.1 christos
246 1.1 christos /* create each bucket as a linked list */
247 1.1 christos i = num;
248 1.1 christos while (--i >= 0)
249 1.1 christos {
250 1.1 christos ll_init(&(b->list));
251 1.1 christos b++;
252 1.1 christos }
253 1.1 christos
254 1.1 christos return result;
255 1.1 christos }
256 1.1 christos
257 1.1 christos /*
258 1.1 christos * unsigned int hash_count(hash_table *ht)
259 1.1 christos *
260 1.1 christos * Return total number of elements contained in hash table.
261 1.1 christos */
262 1.1 christos
263 1.1 christos unsigned int
264 1.1 christos hash_count(hash_table *ht)
265 1.1 christos
266 1.1 christos {
267 1.1 christos register int i = 0;
268 1.1 christos register int cnt = 0;
269 1.1 christos register bucket_t *bucket;
270 1.1 christos
271 1.1 christos bucket = ht->buckets;
272 1.1 christos while (i++ < ht->num_buckets)
273 1.1 christos {
274 1.1 christos cnt += bucket->list.count;
275 1.1 christos bucket++;
276 1.1 christos }
277 1.1 christos
278 1.1 christos return cnt;
279 1.1 christos }
280 1.1 christos
281 1.1 christos /*
282 1.1 christos * void hash_sizeinfo(unsigned int *sizes, int max, hash_table *ht)
283 1.1 christos *
284 1.1 christos * Fill in "sizes" with information about bucket lengths in hash
285 1.1 christos * table "max".
286 1.1 christos */
287 1.1 christos
288 1.1 christos void
289 1.1 christos hash_sizeinfo(unsigned int *sizes, int max, hash_table *ht)
290 1.1 christos
291 1.1 christos {
292 1.1 christos register int i;
293 1.1 christos register int idx;
294 1.1 christos register bucket_t *bucket;
295 1.1 christos
296 1.1 christos memzero(sizes, max * sizeof(unsigned int));
297 1.1 christos
298 1.1 christos bucket = ht->buckets;
299 1.1 christos i = 0;
300 1.1 christos while (i++ < ht->num_buckets)
301 1.1 christos {
302 1.1 christos idx = bucket->list.count;
303 1.1 christos sizes[idx >= max ? max-1 : idx]++;
304 1.1 christos bucket++;
305 1.1 christos }
306 1.1 christos }
307 1.1 christos
308 1.1 christos dnl # HASH_TABLE_TMPL(suffix, keytype, to_hash, to_cmp, to_alloc, to_free)
309 1.1 christos dnl #
310 1.1 christos dnl # This generates hash table functions suitable for keys
311 1.1 christos dnl # of type "keytype". The function names all end with "suffix".
312 1.1 christos dnl # "to_hash" is an expression that generates a hash index (this
313 1.1 christos dnl # expression can include key and ht). "to_cmp" is an expression
314 1.1 christos dnl # that compares "key" to "k1". "to_alloc" is an expression that
315 1.1 christos dnl # allocates space for "key", or empty if no allocation is needed.
316 1.1 christos dnl # "to_free" is an expression that frees "key", or empty if no
317 1.1 christos dnl # allocation is needed.
318 1.1 christos
319 1.1 christos define(`HASH_TABLE_TMPL', `
320 1.1 christos
321 1.1 christos /*
322 1.1 christos * void hash_add_$1(hash_table *ht, $2 key, void *value)
323 1.1 christos *
324 1.1 christos * Add an element to table "ht". The element is described by
325 1.1 christos * "key" and "value". Return NULL on success. If the key
326 1.1 christos * already exists in the table, then no action is taken and
327 1.1 christos * the data for the existing element is returned.
328 1.1 christos * Key type is $2
329 1.1 christos */
330 1.1 christos
331 1.1 christos void *
332 1.1 christos hash_add_$1(hash_table *ht, $2 key, void *value)
333 1.1 christos
334 1.1 christos {
335 1.1 christos bucket_t *bucket;
336 1.1 christos hash_item_$1 *hi;
337 1.1 christos hash_item_$1 *h;
338 1.1 christos llist *ll;
339 1.1 christos llistitem *li;
340 1.1 christos llistitem *newli;
341 1.1 christos $2 k1;
342 1.1 christos
343 1.1 christos /* allocate the space we will need */
344 1.1 christos newli = ll_newitem(sizeof(hash_item_$1));
345 1.1 christos hi = (hash_item_$1 *)newli->datum;
346 1.1 christos
347 1.1 christos /* fill in the values */
348 1.1 christos hi->key = ifelse($5, , key, $5);
349 1.1 christos hi->value = value;
350 1.1 christos
351 1.1 christos /* hash to the bucket */
352 1.1 christos bucket = &(ht->buckets[$3]);
353 1.1 christos
354 1.1 christos /* walk the list to make sure we do not have a duplicate */
355 1.1 christos ll = &(bucket->list);
356 1.1 christos li = LL_FIRST(ll);
357 1.1 christos while (li != NULL)
358 1.1 christos {
359 1.1 christos h = (hash_item_$1 *)li->datum;
360 1.1 christos k1 = h->key;
361 1.1 christos if ($4)
362 1.1 christos {
363 1.1 christos /* found one */
364 1.1 christos break;
365 1.1 christos }
366 1.1 christos li = LL_NEXT(ll, li);
367 1.1 christos }
368 1.1 christos li = NULL;
369 1.1 christos
370 1.1 christos /* is there already one there? */
371 1.1 christos if (li == NULL)
372 1.1 christos {
373 1.1 christos /* add the unique element to the buckets list */
374 1.1 christos ll_add(&(bucket->list), newli);
375 1.1 christos return NULL;
376 1.1 christos }
377 1.1 christos else
378 1.1 christos {
379 1.1 christos /* free the stuff we just allocated */
380 1.1 christos ll_freeitem(newli);
381 1.1 christos return ((hash_item_$1 *)(li->datum))->value;
382 1.1 christos }
383 1.1 christos }
384 1.1 christos
385 1.1 christos /*
386 1.1 christos * void *hash_replace_$1(hash_table *ht, $2 key, void *value)
387 1.1 christos *
388 1.1 christos * Replace an existing value in the hash table with a new one and
389 1.1 christos * return the old value. If the key does not already exist in
390 1.1 christos * the hash table, add a new element and return NULL.
391 1.1 christos * Key type is $2
392 1.1 christos */
393 1.1 christos
394 1.1 christos void *
395 1.1 christos hash_replace_$1(hash_table *ht, $2 key, void *value)
396 1.1 christos
397 1.1 christos {
398 1.1 christos bucket_t *bucket;
399 1.1 christos hash_item_$1 *hi;
400 1.1 christos llist *ll;
401 1.1 christos llistitem *li;
402 1.1 christos void *result = NULL;
403 1.1 christos $2 k1;
404 1.1 christos
405 1.1 christos /* find the bucket */
406 1.1 christos bucket = &(ht->buckets[$3]);
407 1.1 christos
408 1.1 christos /* walk the list until we find the existing item */
409 1.1 christos ll = &(bucket->list);
410 1.1 christos li = LL_FIRST(ll);
411 1.1 christos while (li != NULL)
412 1.1 christos {
413 1.1 christos hi = (hash_item_$1 *)li->datum;
414 1.1 christos k1 = hi->key;
415 1.1 christos if ($4)
416 1.1 christos {
417 1.1 christos /* found it: now replace the value with the new one */
418 1.1 christos result = hi->value;
419 1.1 christos hi->value = value;
420 1.1 christos break;
421 1.1 christos }
422 1.1 christos li = LL_NEXT(ll, li);
423 1.1 christos }
424 1.1 christos
425 1.1 christos /* if the element wasnt found, add it */
426 1.1 christos if (result == NULL)
427 1.1 christos {
428 1.1 christos li = ll_newitem(sizeof(hash_item_$1));
429 1.1 christos hi = (hash_item_$1 *)li->datum;
430 1.1 christos hi->key = ifelse($5, , key, $5);
431 1.1 christos hi->value = value;
432 1.1 christos ll_add(&(bucket->list), li);
433 1.1 christos }
434 1.1 christos
435 1.1 christos /* return the old value (so it can be freed) */
436 1.1 christos return result;
437 1.1 christos }
438 1.1 christos
439 1.1 christos /*
440 1.1 christos * void *hash_lookup_$1(hash_table *ht, $2 key)
441 1.1 christos *
442 1.1 christos * Look up "key" in "ht" and return the associated value. If "key"
443 1.1 christos * is not found, return NULL. Key type is $2
444 1.1 christos */
445 1.1 christos
446 1.1 christos void *
447 1.1 christos hash_lookup_$1(hash_table *ht, $2 key)
448 1.1 christos
449 1.1 christos {
450 1.1 christos bucket_t *bucket;
451 1.1 christos llist *ll;
452 1.1 christos llistitem *li;
453 1.1 christos hash_item_$1 *h;
454 1.1 christos void *result;
455 1.1 christos $2 k1;
456 1.1 christos
457 1.1 christos result = NULL;
458 1.1 christos if ((bucket = &(ht->buckets[$3])) != NULL)
459 1.1 christos {
460 1.1 christos ll = &(bucket->list);
461 1.1 christos li = LL_FIRST(ll);
462 1.1 christos while (li != NULL)
463 1.1 christos {
464 1.1 christos h = (hash_item_$1 *)li->datum;
465 1.1 christos k1 = h->key;
466 1.1 christos if ($4)
467 1.1 christos {
468 1.1 christos result = h->value;
469 1.1 christos break;
470 1.1 christos }
471 1.1 christos li = LL_NEXT(ll, li);
472 1.1 christos }
473 1.1 christos }
474 1.1 christos return result;
475 1.1 christos }
476 1.1 christos
477 1.1 christos /*
478 1.1 christos * void *hash_remove_$1(hash_table *ht, $2 key)
479 1.1 christos *
480 1.1 christos * Remove the element associated with "key" from the hash table
481 1.1 christos * "ht". Return the value or NULL if the key was not found.
482 1.1 christos */
483 1.1 christos
484 1.1 christos void *
485 1.1 christos hash_remove_$1(hash_table *ht, $2 key)
486 1.1 christos
487 1.1 christos {
488 1.1 christos bucket_t *bucket;
489 1.1 christos llist *ll;
490 1.1 christos llistitem *li;
491 1.1 christos llistitem *lilast;
492 1.1 christos hash_item_$1 *hi;
493 1.1 christos void *result;
494 1.1 christos $2 k1;
495 1.1 christos
496 1.1 christos result = NULL;
497 1.1 christos if ((bucket = &(ht->buckets[$3])) != NULL)
498 1.1 christos {
499 1.1 christos ll = &(bucket->list);
500 1.1 christos li = LL_FIRST(ll);
501 1.1 christos lilast = NULL;
502 1.1 christos while (li != NULL)
503 1.1 christos {
504 1.1 christos hi = (hash_item_$1 *)li->datum;
505 1.1 christos k1 = hi->key;
506 1.1 christos if ($4)
507 1.1 christos {
508 1.1 christos ll_extract(ll, li, lilast);
509 1.1 christos result = hi->value;
510 1.1 christos key = hi->key;
511 1.1 christos $6;
512 1.1 christos ll_freeitem(li);
513 1.1 christos break;
514 1.1 christos }
515 1.1 christos lilast = li;
516 1.1 christos li = LL_NEXT(ll, li);
517 1.1 christos }
518 1.1 christos }
519 1.1 christos return result;
520 1.1 christos }
521 1.1 christos
522 1.1 christos /*
523 1.1 christos * hash_item_$1 *hash_first_$1(hash_table *ht, hash_pos *pos)
524 1.1 christos *
525 1.1 christos * First function to call when iterating through all items in the hash
526 1.1 christos * table. Returns the first item in "ht" and initializes "*pos" to track
527 1.1 christos * the current position.
528 1.1 christos */
529 1.1 christos
530 1.1 christos hash_item_$1 *
531 1.1 christos hash_first_$1(hash_table *ht, hash_pos *pos)
532 1.1 christos
533 1.1 christos {
534 1.1 christos /* initialize pos for first item in first bucket */
535 1.1 christos pos->num_buckets = ht->num_buckets;
536 1.1 christos pos->hash_bucket = ht->buckets;
537 1.1 christos pos->curr = 0;
538 1.1 christos pos->ll_last = NULL;
539 1.1 christos
540 1.1 christos /* find the first non-empty bucket */
541 1.1 christos while(pos->hash_bucket->list.count == 0)
542 1.1 christos {
543 1.1 christos pos->hash_bucket++;
544 1.1 christos if (++pos->curr >= pos->num_buckets)
545 1.1 christos {
546 1.1 christos return NULL;
547 1.1 christos }
548 1.1 christos }
549 1.1 christos
550 1.1 christos /* set and return the first item */
551 1.1 christos pos->ll_item = LL_FIRST(&(pos->hash_bucket->list));
552 1.1 christos return (hash_item_$1 *)pos->ll_item->datum;
553 1.1 christos }
554 1.1 christos
555 1.1 christos
556 1.1 christos /*
557 1.1 christos * hash_item_$1 *hash_next_$1(hash_pos *pos)
558 1.1 christos *
559 1.1 christos * Return the next item in the hash table, using "pos" as a description
560 1.1 christos * of the present position in the hash table. "pos" also identifies the
561 1.1 christos * specific hash table. Return NULL if there are no more elements.
562 1.1 christos */
563 1.1 christos
564 1.1 christos hash_item_$1 *
565 1.1 christos hash_next_$1(hash_pos *pos)
566 1.1 christos
567 1.1 christos {
568 1.1 christos llistitem *li;
569 1.1 christos
570 1.1 christos /* move item to last and check for NULL */
571 1.1 christos if ((pos->ll_last = pos->ll_item) == NULL)
572 1.1 christos {
573 1.1 christos /* are we really at the end of the hash table? */
574 1.1 christos if (pos->curr >= pos->num_buckets)
575 1.1 christos {
576 1.1 christos /* yes: return NULL */
577 1.1 christos return NULL;
578 1.1 christos }
579 1.1 christos /* no: regrab first item in current bucket list (might be NULL) */
580 1.1 christos li = LL_FIRST(&(pos->hash_bucket->list));
581 1.1 christos }
582 1.1 christos else
583 1.1 christos {
584 1.1 christos /* get the next item in the llist */
585 1.1 christos li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
586 1.1 christos }
587 1.1 christos
588 1.1 christos /* if its NULL we have to find another bucket */
589 1.1 christos while (li == NULL)
590 1.1 christos {
591 1.1 christos /* locate another bucket */
592 1.1 christos pos->ll_last = NULL;
593 1.1 christos
594 1.1 christos /* move to the next one */
595 1.1 christos pos->hash_bucket++;
596 1.1 christos if (++pos->curr >= pos->num_buckets)
597 1.1 christos {
598 1.1 christos /* at the end of the hash table */
599 1.1 christos pos->ll_item = NULL;
600 1.1 christos return NULL;
601 1.1 christos }
602 1.1 christos
603 1.1 christos /* get the first element (might be NULL) */
604 1.1 christos li = LL_FIRST(&(pos->hash_bucket->list));
605 1.1 christos }
606 1.1 christos
607 1.1 christos /* li is the next element to dish out */
608 1.1 christos pos->ll_item = li;
609 1.1 christos return (hash_item_$1 *)li->datum;
610 1.1 christos }
611 1.1 christos
612 1.1 christos /*
613 1.1 christos * void *hash_remove_pos_$1(hash_pos *pos)
614 1.1 christos *
615 1.1 christos * Remove the hash table entry pointed to by position marker "pos".
616 1.1 christos * The data from the entry is returned upon success, otherwise NULL.
617 1.1 christos */
618 1.1 christos
619 1.1 christos
620 1.1 christos void *
621 1.1 christos hash_remove_pos_$1(hash_pos *pos)
622 1.1 christos
623 1.1 christos {
624 1.1 christos llistitem *li;
625 1.1 christos void *ans;
626 1.1 christos hash_item_$1 *hi;
627 1.1 christos $2 key;
628 1.1 christos
629 1.1 christos /* sanity checks */
630 1.1 christos if (pos == NULL || pos->ll_last == pos->ll_item)
631 1.1 christos {
632 1.1 christos return NULL;
633 1.1 christos }
634 1.1 christos
635 1.1 christos /* at this point pos contains the item to remove (ll_item)
636 1.1 christos and its predecesor (ll_last) */
637 1.1 christos /* extract the item from the llist */
638 1.1 christos li = pos->ll_item;
639 1.1 christos ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
640 1.1 christos
641 1.1 christos /* retain the data */
642 1.1 christos hi = (hash_item_$1 *)li->datum;
643 1.1 christos ans = hi->value;
644 1.1 christos
645 1.1 christos /* free up the space */
646 1.1 christos key = hi->key;
647 1.1 christos $6;
648 1.1 christos ll_freeitem(li);
649 1.1 christos
650 1.1 christos /* back up to previous item */
651 1.1 christos /* its okay for ll_item to be null: hash_next will detect it */
652 1.1 christos pos->ll_item = pos->ll_last;
653 1.1 christos
654 1.1 christos return ans;
655 1.1 christos }
656 1.1 christos ')
657 1.1 christos
658 1.1 christos dnl # create hash talbe functions for unsigned int and for strings */
659 1.1 christos
660 1.1 christos HASH_TABLE_TMPL(`uint', `unsigned int', `(key % ht->num_buckets)', `key == k1', ,)
661 1.1 christos HASH_TABLE_TMPL(`pid', `pid_t', `(key % ht->num_buckets)', `key == k1', ,)
662 1.1 christos HASH_TABLE_TMPL(`string', `char *', `string_hash(ht, key)', `strcmp(key, k1) == 0', `STRDUP(key)', `FREE(key)')
663 1.1 christos HASH_TABLE_TMPL(`pidthr', `pidthr_t', `((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)', `(key.k_pid == k1.k_pid && key.k_thr == k1.k_thr)', ,)
664 1.1 christos #if HAVE_LWPID_T
665 1.1 christos HASH_TABLE_TMPL(`lwpid', `lwpid_t', `(key % ht->num_buckets)', `key == k1', ,)
666 1.1 christos #endif
667