1 /* $NetBSD: table.c,v 1.4 2003/06/23 11:39:04 agc Exp $ */
4 * dynamic hashed associative table for commands and variables
9 __RCSID("$NetBSD: table.c,v 1.4 2003/06/23 11:39:04 agc Exp $");
15 #define INIT_TBLS 8 /* initial table size (power of 2) */
17 static void texpand
ARGS((struct table
*tp
, int nsize
));
18 static int tnamecmp
ARGS((void *p1
, void *p2
));
23 register const char * n
;
25 register unsigned int h
= 0;
29 return h
* 32821; /* scatter bits */
34 register struct table
*tp
;
40 tp
->size
= tp
->nfree
= 0;
47 register struct table
*tp
;
51 register struct tbl
*tblp
, **p
;
52 register struct tbl
**ntblp
, **otblp
= tp
->tbls
;
55 ntblp
= (struct tbl
**) alloc(sizeofN(struct tbl
*, nsize
), tp
->areap
);
56 for (i
= 0; i
< nsize
; i
++)
59 tp
->nfree
= 8*nsize
/10; /* table can get 80% full */
63 for (i
= 0; i
< osize
; i
++) {
64 if ((tblp
= otblp
[i
]) != NULL
) {
65 if ((tblp
->flag
&DEFINED
)) {
66 for (p
= &ntblp
[hash(tblp
->name
)
69 if (p
== ntblp
) /* wrap */
73 } else if (!(tblp
->flag
& FINUSE
)) {
74 afree((void*)tblp
, tp
->areap
);
78 afree((void*)otblp
, tp
->areap
);
83 register struct table
*tp
; /* table */
84 register const char *n
; /* name to enter */
85 unsigned int h
; /* hash(n) */
87 register struct tbl
**pp
, *p
;
92 /* search for name in hashed table */
93 for (pp
= &tp
->tbls
[h
& (tp
->size
-1)]; (p
= *pp
) != NULL
; pp
--) {
94 if (*p
->name
== *n
&& strcmp(p
->name
, n
) == 0
97 if (pp
== tp
->tbls
) /* wrap */
106 register struct table
*tp
; /* table */
107 register const char *n
; /* name to enter */
108 unsigned int h
; /* hash(n) */
110 register struct tbl
**pp
, *p
;
114 texpand(tp
, INIT_TBLS
);
116 /* search for name in hashed table */
117 for (pp
= &tp
->tbls
[h
& (tp
->size
-1)]; (p
= *pp
) != NULL
; pp
--) {
118 if (*p
->name
== *n
&& strcmp(p
->name
, n
) == 0)
119 return p
; /* found */
120 if (pp
== tp
->tbls
) /* wrap */
124 if (tp
->nfree
<= 0) { /* too full */
125 texpand(tp
, 2*tp
->size
);
129 /* create new tbl entry */
131 p
= (struct tbl
*) alloc(offsetof(struct tbl
, name
[0]) + len
,
135 p
->areap
= tp
->areap
;
137 p
->u
.array
= (struct tbl
*)0;
138 memcpy(p
->name
, n
, len
);
140 /* enter in tp->tbls */
148 register struct tbl
*p
;
166 while (--ts
->left
>= 0) {
167 struct tbl
*p
= *ts
->next
++;
168 if (p
!= NULL
&& (p
->flag
&DEFINED
))
178 return strcmp(((struct tbl
*)p1
)->name
, ((struct tbl
*)p2
)->name
);
183 register struct table
*tp
;
186 register struct tbl
**p
, **sp
, **dp
;
188 p
= (struct tbl
**)alloc(sizeofN(struct tbl
*, tp
->size
+1), ATEMP
);
189 sp
= tp
->tbls
; /* source */
191 for (i
= 0; i
< tp
->size
; i
++)
192 if ((*dp
= *sp
++) != NULL
&& (((*dp
)->flag
&DEFINED
) ||
193 ((*dp
)->flag
&ARRAY
)))
196 qsortp((void**)p
, (size_t)i
, tnamecmp
);
201 #ifdef PERF_DEBUG /* performance debugging */
203 void tprintinfo
ARGS((struct table
*tp
));
213 int totncmp
= 0, maxncmp
= 0;
217 shellf("table size %d, nfree %d\n", tp
->size
, tp
->nfree
);
218 shellf(" Ncmp name\n");
220 while ((te
= tnext(&ts
))) {
221 register struct tbl
**pp
, *p
;
223 h
= hash(n
= te
->name
);
226 /* taken from tsearch() and added counter */
227 for (pp
= &tp
->tbls
[h
& (tp
->size
-1)]; (p
= *pp
); pp
--) {
229 if (*p
->name
== *n
&& strcmp(p
->name
, n
) == 0
230 && (p
->flag
&DEFINED
))
231 break; /* return p; */
232 if (pp
== tp
->tbls
) /* wrap */
235 shellf(" %4d %s\n", ncmp
, n
);
242 shellf(" %d entries, worst ncmp %d, avg ncmp %d.%02d\n",
245 (totncmp
% nentries
) * 100 / nentries
);
247 #endif /* PERF_DEBUG */