1*57489Storek /* 2*57489Storek * Copyright (c) 1992 The Regents of the University of California. 3*57489Storek * All rights reserved. 4*57489Storek * 5*57489Storek * This software was developed by the Computer Systems Engineering group 6*57489Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7*57489Storek * contributed to Berkeley. 8*57489Storek * 9*57489Storek * All advertising materials mentioning features or use of this software 10*57489Storek * must display the following acknowledgement: 11*57489Storek * This product includes software developed by the University of 12*57489Storek * California, Lawrence Berkeley Laboratories. 13*57489Storek * 14*57489Storek * %sccs.include.redist.c% 15*57489Storek * 16*57489Storek * @(#)hash.c 5.1 (Berkeley) 01/12/93 17*57489Storek * 18*57489Storek * from: $Header: hash.c,v 1.2 93/01/12 03:57:57 torek Exp $ 19*57489Storek */ 20*57489Storek 21*57489Storek #include <sys/param.h> 22*57489Storek #include <stdlib.h> 23*57489Storek #include <string.h> 24*57489Storek #include "config.h" 25*57489Storek 26*57489Storek /* 27*57489Storek * Interned strings are kept in a hash table. By making each string 28*57489Storek * unique, the program can compare strings by comparing pointers. 29*57489Storek */ 30*57489Storek struct hashent { 31*57489Storek struct hashent *h_next; /* hash buckets are chained */ 32*57489Storek const char *h_name; /* the string */ 33*57489Storek u_int h_hash; /* its hash value */ 34*57489Storek void *h_value; /* other values (for name=value) */ 35*57489Storek }; 36*57489Storek struct hashtab { 37*57489Storek size_t ht_size; /* size (power of 2) */ 38*57489Storek u_int ht_mask; /* == ht_size - 1 */ 39*57489Storek u_int ht_used; /* number of entries used */ 40*57489Storek u_int ht_lim; /* when to expand */ 41*57489Storek struct hashent **ht_tab; /* base of table */ 42*57489Storek }; 43*57489Storek static struct hashtab strings; 44*57489Storek 45*57489Storek /* 46*57489Storek * HASHFRACTION controls ht_lim, which in turn controls the average chain 47*57489Storek * length. We allow a few entries, on average, as comparing them is usually 48*57489Storek * cheap (the h_hash values prevent a strcmp). 49*57489Storek */ 50*57489Storek #define HASHFRACTION(sz) ((sz) * 3 / 2) 51*57489Storek 52*57489Storek /* round up to next multiple of y, where y is a power of 2 */ 53*57489Storek #define ROUND(x, y) (((x) + (y) - 1) & ~((y) - 1)) 54*57489Storek 55*57489Storek /* 56*57489Storek * Allocate space that will never be freed. 57*57489Storek */ 58*57489Storek static void * 59*57489Storek poolalloc(size) 60*57489Storek size_t size; 61*57489Storek { 62*57489Storek register char *p; 63*57489Storek register size_t alloc; 64*57489Storek static char *pool; 65*57489Storek static size_t nleft; 66*57489Storek 67*57489Storek if (nleft < size) { 68*57489Storek /* 69*57489Storek * Compute a `good' size to allocate via malloc. 70*57489Storek * 16384 is a guess at a good page size for malloc; 71*57489Storek * 32 is a guess at malloc's overhead. 72*57489Storek */ 73*57489Storek alloc = ROUND(size + 32, 16384) - 32; 74*57489Storek p = emalloc(alloc); 75*57489Storek nleft = alloc - size; 76*57489Storek } else { 77*57489Storek p = pool; 78*57489Storek nleft -= size; 79*57489Storek } 80*57489Storek pool = p + size; 81*57489Storek return (p); 82*57489Storek } 83*57489Storek 84*57489Storek /* 85*57489Storek * Initialize a new hash table. The size must be a power of 2. 86*57489Storek */ 87*57489Storek static void 88*57489Storek ht_init(ht, sz) 89*57489Storek register struct hashtab *ht; 90*57489Storek size_t sz; 91*57489Storek { 92*57489Storek register struct hashent **h; 93*57489Storek register u_int n; 94*57489Storek 95*57489Storek h = emalloc(sz * sizeof *h); 96*57489Storek ht->ht_tab = h; 97*57489Storek ht->ht_size = sz; 98*57489Storek ht->ht_mask = sz - 1; 99*57489Storek for (n = 0; n < sz; n++) 100*57489Storek *h++ = NULL; 101*57489Storek ht->ht_used = 0; 102*57489Storek ht->ht_lim = HASHFRACTION(sz); 103*57489Storek } 104*57489Storek 105*57489Storek /* 106*57489Storek * Expand an existing hash table. 107*57489Storek */ 108*57489Storek static void 109*57489Storek ht_expand(ht) 110*57489Storek register struct hashtab *ht; 111*57489Storek { 112*57489Storek register struct hashent *p, **h, **oldh, *q; 113*57489Storek register u_int n, i; 114*57489Storek 115*57489Storek n = ht->ht_size * 2; 116*57489Storek h = emalloc(n * sizeof *h); 117*57489Storek for (i = 0; i < n; i++) 118*57489Storek h[i] = NULL; 119*57489Storek oldh = ht->ht_tab; 120*57489Storek n--; 121*57489Storek for (i = ht->ht_size; i != 0; i--) { 122*57489Storek for (p = *oldh++; p != NULL; p = q) { 123*57489Storek q = p->h_next; 124*57489Storek p->h_next = h[p->h_hash & n]; 125*57489Storek h[p->h_hash & n] = p; 126*57489Storek } 127*57489Storek } 128*57489Storek free(ht->ht_tab); 129*57489Storek ht->ht_tab = h; 130*57489Storek ht->ht_mask = n; 131*57489Storek ht->ht_size = ++n; 132*57489Storek ht->ht_lim = HASHFRACTION(n); 133*57489Storek } 134*57489Storek 135*57489Storek /* 136*57489Storek * Make a new hash entry, setting its h_next to NULL. 137*57489Storek */ 138*57489Storek static inline struct hashent * 139*57489Storek newhashent(name, h) 140*57489Storek const char *name; 141*57489Storek u_int h; 142*57489Storek { 143*57489Storek register struct hashent *hp; 144*57489Storek register char *m; 145*57489Storek 146*57489Storek m = poolalloc(sizeof(*hp) + ALIGNBYTES); 147*57489Storek hp = (struct hashent *)ALIGN(m); 148*57489Storek hp->h_name = name; 149*57489Storek hp->h_hash = h; 150*57489Storek hp->h_next = NULL; 151*57489Storek return (hp); 152*57489Storek } 153*57489Storek 154*57489Storek /* 155*57489Storek * Hash a string. 156*57489Storek */ 157*57489Storek static inline u_int 158*57489Storek hash(str) 159*57489Storek register const char *str; 160*57489Storek { 161*57489Storek register u_int h; 162*57489Storek 163*57489Storek for (h = 0; *str;) 164*57489Storek h = (h << 5) + h + *str++; 165*57489Storek return (h); 166*57489Storek } 167*57489Storek 168*57489Storek void 169*57489Storek initintern() 170*57489Storek { 171*57489Storek 172*57489Storek ht_init(&strings, 128); 173*57489Storek } 174*57489Storek 175*57489Storek /* 176*57489Storek * Generate a single unique copy of the given string. We expect this 177*57489Storek * function to be used frequently, so it should be fast. 178*57489Storek */ 179*57489Storek const char * 180*57489Storek intern(s) 181*57489Storek register const char *s; 182*57489Storek { 183*57489Storek register struct hashtab *ht; 184*57489Storek register struct hashent *hp, **hpp; 185*57489Storek register u_int h; 186*57489Storek register char *p; 187*57489Storek register size_t l; 188*57489Storek 189*57489Storek ht = &strings; 190*57489Storek h = hash(s); 191*57489Storek hpp = &ht->ht_tab[h & ht->ht_mask]; 192*57489Storek for (; (hp = *hpp) != NULL; hpp = &hp->h_next) 193*57489Storek if (hp->h_hash == h && strcmp(hp->h_name, s) == 0) 194*57489Storek return (hp->h_name); 195*57489Storek l = strlen(s) + 1; 196*57489Storek p = poolalloc(l); 197*57489Storek bcopy(s, p, l); 198*57489Storek *hpp = newhashent(p, h); 199*57489Storek if (++ht->ht_used > ht->ht_lim) 200*57489Storek ht_expand(ht); 201*57489Storek return (p); 202*57489Storek } 203*57489Storek 204*57489Storek struct hashtab * 205*57489Storek ht_new() 206*57489Storek { 207*57489Storek register struct hashtab *ht; 208*57489Storek 209*57489Storek ht = emalloc(sizeof *ht); 210*57489Storek ht_init(ht, 8); 211*57489Storek return (ht); 212*57489Storek } 213*57489Storek 214*57489Storek /* 215*57489Storek * Insert and/or replace. 216*57489Storek */ 217*57489Storek int 218*57489Storek ht_insrep(ht, nam, val, replace) 219*57489Storek register struct hashtab *ht; 220*57489Storek register const char *nam; 221*57489Storek void *val; 222*57489Storek int replace; 223*57489Storek { 224*57489Storek register struct hashent *hp, **hpp; 225*57489Storek register u_int h; 226*57489Storek 227*57489Storek h = hash(nam); 228*57489Storek hpp = &ht->ht_tab[h & ht->ht_mask]; 229*57489Storek for (; (hp = *hpp) != NULL; hpp = &hp->h_next) { 230*57489Storek if (hp->h_name == nam) { 231*57489Storek if (replace) 232*57489Storek hp->h_value = val; 233*57489Storek return (1); 234*57489Storek } 235*57489Storek } 236*57489Storek *hpp = hp = newhashent(nam, h); 237*57489Storek hp->h_value = val; 238*57489Storek return (0); 239*57489Storek } 240*57489Storek 241*57489Storek void * 242*57489Storek ht_lookup(ht, nam) 243*57489Storek register struct hashtab *ht; 244*57489Storek register const char *nam; 245*57489Storek { 246*57489Storek register struct hashent *hp, **hpp; 247*57489Storek register u_int h; 248*57489Storek 249*57489Storek h = hash(nam); 250*57489Storek hpp = &ht->ht_tab[h & ht->ht_mask]; 251*57489Storek for (; (hp = *hpp) != NULL; hpp = &hp->h_next) 252*57489Storek if (hp->h_name == nam) 253*57489Storek return (hp->h_value); 254*57489Storek return (NULL); 255*57489Storek } 256