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