• rework hash table interna to avoid gcc-4.1 on Debian etch bug
• also improve behaviour with _a lot_ (>2²⁸) entries • while here, improve comments and whitespace
This commit is contained in:
90
main.c
90
main.c
@ -33,7 +33,7 @@
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.192 2011/06/04 16:42:30 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.193 2011/06/05 19:58:18 tg Exp $");
|
||||
|
||||
extern char **environ;
|
||||
|
||||
@ -206,8 +206,9 @@ main(int argc, const char *argv[])
|
||||
ccp = empty_argv[0];
|
||||
|
||||
/* define built-in commands and see if we were called as one */
|
||||
ktinit(&builtins, APERM,
|
||||
/* must be 80% of 2^n (currently 44 builtins) */ 64);
|
||||
ktinit(APERM, &builtins,
|
||||
/* currently 50 builtins -> 80% of 64 (2^6) */
|
||||
6);
|
||||
for (i = 0; mkshbuiltins[i].name != NULL; i++)
|
||||
if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
|
||||
mkshbuiltins[i].func)))
|
||||
@ -235,10 +236,10 @@ main(int argc, const char *argv[])
|
||||
coproc_init();
|
||||
|
||||
/* set up variable and command dictionaries */
|
||||
ktinit(&taliases, APERM, 0);
|
||||
ktinit(&aliases, APERM, 0);
|
||||
ktinit(APERM, &taliases, 0);
|
||||
ktinit(APERM, &aliases, 0);
|
||||
#ifndef MKSH_NOPWNAM
|
||||
ktinit(&homedirs, APERM, 0);
|
||||
ktinit(APERM, &homedirs, 0);
|
||||
#endif
|
||||
|
||||
/* define shell keywords */
|
||||
@ -1442,53 +1443,48 @@ maketemp(Area *ap, Temp_type type, struct temp **tlist)
|
||||
* but with a slightly tweaked implementation written from scratch.
|
||||
*/
|
||||
|
||||
#define INIT_TBLS 8 /* initial table size (power of 2) */
|
||||
#define INIT_TBLSHIFT 3 /* initial table shift (2^3 = 8) */
|
||||
#define PERTURB_SHIFT 5 /* see Python 2.5.4 Objects/dictobject.c */
|
||||
|
||||
static void texpand(struct table *, size_t);
|
||||
static void tgrow(struct table *);
|
||||
static int tnamecmp(const void *, const void *);
|
||||
static struct tbl *ktscan(struct table *, const char *, uint32_t,
|
||||
struct tbl ***);
|
||||
|
||||
static void
|
||||
texpand(struct table *tp, size_t nsize)
|
||||
tgrow(struct table *tp)
|
||||
{
|
||||
size_t i, j, osize = tp->size, perturb;
|
||||
size_t i, j, osize, mask, perturb;
|
||||
struct tbl *tblp, **pp;
|
||||
struct tbl **ntblp, **otblp = tp->tbls;
|
||||
|
||||
i = 1;
|
||||
i <<= 30;
|
||||
if (nsize > i)
|
||||
if (tp->tshift > 29)
|
||||
internal_errorf("hash table size limit reached");
|
||||
|
||||
ntblp = alloc2(nsize, sizeof(struct tbl *), tp->areap);
|
||||
memset(ntblp, 0, nsize * sizeof(struct tbl *));
|
||||
tp->size = nsize;
|
||||
if (nsize == i) {
|
||||
/* cannot be grown any more, use a fixed value */
|
||||
tp->nfree = i - 65536;
|
||||
} else /* (nsize < 2^30) */ {
|
||||
/* table can get 80% full */
|
||||
tp->nfree = (nsize * 4) / 5;
|
||||
}
|
||||
/* calculate old size, new shift and new size */
|
||||
osize = 1 << (tp->tshift++);
|
||||
i = osize << 1;
|
||||
|
||||
ntblp = alloc2(i, sizeof(struct tbl *), tp->areap);
|
||||
/* multiplication cannot overflow: alloc2 checked that */
|
||||
memset(ntblp, 0, i * sizeof(struct tbl *));
|
||||
|
||||
/* table can get 80% full except when reaching its limit */
|
||||
tp->nfree = (tp->tshift == 30) ? 0x3FFF0000UL : ((i * 4) / 5);
|
||||
tp->tbls = ntblp;
|
||||
if (otblp == NULL)
|
||||
return;
|
||||
|
||||
/* from here on nsize := mask */
|
||||
nsize--;
|
||||
mask = i - 1;
|
||||
for (i = 0; i < osize; i++)
|
||||
if ((tblp = otblp[i]) != NULL) {
|
||||
if ((tblp->flag & DEFINED)) {
|
||||
/* search for free hash table slot */
|
||||
j = (perturb = tblp->ua.hval) & nsize;
|
||||
j = (perturb = tblp->ua.hval) & mask;
|
||||
goto find_first_empty_slot;
|
||||
find_next_empty_slot:
|
||||
j = (j << 2) + j + perturb + 1;
|
||||
perturb >>= PERTURB_SHIFT;
|
||||
find_first_empty_slot:
|
||||
pp = &ntblp[j & nsize];
|
||||
pp = &ntblp[j & mask];
|
||||
if (*pp != NULL)
|
||||
goto find_next_empty_slot;
|
||||
/* found an empty hash table slot */
|
||||
@ -1502,23 +1498,23 @@ texpand(struct table *tp, size_t nsize)
|
||||
}
|
||||
|
||||
void
|
||||
ktinit(struct table *tp, Area *ap, size_t tsize)
|
||||
ktinit(Area *ap, struct table *tp, uint8_t initshift)
|
||||
{
|
||||
tp->areap = ap;
|
||||
tp->tbls = NULL;
|
||||
tp->size = tp->nfree = 0;
|
||||
if (tsize)
|
||||
texpand(tp, tsize);
|
||||
tp->tshift = ((initshift > INIT_TBLSHIFT) ?
|
||||
initshift : INIT_TBLSHIFT) - 1;
|
||||
tgrow(tp);
|
||||
}
|
||||
|
||||
/* table, name (key) to search for, hash(name), rv pointer to tbl ptr */
|
||||
static struct tbl *
|
||||
struct tbl *
|
||||
ktscan(struct table *tp, const char *name, uint32_t h, struct tbl ***ppp)
|
||||
{
|
||||
size_t j, perturb, mask;
|
||||
struct tbl **pp, *p;
|
||||
|
||||
mask = tp->size - 1;
|
||||
mask = (1 << (tp->tshift)) - 1;
|
||||
/* search for hash table slot matching name */
|
||||
j = (perturb = h) & mask;
|
||||
goto find_first_slot;
|
||||
@ -1536,13 +1532,6 @@ ktscan(struct table *tp, const char *name, uint32_t h, struct tbl ***ppp)
|
||||
return (p);
|
||||
}
|
||||
|
||||
/* table, name (key) to search for, hash(n) */
|
||||
struct tbl *
|
||||
ktsearch(struct table *tp, const char *n, uint32_t h)
|
||||
{
|
||||
return (tp->size ? ktscan(tp, n, h, NULL) : NULL);
|
||||
}
|
||||
|
||||
/* table, name (key) to enter, hash(n) */
|
||||
struct tbl *
|
||||
ktenter(struct table *tp, const char *n, uint32_t h)
|
||||
@ -1550,15 +1539,13 @@ ktenter(struct table *tp, const char *n, uint32_t h)
|
||||
struct tbl **pp, *p;
|
||||
size_t len;
|
||||
|
||||
if (tp->size == 0)
|
||||
texpand(tp, INIT_TBLS);
|
||||
Search:
|
||||
if ((p = ktscan(tp, n, h, &pp)))
|
||||
return (p);
|
||||
|
||||
if (tp->nfree == 0) {
|
||||
/* too full */
|
||||
texpand(tp, 2 * tp->size);
|
||||
tgrow(tp);
|
||||
goto Search;
|
||||
}
|
||||
|
||||
@ -1583,7 +1570,7 @@ ktenter(struct table *tp, const char *n, uint32_t h)
|
||||
void
|
||||
ktwalk(struct tstate *ts, struct table *tp)
|
||||
{
|
||||
ts->left = tp->size;
|
||||
ts->left = 1 << (tp->tshift);
|
||||
ts->next = tp->tbls;
|
||||
}
|
||||
|
||||
@ -1613,16 +1600,19 @@ ktsort(struct table *tp)
|
||||
size_t i;
|
||||
struct tbl **p, **sp, **dp;
|
||||
|
||||
/* tp->size + 1 will not overflow */
|
||||
p = alloc2(tp->size + 1, sizeof(struct tbl *), ATEMP);
|
||||
/*
|
||||
* since the table is never entirely full, no need to reserve
|
||||
* additional space for the trailing NULL appended below
|
||||
*/
|
||||
i = 1 << (tp->tshift);
|
||||
p = alloc2(i, sizeof(struct tbl *), ATEMP);
|
||||
sp = tp->tbls; /* source */
|
||||
dp = p; /* dest */
|
||||
i = (size_t)tp->size;
|
||||
while (i--)
|
||||
if ((*dp = *sp++) != NULL && (((*dp)->flag & DEFINED) ||
|
||||
((*dp)->flag & ARRAY)))
|
||||
dp++;
|
||||
qsort(p, (i = dp - p), sizeof(void *), tnamecmp);
|
||||
qsort(p, (i = dp - p), sizeof(struct tbl *), tnamecmp);
|
||||
p[i] = NULL;
|
||||
return (p);
|
||||
}
|
||||
|
Reference in New Issue
Block a user