xref: /csrg-svn/usr.sbin/config.new/hash.c (revision 57489)
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