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