1 /* $OpenBSD: table.c,v 1.15 2012/02/19 07:52:30 otto Exp $ */
4 * dynamic hashed associative table for commands and variables
9 #define INIT_TBLS 8 /* initial table size (power of 2) */
11 static void texpand(struct table
*, int);
12 static int tnamecmp(const void *, const void *);
21 h
= 33*h
+ (unsigned char)(*n
++);
26 ktinit(struct table
*tp
, Area
*ap
, int tsize
)
30 tp
->size
= tp
->nfree
= 0;
36 texpand(struct table
*tp
, int nsize
)
39 struct tbl
*tblp
, **p
;
40 struct tbl
**ntblp
, **otblp
= tp
->tbls
;
43 ntblp
= (struct tbl
**) alloc(sizeofN(struct tbl
*, nsize
), tp
->areap
);
44 for (i
= 0; i
< nsize
; i
++)
47 tp
->nfree
= 7*nsize
/10; /* table can get 70% full */
51 for (i
= 0; i
< osize
; i
++)
52 if ((tblp
= otblp
[i
]) != NULL
) {
53 if ((tblp
->flag
&DEFINED
)) {
54 for (p
= &ntblp
[hash(tblp
->name
) &
55 (tp
->size
-1)]; *p
!= NULL
; p
--)
56 if (p
== ntblp
) /* wrap */
60 } else if (!(tblp
->flag
& FINUSE
)) {
61 afree((void*)tblp
, tp
->areap
);
64 afree((void*)otblp
, tp
->areap
);
71 ktsearch(struct table
*tp
, const char *n
, unsigned int h
)
78 /* search for name in hashed table */
79 for (pp
= &tp
->tbls
[h
& (tp
->size
-1)]; (p
= *pp
) != NULL
; pp
--) {
80 if (*p
->name
== *n
&& strcmp(p
->name
, n
) == 0 &&
83 if (pp
== tp
->tbls
) /* wrap */
94 ktenter(struct table
*tp
, const char *n
, unsigned int h
)
100 texpand(tp
, INIT_TBLS
);
102 /* search for name in hashed table */
103 for (pp
= &tp
->tbls
[h
& (tp
->size
-1)]; (p
= *pp
) != NULL
; pp
--) {
104 if (*p
->name
== *n
&& strcmp(p
->name
, n
) == 0)
105 return p
; /* found */
106 if (pp
== tp
->tbls
) /* wrap */
110 if (tp
->nfree
<= 0) { /* too full */
111 if (tp
->size
<= INT_MAX
/2)
112 texpand(tp
, 2*tp
->size
);
114 internal_errorf(1, "too many vars");
118 /* create new tbl entry */
120 p
= (struct tbl
*) alloc(offsetof(struct tbl
, name
[0]) + len
,
124 p
->areap
= tp
->areap
;
126 p
->u
.array
= (struct tbl
*)0;
127 memcpy(p
->name
, n
, len
);
129 /* enter in tp->tbls */
136 ktdelete(struct tbl
*p
)
142 ktwalk(struct tstate
*ts
, struct table
*tp
)
149 ktnext(struct tstate
*ts
)
151 while (--ts
->left
>= 0) {
152 struct tbl
*p
= *ts
->next
++;
153 if (p
!= NULL
&& (p
->flag
&DEFINED
))
160 tnamecmp(const void *p1
, const void *p2
)
162 char *name1
= (*(struct tbl
**)p1
)->name
;
163 char *name2
= (*(struct tbl
**)p2
)->name
;
164 return strcmp(name1
, name2
);
168 ktsort(struct table
*tp
)
171 struct tbl
**p
, **sp
, **dp
;
173 p
= (struct tbl
**)alloc(sizeofN(struct tbl
*, tp
->size
+1), ATEMP
);
174 sp
= tp
->tbls
; /* source */
176 for (i
= 0; i
< tp
->size
; i
++)
177 if ((*dp
= *sp
++) != NULL
&& (((*dp
)->flag
&DEFINED
) ||
178 ((*dp
)->flag
&ARRAY
)))
181 qsortp((void**)p
, (size_t)i
, tnamecmp
);
186 #ifdef PERF_DEBUG /* performance debugging */
188 void tprintinfo(struct table
*tp
);
191 tprintinfo(struct table
*tp
)
197 int totncmp
= 0, maxncmp
= 0;
201 shellf("table size %d, nfree %d\n", tp
->size
, tp
->nfree
);
202 shellf(" Ncmp name\n");
204 while ((te
= ktnext(&ts
))) {
207 h
= hash(n
= te
->name
);
210 /* taken from ktsearch() and added counter */
211 for (pp
= &tp
->tbls
[h
& (tp
->size
-1)]; (p
= *pp
); pp
--) {
213 if (*p
->name
== *n
&& strcmp(p
->name
, n
) == 0 &&
215 break; /* return p; */
216 if (pp
== tp
->tbls
) /* wrap */
219 shellf(" %4d %s\n", ncmp
, n
);
226 shellf(" %d entries, worst ncmp %d, avg ncmp %d.%02d\n",
229 (totncmp
% nentries
) * 100 / nentries
);
231 #endif /* PERF_DEBUG */