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