/* - miss - handle a cache miss ^ static struct sset *miss(struct vars *, struct dfa *, struct sset *, ^ pcolor, chr *, chr *); */ static struct sset * /* NULL if goes to empty set */ miss( struct vars *v, /* used only for debug flags */ struct dfa *d, struct sset *css, pcolor co, chr *cp, /* next chr */ chr *start) /* where the attempt got started */ { struct cnfa *cnfa = d->cnfa; int i; unsigned h; struct carc *ca; struct sset *p; int ispost; int noprogress; int gotstate; int dolacons; int sawlacons; /* * For convenience, we can be called even if it might not be a miss. */ if (css->outs[co] != NULL) { FDEBUG(("hit\n")); return css->outs[co]; } FDEBUG(("miss\n")); /* * First, what set of states would we end up in? */ for (i = 0; i < d->wordsper; i++) { d->work[i] = 0; } ispost = 0; noprogress = 1; gotstate = 0; for (i = 0; i < d->nstates; i++) { if (ISBSET(css->states, i)) { for (ca = cnfa->states[i]+1; ca->co != COLORLESS; ca++) { if (ca->co == co) { BSET(d->work, ca->to); gotstate = 1; if (ca->to == cnfa->post) { ispost = 1; } if (!cnfa->states[ca->to]->co) { noprogress = 0; } FDEBUG(("%d -> %d\n", i, ca->to)); } } } } dolacons = (gotstate) ? (cnfa->flags&HASLACONS) : 0; sawlacons = 0; while (dolacons) { /* transitive closure */ dolacons = 0; for (i = 0; i < d->nstates; i++) { if (ISBSET(d->work, i)) { for (ca = cnfa->states[i]+1; ca->co != COLORLESS; ca++) { if (ca->co <= cnfa->ncolors) { continue; /* NOTE CONTINUE */ } sawlacons = 1; if (ISBSET(d->work, ca->to)) { continue; /* NOTE CONTINUE */ } if (!lacon(v, cnfa, cp, ca->co)) { continue; /* NOTE CONTINUE */ } BSET(d->work, ca->to); dolacons = 1; if (ca->to == cnfa->post) { ispost = 1; } if (!cnfa->states[ca->to]->co) { noprogress = 0; } FDEBUG(("%d :> %d\n", i, ca->to)); } } } } if (!gotstate) { return NULL; } h = HASH(d->work, d->wordsper); /* * Next, is that in the cache? */ for (p = d->ssets, i = d->nssused; i > 0; p++, i--) { if (HIT(h, d->work, p, d->wordsper)) { FDEBUG(("cached c%d\n", p - d->ssets)); break; /* NOTE BREAK OUT */ } } if (i == 0) { /* nope, need a new cache entry */ p = getvacant(v, d, cp, start); assert(p != css); for (i = 0; i < d->wordsper; i++) { p->states[i] = d->work[i]; } p->hash = h; p->flags = (ispost) ? POSTSTATE : 0; if (noprogress) { p->flags |= NOPROGRESS; } /* * lastseen to be dealt with by caller */ } if (!sawlacons) { /* lookahead conds. always cache miss */ FDEBUG(("c%d[%d]->c%d\n", css - d->ssets, co, p - d->ssets)); css->outs[co] = p; css->inchain[co] = p->ins; p->ins.ss = css; p->ins.co = (color)co; } return p; }
abb::void_block operator()(int elem) { ++this->counter; REQUIRE_EQUAL(this->counter, elem); HIT(); return abb::success(); }
/* * miss - handle a stateset cache miss * * css is the current stateset, co is the color of the current input character, * cp points to the character after that (which is where we may need to test * LACONs). start does not affect matching behavior but is needed for pickss' * heuristics about which stateset cache entry to replace. * * Ordinarily, returns the address of the next stateset (the one that is * valid after consuming the input character). Returns NULL if no valid * NFA states remain, ie we have a certain match failure. * Internal errors also return NULL, with v->err set. */ static struct sset * miss(struct vars * v, struct dfa * d, struct sset * css, pcolor co, chr *cp, /* next chr */ chr *start) /* where the attempt got started */ { struct cnfa *cnfa = d->cnfa; int i; unsigned h; struct carc *ca; struct sset *p; int ispost; int noprogress; int gotstate; int dolacons; int sawlacons; /* for convenience, we can be called even if it might not be a miss */ if (css->outs[co] != NULL) { FDEBUG(("hit\n")); return css->outs[co]; } FDEBUG(("miss\n")); /* * Checking for operation cancel in the inner text search loop seems * unduly expensive. As a compromise, check during cache misses. */ if (CANCEL_REQUESTED(v->re)) { ERR(REG_CANCEL); return NULL; } /* * What set of states would we end up in after consuming the co character? * We first consider PLAIN arcs that consume the character, and then look * to see what LACON arcs could be traversed after consuming it. */ for (i = 0; i < d->wordsper; i++) d->work[i] = 0; /* build new stateset bitmap in d->work */ ispost = 0; noprogress = 1; gotstate = 0; for (i = 0; i < d->nstates; i++) if (ISBSET(css->states, i)) for (ca = cnfa->states[i]; ca->co != COLORLESS; ca++) if (ca->co == co) { BSET(d->work, ca->to); gotstate = 1; if (ca->to == cnfa->post) ispost = 1; if (!(cnfa->stflags[ca->to] & CNFA_NOPROGRESS)) noprogress = 0; FDEBUG(("%d -> %d\n", i, ca->to)); } if (!gotstate) return NULL; /* character cannot reach any new state */ dolacons = (cnfa->flags & HASLACONS); sawlacons = 0; /* outer loop handles transitive closure of reachable-by-LACON states */ while (dolacons) { dolacons = 0; for (i = 0; i < d->nstates; i++) if (ISBSET(d->work, i)) for (ca = cnfa->states[i]; ca->co != COLORLESS; ca++) { if (ca->co < cnfa->ncolors) continue; /* not a LACON arc */ if (ISBSET(d->work, ca->to)) continue; /* arc would be a no-op anyway */ sawlacons = 1; /* this LACON affects our result */ if (!lacon(v, cnfa, cp, ca->co)) { if (ISERR()) return NULL; continue; /* LACON arc cannot be traversed */ } if (ISERR()) return NULL; BSET(d->work, ca->to); dolacons = 1; if (ca->to == cnfa->post) ispost = 1; if (!(cnfa->stflags[ca->to] & CNFA_NOPROGRESS)) noprogress = 0; FDEBUG(("%d :> %d\n", i, ca->to)); } } h = HASH(d->work, d->wordsper); /* Is this stateset already in the cache? */ for (p = d->ssets, i = d->nssused; i > 0; p++, i--) if (HIT(h, d->work, p, d->wordsper)) { FDEBUG(("cached c%d\n", (int) (p - d->ssets))); break; /* NOTE BREAK OUT */ } if (i == 0) { /* nope, need a new cache entry */ p = getvacant(v, d, cp, start); if (p == NULL) return NULL; assert(p != css); for (i = 0; i < d->wordsper; i++) p->states[i] = d->work[i]; p->hash = h; p->flags = (ispost) ? POSTSTATE : 0; if (noprogress) p->flags |= NOPROGRESS; /* lastseen to be dealt with by caller */ } /* * Link new stateset to old, unless a LACON affected the result, in which * case we don't create the link. That forces future transitions across * this same arc (same prior stateset and character color) to come through * miss() again, so that we can recheck the LACON(s), which might or might * not pass since context will be different. */ if (!sawlacons) { FDEBUG(("c%d[%d]->c%d\n", (int) (css - d->ssets), co, (int) (p - d->ssets))); css->outs[co] = p; css->inchain[co] = p->ins; p->ins.ss = css; p->ins.co = (color) co; } return p; }