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