xref: /minix3/bin/ksh/table.c (revision 2718b5688b1550d32bf379153192626eee37752d)
1*2718b568SThomas Cort /*	$NetBSD: table.c,v 1.4 2003/06/23 11:39:04 agc Exp $	*/
2*2718b568SThomas Cort 
3*2718b568SThomas Cort /*
4*2718b568SThomas Cort  * dynamic hashed associative table for commands and variables
5*2718b568SThomas Cort  */
6*2718b568SThomas Cort #include <sys/cdefs.h>
7*2718b568SThomas Cort 
8*2718b568SThomas Cort #ifndef lint
9*2718b568SThomas Cort __RCSID("$NetBSD: table.c,v 1.4 2003/06/23 11:39:04 agc Exp $");
10*2718b568SThomas Cort #endif
11*2718b568SThomas Cort 
12*2718b568SThomas Cort 
13*2718b568SThomas Cort #include "sh.h"
14*2718b568SThomas Cort 
15*2718b568SThomas Cort #define	INIT_TBLS	8	/* initial table size (power of 2) */
16*2718b568SThomas Cort 
17*2718b568SThomas Cort static void     texpand     ARGS((struct table *tp, int nsize));
18*2718b568SThomas Cort static int      tnamecmp    ARGS((void *p1, void *p2));
19*2718b568SThomas Cort 
20*2718b568SThomas Cort 
21*2718b568SThomas Cort unsigned int
hash(n)22*2718b568SThomas Cort hash(n)
23*2718b568SThomas Cort 	register const char * n;
24*2718b568SThomas Cort {
25*2718b568SThomas Cort 	register unsigned int h = 0;
26*2718b568SThomas Cort 
27*2718b568SThomas Cort 	while (*n != '\0')
28*2718b568SThomas Cort 		h = 2*h + *n++;
29*2718b568SThomas Cort 	return h * 32821;	/* scatter bits */
30*2718b568SThomas Cort }
31*2718b568SThomas Cort 
32*2718b568SThomas Cort void
tinit(tp,ap,tsize)33*2718b568SThomas Cort tinit(tp, ap, tsize)
34*2718b568SThomas Cort 	register struct table *tp;
35*2718b568SThomas Cort 	register Area *ap;
36*2718b568SThomas Cort 	int tsize;
37*2718b568SThomas Cort {
38*2718b568SThomas Cort 	tp->areap = ap;
39*2718b568SThomas Cort 	tp->tbls = NULL;
40*2718b568SThomas Cort 	tp->size = tp->nfree = 0;
41*2718b568SThomas Cort 	if (tsize)
42*2718b568SThomas Cort 		texpand(tp, tsize);
43*2718b568SThomas Cort }
44*2718b568SThomas Cort 
45*2718b568SThomas Cort static void
texpand(tp,nsize)46*2718b568SThomas Cort texpand(tp, nsize)
47*2718b568SThomas Cort 	register struct table *tp;
48*2718b568SThomas Cort 	int nsize;
49*2718b568SThomas Cort {
50*2718b568SThomas Cort 	register int i;
51*2718b568SThomas Cort 	register struct tbl *tblp, **p;
52*2718b568SThomas Cort 	register struct tbl **ntblp, **otblp = tp->tbls;
53*2718b568SThomas Cort 	int osize = tp->size;
54*2718b568SThomas Cort 
55*2718b568SThomas Cort 	ntblp = (struct tbl**) alloc(sizeofN(struct tbl *, nsize), tp->areap);
56*2718b568SThomas Cort 	for (i = 0; i < nsize; i++)
57*2718b568SThomas Cort 		ntblp[i] = NULL;
58*2718b568SThomas Cort 	tp->size = nsize;
59*2718b568SThomas Cort 	tp->nfree = 8*nsize/10;	/* table can get 80% full */
60*2718b568SThomas Cort 	tp->tbls = ntblp;
61*2718b568SThomas Cort 	if (otblp == NULL)
62*2718b568SThomas Cort 		return;
63*2718b568SThomas Cort 	for (i = 0; i < osize; i++) {
64*2718b568SThomas Cort 		if ((tblp = otblp[i]) != NULL) {
65*2718b568SThomas Cort 			if ((tblp->flag&DEFINED)) {
66*2718b568SThomas Cort 				for (p = &ntblp[hash(tblp->name)
67*2718b568SThomas Cort 					  & (tp->size-1)];
68*2718b568SThomas Cort 				     *p != NULL; p--)
69*2718b568SThomas Cort 					if (p == ntblp) /* wrap */
70*2718b568SThomas Cort 						p += tp->size;
71*2718b568SThomas Cort 				*p = tblp;
72*2718b568SThomas Cort 				tp->nfree--;
73*2718b568SThomas Cort 			} else if (!(tblp->flag & FINUSE)) {
74*2718b568SThomas Cort 				afree((void*)tblp, tp->areap);
75*2718b568SThomas Cort 			}
76*2718b568SThomas Cort 		}
77*2718b568SThomas Cort 	}
78*2718b568SThomas Cort 	afree((void*)otblp, tp->areap);
79*2718b568SThomas Cort }
80*2718b568SThomas Cort 
81*2718b568SThomas Cort struct tbl *
tsearch(tp,n,h)82*2718b568SThomas Cort tsearch(tp, n, h)
83*2718b568SThomas Cort 	register struct table *tp;	/* table */
84*2718b568SThomas Cort 	register const char *n;		/* name to enter */
85*2718b568SThomas Cort 	unsigned int h;			/* hash(n) */
86*2718b568SThomas Cort {
87*2718b568SThomas Cort 	register struct tbl **pp, *p;
88*2718b568SThomas Cort 
89*2718b568SThomas Cort 	if (tp->size == 0)
90*2718b568SThomas Cort 		return NULL;
91*2718b568SThomas Cort 
92*2718b568SThomas Cort 	/* search for name in hashed table */
93*2718b568SThomas Cort 	for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) {
94*2718b568SThomas Cort 		if (*p->name == *n && strcmp(p->name, n) == 0
95*2718b568SThomas Cort 		    && (p->flag&DEFINED))
96*2718b568SThomas Cort 			return p;
97*2718b568SThomas Cort 		if (pp == tp->tbls) /* wrap */
98*2718b568SThomas Cort 			pp += tp->size;
99*2718b568SThomas Cort 	}
100*2718b568SThomas Cort 
101*2718b568SThomas Cort 	return NULL;
102*2718b568SThomas Cort }
103*2718b568SThomas Cort 
104*2718b568SThomas Cort struct tbl *
tenter(tp,n,h)105*2718b568SThomas Cort tenter(tp, n, h)
106*2718b568SThomas Cort 	register struct table *tp;	/* table */
107*2718b568SThomas Cort 	register const char *n;		/* name to enter */
108*2718b568SThomas Cort 	unsigned int h;			/* hash(n) */
109*2718b568SThomas Cort {
110*2718b568SThomas Cort 	register struct tbl **pp, *p;
111*2718b568SThomas Cort 	register int len;
112*2718b568SThomas Cort 
113*2718b568SThomas Cort 	if (tp->size == 0)
114*2718b568SThomas Cort 		texpand(tp, INIT_TBLS);
115*2718b568SThomas Cort   Search:
116*2718b568SThomas Cort 	/* search for name in hashed table */
117*2718b568SThomas Cort 	for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) {
118*2718b568SThomas Cort 		if (*p->name == *n && strcmp(p->name, n) == 0)
119*2718b568SThomas Cort 			return p; 	/* found */
120*2718b568SThomas Cort 		if (pp == tp->tbls) /* wrap */
121*2718b568SThomas Cort 			pp += tp->size;
122*2718b568SThomas Cort 	}
123*2718b568SThomas Cort 
124*2718b568SThomas Cort 	if (tp->nfree <= 0) {	/* too full */
125*2718b568SThomas Cort 		texpand(tp, 2*tp->size);
126*2718b568SThomas Cort 		goto Search;
127*2718b568SThomas Cort 	}
128*2718b568SThomas Cort 
129*2718b568SThomas Cort 	/* create new tbl entry */
130*2718b568SThomas Cort 	len = strlen(n) + 1;
131*2718b568SThomas Cort 	p = (struct tbl *) alloc(offsetof(struct tbl, name[0]) + len,
132*2718b568SThomas Cort 				 tp->areap);
133*2718b568SThomas Cort 	p->flag = 0;
134*2718b568SThomas Cort 	p->type = 0;
135*2718b568SThomas Cort 	p->areap = tp->areap;
136*2718b568SThomas Cort 	p->u2.field = 0;
137*2718b568SThomas Cort 	p->u.array = (struct tbl *)0;
138*2718b568SThomas Cort 	memcpy(p->name, n, len);
139*2718b568SThomas Cort 
140*2718b568SThomas Cort 	/* enter in tp->tbls */
141*2718b568SThomas Cort 	tp->nfree--;
142*2718b568SThomas Cort 	*pp = p;
143*2718b568SThomas Cort 	return p;
144*2718b568SThomas Cort }
145*2718b568SThomas Cort 
146*2718b568SThomas Cort void
tdelete(p)147*2718b568SThomas Cort tdelete(p)
148*2718b568SThomas Cort 	register struct tbl *p;
149*2718b568SThomas Cort {
150*2718b568SThomas Cort 	p->flag = 0;
151*2718b568SThomas Cort }
152*2718b568SThomas Cort 
153*2718b568SThomas Cort void
twalk(ts,tp)154*2718b568SThomas Cort twalk(ts, tp)
155*2718b568SThomas Cort 	struct tstate *ts;
156*2718b568SThomas Cort 	struct table *tp;
157*2718b568SThomas Cort {
158*2718b568SThomas Cort 	ts->left = tp->size;
159*2718b568SThomas Cort 	ts->next = tp->tbls;
160*2718b568SThomas Cort }
161*2718b568SThomas Cort 
162*2718b568SThomas Cort struct tbl *
tnext(ts)163*2718b568SThomas Cort tnext(ts)
164*2718b568SThomas Cort 	struct tstate *ts;
165*2718b568SThomas Cort {
166*2718b568SThomas Cort 	while (--ts->left >= 0) {
167*2718b568SThomas Cort 		struct tbl *p = *ts->next++;
168*2718b568SThomas Cort 		if (p != NULL && (p->flag&DEFINED))
169*2718b568SThomas Cort 			return p;
170*2718b568SThomas Cort 	}
171*2718b568SThomas Cort 	return NULL;
172*2718b568SThomas Cort }
173*2718b568SThomas Cort 
174*2718b568SThomas Cort static int
tnamecmp(p1,p2)175*2718b568SThomas Cort tnamecmp(p1, p2)
176*2718b568SThomas Cort 	void *p1, *p2;
177*2718b568SThomas Cort {
178*2718b568SThomas Cort 	return strcmp(((struct tbl *)p1)->name, ((struct tbl *)p2)->name);
179*2718b568SThomas Cort }
180*2718b568SThomas Cort 
181*2718b568SThomas Cort struct tbl **
tsort(tp)182*2718b568SThomas Cort tsort(tp)
183*2718b568SThomas Cort 	register struct table *tp;
184*2718b568SThomas Cort {
185*2718b568SThomas Cort 	register int i;
186*2718b568SThomas Cort 	register struct tbl **p, **sp, **dp;
187*2718b568SThomas Cort 
188*2718b568SThomas Cort 	p = (struct tbl **)alloc(sizeofN(struct tbl *, tp->size+1), ATEMP);
189*2718b568SThomas Cort 	sp = tp->tbls;		/* source */
190*2718b568SThomas Cort 	dp = p;			/* dest */
191*2718b568SThomas Cort 	for (i = 0; i < tp->size; i++)
192*2718b568SThomas Cort 		if ((*dp = *sp++) != NULL && (((*dp)->flag&DEFINED) ||
193*2718b568SThomas Cort 					      ((*dp)->flag&ARRAY)))
194*2718b568SThomas Cort 			dp++;
195*2718b568SThomas Cort 	i = dp - p;
196*2718b568SThomas Cort 	qsortp((void**)p, (size_t)i, tnamecmp);
197*2718b568SThomas Cort 	p[i] = NULL;
198*2718b568SThomas Cort 	return p;
199*2718b568SThomas Cort }
200*2718b568SThomas Cort 
201*2718b568SThomas Cort #ifdef PERF_DEBUG /* performance debugging */
202*2718b568SThomas Cort 
203*2718b568SThomas Cort void tprintinfo ARGS((struct table *tp));
204*2718b568SThomas Cort 
205*2718b568SThomas Cort void
tprintinfo(tp)206*2718b568SThomas Cort tprintinfo(tp)
207*2718b568SThomas Cort 	struct table *tp;
208*2718b568SThomas Cort {
209*2718b568SThomas Cort 	struct tbl *te;
210*2718b568SThomas Cort 	char *n;
211*2718b568SThomas Cort 	unsigned int h;
212*2718b568SThomas Cort 	int ncmp;
213*2718b568SThomas Cort 	int totncmp = 0, maxncmp = 0;
214*2718b568SThomas Cort 	int nentries = 0;
215*2718b568SThomas Cort 	struct tstate ts;
216*2718b568SThomas Cort 
217*2718b568SThomas Cort 	shellf("table size %d, nfree %d\n", tp->size, tp->nfree);
218*2718b568SThomas Cort 	shellf("    Ncmp name\n");
219*2718b568SThomas Cort 	twalk(&ts, tp);
220*2718b568SThomas Cort 	while ((te = tnext(&ts))) {
221*2718b568SThomas Cort 		register struct tbl **pp, *p;
222*2718b568SThomas Cort 
223*2718b568SThomas Cort 		h = hash(n = te->name);
224*2718b568SThomas Cort 		ncmp = 0;
225*2718b568SThomas Cort 
226*2718b568SThomas Cort 		/* taken from tsearch() and added counter */
227*2718b568SThomas Cort 		for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp); pp--) {
228*2718b568SThomas Cort 			ncmp++;
229*2718b568SThomas Cort 			if (*p->name == *n && strcmp(p->name, n) == 0
230*2718b568SThomas Cort 			    && (p->flag&DEFINED))
231*2718b568SThomas Cort 				break; /* return p; */
232*2718b568SThomas Cort 			if (pp == tp->tbls) /* wrap */
233*2718b568SThomas Cort 				pp += tp->size;
234*2718b568SThomas Cort 		}
235*2718b568SThomas Cort 		shellf("    %4d %s\n", ncmp, n);
236*2718b568SThomas Cort 		totncmp += ncmp;
237*2718b568SThomas Cort 		nentries++;
238*2718b568SThomas Cort 		if (ncmp > maxncmp)
239*2718b568SThomas Cort 			maxncmp = ncmp;
240*2718b568SThomas Cort 	}
241*2718b568SThomas Cort 	if (nentries)
242*2718b568SThomas Cort 		shellf("  %d entries, worst ncmp %d, avg ncmp %d.%02d\n",
243*2718b568SThomas Cort 			nentries, maxncmp,
244*2718b568SThomas Cort 			totncmp / nentries,
245*2718b568SThomas Cort 			(totncmp % nentries) * 100 / nentries);
246*2718b568SThomas Cort }
247*2718b568SThomas Cort #endif /* PERF_DEBUG */
248