2 * Copyright (c) 1984 through 2008, William LeFebvre
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
16 * * Neither the name of William LeFebvre nor the names of other
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 /* The file hash.c is generated from hash.m4c via the preprocessor M4 */
38 * Hash table functions: init, add, lookup, first, next, sizeinfo.
39 * This is a conventional "bucket hash". The key is hashed in to a number
40 * less than or equal to the number of buckets and the result is used
41 * to index in to the array of buckets. Each bucket is a linked list
42 * that contains all the key/value pairs which hashed to that index.
50 #define memzero(a, b) memset((a), 0, (b))
51 #else /* !STDC_HEADERS */
53 #define memzero(a, b) memset((a), 0, (b))
55 #define memcpy(a, b, c) bcopy((b), (a), (c))
56 #define memzero(a, b) bzero((a), (b))
57 #define memcmp(a, b, c) bcmp((a), (b), (c))
58 #endif /* HAVE_MEMCPY */
69 #endif /* !STDC_HEADERS */
71 /* After all that there are still some systems that don't have NULL defined */
89 dnl # The m4 code uses MALLOC, FREE, and STRDUP for dynamic allocation.
90 dnl # You can change what these get mapped to here:
92 define(`MALLOC', `malloc($1)')
93 define(`FREE', `free($1)')
94 define(`STRDUP', `strdup($1)')
109 if ((i/j)==floor(i/j))
126 string_hash(hash_table *ht, char *key)
133 while ((ch = (unsigned char)*key++) != '\0')
142 s = s + (ch << shifting);
147 return (s % ht->num_buckets);
150 void ll_init(llist *q)
157 llistitem *ll_newitem(int size)
162 qi = (llistitem *)MALLOC(sizeof(llistitem) + size);
163 qi->datum = ((void *)qi + sizeof(llistitem));
167 void ll_freeitem(llistitem *li)
173 void ll_add(llist *q, llistitem *new)
181 void ll_extract(llist *q, llistitem *qi, llistitem *last)
190 last->next = qi->next;
196 #define LL_FIRST(q) ((q)->head)
204 #define LL_NEXT(q, qi) ((qi) != NULL ? (qi)->next : NULL)
206 ll_next(llist *q, llistitem *qi)
209 return (qi != NULL ? qi->next : NULL);
212 #define LL_ISEMPTY(ll) ((ll)->count == 0)
214 ll_isempty(llist *ll)
217 return (ll->count == 0);
221 * hash_table *hash_create(int num)
223 * Creates a hash table structure with at least "num" buckets.
235 /* create the resultant structure */
236 result = (hash_table *)MALLOC(sizeof(hash_table));
238 /* adjust bucket count to be prime */
239 num = next_prime(num);
241 /* create the buckets */
242 bytes = sizeof(bucket_t) * num;
243 result->buckets = b = (bucket_t *)MALLOC(bytes);
244 result->num_buckets = num;
246 /* create each bucket as a linked list */
258 * unsigned int hash_count(hash_table *ht)
260 * Return total number of elements contained in hash table.
264 hash_count(hash_table *ht)
268 register int cnt = 0;
269 register bucket_t *bucket;
271 bucket = ht->buckets;
272 while (i++ < ht->num_buckets)
274 cnt += bucket->list.count;
282 * void hash_sizeinfo(unsigned int *sizes, int max, hash_table *ht)
284 * Fill in "sizes" with information about bucket lengths in hash
289 hash_sizeinfo(unsigned int *sizes, int max, hash_table *ht)
294 register bucket_t *bucket;
296 memzero(sizes, max * sizeof(unsigned int));
298 bucket = ht->buckets;
300 while (i++ < ht->num_buckets)
302 idx = bucket->list.count;
303 sizes[idx >= max ? max-1 : idx]++;
308 dnl # HASH_TABLE_TMPL(suffix, keytype, to_hash, to_cmp, to_alloc, to_free)
310 dnl # This generates hash table functions suitable for keys
311 dnl # of type "keytype". The function names all end with "suffix".
312 dnl # "to_hash" is an expression that generates a hash index (this
313 dnl # expression can include key and ht). "to_cmp" is an expression
314 dnl # that compares "key" to "k1". "to_alloc" is an expression that
315 dnl # allocates space for "key", or empty if no allocation is needed.
316 dnl # "to_free" is an expression that frees "key", or empty if no
317 dnl # allocation is needed.
319 define(`HASH_TABLE_TMPL', `
322 * void hash_add_$1(hash_table *ht, $2 key, void *value)
324 * Add an element to table "ht". The element is described by
325 * "key" and "value". Return NULL on success. If the key
326 * already exists in the table, then no action is taken and
327 * the data for the existing element is returned.
332 hash_add_$1(hash_table *ht, $2 key, void *value)
343 /* allocate the space we will need */
344 newli = ll_newitem(sizeof(hash_item_$1));
345 hi = (hash_item_$1 *)newli->datum;
347 /* fill in the values */
348 hi->key = ifelse($5, , key, $5);
351 /* hash to the bucket */
352 bucket = &(ht->buckets[$3]);
354 /* walk the list to make sure we do not have a duplicate */
355 ll = &(bucket->list);
359 h = (hash_item_$1 *)li->datum;
366 li = LL_NEXT(ll, li);
370 /* is there already one there? */
373 /* add the unique element to the buckets list */
374 ll_add(&(bucket->list), newli);
379 /* free the stuff we just allocated */
381 return ((hash_item_$1 *)(li->datum))->value;
386 * void *hash_replace_$1(hash_table *ht, $2 key, void *value)
388 * Replace an existing value in the hash table with a new one and
389 * return the old value. If the key does not already exist in
390 * the hash table, add a new element and return NULL.
395 hash_replace_$1(hash_table *ht, $2 key, void *value)
405 /* find the bucket */
406 bucket = &(ht->buckets[$3]);
408 /* walk the list until we find the existing item */
409 ll = &(bucket->list);
413 hi = (hash_item_$1 *)li->datum;
417 /* found it: now replace the value with the new one */
422 li = LL_NEXT(ll, li);
425 /* if the element wasnt found, add it */
428 li = ll_newitem(sizeof(hash_item_$1));
429 hi = (hash_item_$1 *)li->datum;
430 hi->key = ifelse($5, , key, $5);
432 ll_add(&(bucket->list), li);
435 /* return the old value (so it can be freed) */
440 * void *hash_lookup_$1(hash_table *ht, $2 key)
442 * Look up "key" in "ht" and return the associated value. If "key"
443 * is not found, return NULL. Key type is $2
447 hash_lookup_$1(hash_table *ht, $2 key)
458 if ((bucket = &(ht->buckets[$3])) != NULL)
460 ll = &(bucket->list);
464 h = (hash_item_$1 *)li->datum;
471 li = LL_NEXT(ll, li);
478 * void *hash_remove_$1(hash_table *ht, $2 key)
480 * Remove the element associated with "key" from the hash table
481 * "ht". Return the value or NULL if the key was not found.
485 hash_remove_$1(hash_table *ht, $2 key)
497 if ((bucket = &(ht->buckets[$3])) != NULL)
499 ll = &(bucket->list);
504 hi = (hash_item_$1 *)li->datum;
508 ll_extract(ll, li, lilast);
516 li = LL_NEXT(ll, li);
523 * hash_item_$1 *hash_first_$1(hash_table *ht, hash_pos *pos)
525 * First function to call when iterating through all items in the hash
526 * table. Returns the first item in "ht" and initializes "*pos" to track
527 * the current position.
531 hash_first_$1(hash_table *ht, hash_pos *pos)
534 /* initialize pos for first item in first bucket */
535 pos->num_buckets = ht->num_buckets;
536 pos->hash_bucket = ht->buckets;
540 /* find the first non-empty bucket */
541 while(pos->hash_bucket->list.count == 0)
544 if (++pos->curr >= pos->num_buckets)
550 /* set and return the first item */
551 pos->ll_item = LL_FIRST(&(pos->hash_bucket->list));
552 return (hash_item_$1 *)pos->ll_item->datum;
557 * hash_item_$1 *hash_next_$1(hash_pos *pos)
559 * Return the next item in the hash table, using "pos" as a description
560 * of the present position in the hash table. "pos" also identifies the
561 * specific hash table. Return NULL if there are no more elements.
565 hash_next_$1(hash_pos *pos)
570 /* move item to last and check for NULL */
571 if ((pos->ll_last = pos->ll_item) == NULL)
573 /* are we really at the end of the hash table? */
574 if (pos->curr >= pos->num_buckets)
576 /* yes: return NULL */
579 /* no: regrab first item in current bucket list (might be NULL) */
580 li = LL_FIRST(&(pos->hash_bucket->list));
584 /* get the next item in the llist */
585 li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
588 /* if its NULL we have to find another bucket */
591 /* locate another bucket */
594 /* move to the next one */
596 if (++pos->curr >= pos->num_buckets)
598 /* at the end of the hash table */
603 /* get the first element (might be NULL) */
604 li = LL_FIRST(&(pos->hash_bucket->list));
607 /* li is the next element to dish out */
609 return (hash_item_$1 *)li->datum;
613 * void *hash_remove_pos_$1(hash_pos *pos)
615 * Remove the hash table entry pointed to by position marker "pos".
616 * The data from the entry is returned upon success, otherwise NULL.
621 hash_remove_pos_$1(hash_pos *pos)
630 if (pos == NULL || pos->ll_last == pos->ll_item)
635 /* at this point pos contains the item to remove (ll_item)
636 and its predecesor (ll_last) */
637 /* extract the item from the llist */
639 ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
641 /* retain the data */
642 hi = (hash_item_$1 *)li->datum;
645 /* free up the space */
650 /* back up to previous item */
651 /* its okay for ll_item to be null: hash_next will detect it */
652 pos->ll_item = pos->ll_last;
658 dnl # create hash talbe functions for unsigned int and for strings */
660 HASH_TABLE_TMPL(`uint', `unsigned int', `(key % ht->num_buckets)', `key == k1', ,)
661 HASH_TABLE_TMPL(`pid', `pid_t', `(key % ht->num_buckets)', `key == k1', ,)
662 HASH_TABLE_TMPL(`string', `char *', `string_hash(ht, key)', `strcmp(key, k1) == 0', `STRDUP(key)', `FREE(key)')
663 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)', ,)
665 HASH_TABLE_TMPL(`lwpid', `lwpid_t', `(key % ht->num_buckets)', `key == k1', ,)