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