Home | History | Annotate | Line # | Download | only in dist
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