1 /* $OpenBSD: table.c,v 1.25 2018/01/16 22:52:32 jca Exp $ */
4 * dynamic hashed associative table for commands and variables
13 #define INIT_TBLS 8 /* initial table size (power of 2) */
15 struct table taliases
; /* tracked aliases */
16 struct table builtins
; /* built-in commands */
17 struct table aliases
; /* aliases */
18 struct table keywords
; /* keywords */
19 struct table homedirs
; /* homedir() cache */
21 char *search_path
; /* copy of either PATH or def_path */
22 const char *def_path
; /* path to use if PATH not set */
23 char *tmpdir
; /* TMPDIR value */
25 int cur_prompt
; /* PS1 or PS2 */
26 int current_lineno
; /* LINENO value */
28 static void texpand(struct table
*, int);
29 static int tnamecmp(const void *, const void *);
38 h
= 33*h
+ (unsigned char)(*n
++);
43 ktinit(struct table
*tp
, Area
*ap
, int tsize
)
47 tp
->size
= tp
->nfree
= 0;
53 texpand(struct table
*tp
, int nsize
)
56 struct tbl
*tblp
, **p
;
57 struct tbl
**ntblp
, **otblp
= tp
->tbls
;
60 ntblp
= areallocarray(NULL
, nsize
, sizeof(struct tbl
*), tp
->areap
);
61 for (i
= 0; i
< nsize
; i
++)
64 tp
->nfree
= 7*nsize
/10; /* table can get 70% full */
68 for (i
= 0; i
< osize
; i
++)
69 if ((tblp
= otblp
[i
]) != NULL
) {
70 if ((tblp
->flag
&DEFINED
)) {
71 for (p
= &ntblp
[hash(tblp
->name
) &
72 (tp
->size
-1)]; *p
!= NULL
; p
--)
73 if (p
== ntblp
) /* wrap */
77 } else if (!(tblp
->flag
& FINUSE
)) {
78 afree(tblp
, tp
->areap
);
81 afree(otblp
, tp
->areap
);
88 ktsearch(struct table
*tp
, const char *n
, unsigned int h
)
95 /* search for name in hashed table */
96 for (pp
= &tp
->tbls
[h
& (tp
->size
-1)]; (p
= *pp
) != NULL
; pp
--) {
97 if (*p
->name
== *n
&& strcmp(p
->name
, n
) == 0 &&
100 if (pp
== tp
->tbls
) /* wrap */
111 ktenter(struct table
*tp
, const char *n
, unsigned int h
)
117 texpand(tp
, INIT_TBLS
);
119 /* search for name in hashed table */
120 for (pp
= &tp
->tbls
[h
& (tp
->size
-1)]; (p
= *pp
) != NULL
; pp
--) {
121 if (*p
->name
== *n
&& strcmp(p
->name
, n
) == 0)
122 return p
; /* found */
123 if (pp
== tp
->tbls
) /* wrap */
127 if (tp
->nfree
<= 0) { /* too full */
128 if (tp
->size
<= INT_MAX
/2)
129 texpand(tp
, 2*tp
->size
);
131 internal_errorf("too many vars");
135 /* create new tbl entry */
137 p
= alloc(offsetof(struct tbl
, name
[0]) + len
,
141 p
->areap
= tp
->areap
;
144 memcpy(p
->name
, n
, len
);
146 /* enter in tp->tbls */
153 ktdelete(struct tbl
*p
)
159 ktwalk(struct tstate
*ts
, struct table
*tp
)
166 ktnext(struct tstate
*ts
)
168 while (--ts
->left
>= 0) {
169 struct tbl
*p
= *ts
->next
++;
170 if (p
!= NULL
&& (p
->flag
&DEFINED
))
177 tnamecmp(const void *p1
, const void *p2
)
179 char *name1
= (*(struct tbl
**)p1
)->name
;
180 char *name2
= (*(struct tbl
**)p2
)->name
;
181 return strcmp(name1
, name2
);
185 ktsort(struct table
*tp
)
188 struct tbl
**p
, **sp
, **dp
;
190 p
= areallocarray(NULL
, tp
->size
+ 1,
191 sizeof(struct tbl
*), ATEMP
);
192 sp
= tp
->tbls
; /* source */
194 for (i
= 0; i
< tp
->size
; i
++)
195 if ((*dp
= *sp
++) != NULL
&& (((*dp
)->flag
&DEFINED
) ||
196 ((*dp
)->flag
&ARRAY
)))
199 qsortp((void**)p
, (size_t)i
, tnamecmp
);
204 #ifdef PERF_DEBUG /* performance debugging */
206 void tprintinfo(struct table
*tp
);
209 tprintinfo(struct table
*tp
)
215 int totncmp
= 0, maxncmp
= 0;
219 shellf("table size %d, nfree %d\n", tp
->size
, tp
->nfree
);
220 shellf(" Ncmp name\n");
222 while ((te
= ktnext(&ts
))) {
225 h
= hash(n
= te
->name
);
228 /* taken from ktsearch() and added counter */
229 for (pp
= &tp
->tbls
[h
& (tp
->size
-1)]; (p
= *pp
); pp
--) {
231 if (*p
->name
== *n
&& strcmp(p
->name
, n
) == 0 &&
233 break; /* return p; */
234 if (pp
== tp
->tbls
) /* wrap */
237 shellf(" %4d %s\n", ncmp
, n
);
244 shellf(" %d entries, worst ncmp %d, avg ncmp %d.%02d\n",
247 (totncmp
% nentries
) * 100 / nentries
);
249 #endif /* PERF_DEBUG */