static rose_inline
char roseLeftfixCheckMiracles(const struct RoseEngine *t,
const struct LeftNfaInfo *left,
- struct core_info *ci, struct mq *q, u64a end) {
- if (left->transient) {
+ struct core_info *ci, struct mq *q, u64a end,
+ const char is_infix) {
+ if (!is_infix && left->transient) {
// Miracles won't help us with transient leftfix engines; they only
// scan for a limited time anyway.
return 1;
// If we're a prefix, then a miracle effectively results in us needing to
// re-init our state and start fresh.
- if (!left->infix) {
+ if (!is_infix) {
if (miracle_loc != begin_loc) {
DEBUG_PRINTF("re-init prefix state\n");
q->cur = q->end = 0;
return HWLM_CONTINUE_MATCHING;
}
-static rose_inline
+static really_inline
char roseTestLeftfix(const struct RoseEngine *t, struct hs_scratch *scratch,
- u32 qi, u32 leftfixLag, ReportID leftfixReport, u64a end) {
+ u32 qi, u32 leftfixLag, ReportID leftfixReport, u64a end,
+ const char is_infix) {
struct core_info *ci = &scratch->core_info;
u32 ri = queueToLeftIndex(t, qi);
DEBUG_PRINTF("testing %s %s %u/%u with lag %u (maxLag=%u)\n",
(left->transient ? "transient" : "active"),
- (left->infix ? "infix" : "prefix"),
+ (is_infix ? "infix" : "prefix"),
ri, qi, leftfixLag, left->maxLag);
assert(leftfixLag <= left->maxLag);
+ assert(left->infix == is_infix);
+ assert(!is_infix || !left->transient); // Only prefixes can be transient.
struct mq *q = scratch->queues + qi;
char *state = scratch->core_info.state;
initRoseQueue(t, qi, left, scratch);
if (ci->buf_offset) { // there have been writes before us!
s32 sp;
- if (left->transient) {
+ if (!is_infix && left->transient) {
sp = -(s32)ci->hlen;
} else {
sp = -(s32)loadRoseDelay(t, state, left);
* at stream boundary */
pushQueueAt(q, 0, MQE_START, sp);
- if (left->infix || (ci->buf_offset + sp > 0 && !left->transient)) {
+ if (is_infix || (ci->buf_offset + sp > 0 && !left->transient)) {
loadStreamState(q->nfa, q, sp);
} else {
pushQueueAt(q, 1, MQE_TOP, sp);
assert(loc >= q_cur_loc(q));
assert(leftfixReport != MO_INVALID_IDX);
- if (left->transient) {
+ if (!is_infix && left->transient) {
s64a start_loc = loc - left->transient;
if (q_cur_loc(q) < start_loc) {
q->cur = q->end = 0;
}
if (q_cur_loc(q) < loc || q_last_type(q) != MQE_START) {
- if (left->infix) {
+ if (is_infix) {
if (infixTooOld(q, loc)) {
DEBUG_PRINTF("infix %u died of old age\n", ri);
goto nfa_dead;
reduceInfixQueue(q, loc, left->maxQueueLen, q->nfa->maxWidth);
}
- if (!roseLeftfixCheckMiracles(t, left, ci, q, end)) {
+ if (!roseLeftfixCheckMiracles(t, left, ci, q, end, is_infix)) {
DEBUG_PRINTF("leftfix %u died due to miracle\n", ri);
goto nfa_dead;
}
return 0;
}
+static rose_inline
+char roseTestPrefix(const struct RoseEngine *t, struct hs_scratch *scratch,
+ u32 qi, u32 leftfixLag, ReportID leftfixReport, u64a end) {
+ return roseTestLeftfix(t, scratch, qi, leftfixLag, leftfixReport, end, 0);
+}
+
+static rose_inline
+char roseTestInfix(const struct RoseEngine *t, struct hs_scratch *scratch,
+ u32 qi, u32 leftfixLag, ReportID leftfixReport, u64a end) {
+ return roseTestLeftfix(t, scratch, qi, leftfixLag, leftfixReport, end, 1);
+}
+
static rose_inline
void roseTriggerInfix(const struct RoseEngine *t, struct hs_scratch *scratch,
u64a start, u64a end, u32 qi, u32 topEvent, u8 cancel) {
}
PROGRAM_NEXT_INSTRUCTION
- PROGRAM_CASE(CHECK_LEFTFIX) {
- if (!roseTestLeftfix(t, scratch, ri->queue, ri->lag, ri->report,
- end)) {
- DEBUG_PRINTF("failed leftfix check\n");
+ PROGRAM_CASE(CHECK_INFIX) {
+ if (!roseTestInfix(t, scratch, ri->queue, ri->lag, ri->report,
+ end)) {
+ DEBUG_PRINTF("failed infix check\n");
+ assert(ri->fail_jump); // must progress
+ pc += ri->fail_jump;
+ continue;
+ }
+ }
+ PROGRAM_NEXT_INSTRUCTION
+
+ PROGRAM_CASE(CHECK_PREFIX) {
+ if (!roseTestPrefix(t, scratch, ri->queue, ri->lag, ri->report,
+ end)) {
+ DEBUG_PRINTF("failed prefix check\n");
assert(ri->fail_jump); // must progress
pc += ri->fail_jump;
continue;
case ROSE_INSTR_CHECK_BOUNDS: return &u.checkBounds;
case ROSE_INSTR_CHECK_NOT_HANDLED: return &u.checkNotHandled;
case ROSE_INSTR_CHECK_LOOKAROUND: return &u.checkLookaround;
- case ROSE_INSTR_CHECK_LEFTFIX: return &u.checkLeftfix;
+ case ROSE_INSTR_CHECK_INFIX: return &u.checkInfix;
+ case ROSE_INSTR_CHECK_PREFIX: return &u.checkPrefix;
case ROSE_INSTR_ANCHORED_DELAY: return &u.anchoredDelay;
case ROSE_INSTR_PUSH_DELAYED: return &u.pushDelayed;
case ROSE_INSTR_CATCH_UP: return &u.catchUp;
case ROSE_INSTR_CHECK_BOUNDS: return sizeof(u.checkBounds);
case ROSE_INSTR_CHECK_NOT_HANDLED: return sizeof(u.checkNotHandled);
case ROSE_INSTR_CHECK_LOOKAROUND: return sizeof(u.checkLookaround);
- case ROSE_INSTR_CHECK_LEFTFIX: return sizeof(u.checkLeftfix);
+ case ROSE_INSTR_CHECK_INFIX: return sizeof(u.checkInfix);
+ case ROSE_INSTR_CHECK_PREFIX: return sizeof(u.checkPrefix);
case ROSE_INSTR_ANCHORED_DELAY: return sizeof(u.anchoredDelay);
case ROSE_INSTR_PUSH_DELAYED: return sizeof(u.pushDelayed);
case ROSE_INSTR_CATCH_UP: return sizeof(u.catchUp);
ROSE_STRUCT_CHECK_BOUNDS checkBounds;
ROSE_STRUCT_CHECK_NOT_HANDLED checkNotHandled;
ROSE_STRUCT_CHECK_LOOKAROUND checkLookaround;
- ROSE_STRUCT_CHECK_LEFTFIX checkLeftfix;
+ ROSE_STRUCT_CHECK_INFIX checkInfix;
+ ROSE_STRUCT_CHECK_PREFIX checkPrefix;
ROSE_STRUCT_ANCHORED_DELAY anchoredDelay;
ROSE_STRUCT_PUSH_DELAYED pushDelayed;
ROSE_STRUCT_CATCH_UP catchUp;
case ROSE_INSTR_CHECK_LOOKAROUND:
ri.u.checkLookaround.fail_jump = jump_val;
break;
- case ROSE_INSTR_CHECK_LEFTFIX:
- ri.u.checkLeftfix.fail_jump = jump_val;
+ case ROSE_INSTR_CHECK_INFIX:
+ ri.u.checkInfix.fail_jump = jump_val;
+ break;
+ case ROSE_INSTR_CHECK_PREFIX:
+ ri.u.checkPrefix.fail_jump = jump_val;
break;
case ROSE_INSTR_DEDUPE:
ri.u.dedupe.fail_jump = jump_val;
assert(!build.cc.streaming ||
build.g[v].left.lag <= MAX_STORED_LEFTFIX_LAG);
- auto ri = RoseInstruction(ROSE_INSTR_CHECK_LEFTFIX, JumpTarget::NEXT_BLOCK);
- ri.u.checkLeftfix.queue = lni.queue;
- ri.u.checkLeftfix.lag = build.g[v].left.lag;
- ri.u.checkLeftfix.report = build.g[v].left.leftfix_report;
- program.push_back(ri);
+ bool is_prefix = build.isRootSuccessor(v);
+ if (is_prefix) {
+ auto ri =
+ RoseInstruction(ROSE_INSTR_CHECK_PREFIX, JumpTarget::NEXT_BLOCK);
+ ri.u.checkPrefix.queue = lni.queue;
+ ri.u.checkPrefix.lag = build.g[v].left.lag;
+ ri.u.checkPrefix.report = build.g[v].left.leftfix_report;
+ program.push_back(move(ri));
+ } else {
+ auto ri =
+ RoseInstruction(ROSE_INSTR_CHECK_INFIX, JumpTarget::NEXT_BLOCK);
+ ri.u.checkInfix.queue = lni.queue;
+ ri.u.checkInfix.lag = build.g[v].left.lag;
+ ri.u.checkInfix.report = build.g[v].left.leftfix_report;
+ program.push_back(move(ri));
+ }
}
static
ROSE_INSTR_CHECK_BOUNDS, //!< Bounds on distance from offset 0.
ROSE_INSTR_CHECK_NOT_HANDLED, //!< Test & set role in "handled".
ROSE_INSTR_CHECK_LOOKAROUND, //!< Lookaround check.
- ROSE_INSTR_CHECK_LEFTFIX, //!< Leftfix must be in accept state.
+ ROSE_INSTR_CHECK_INFIX, //!< Infix engine must be in accept state.
+ ROSE_INSTR_CHECK_PREFIX, //!< Prefix engine must be in accept state.
ROSE_INSTR_PUSH_DELAYED, //!< Push delayed literal matches.
ROSE_INSTR_CATCH_UP, //!< Catch up engines, anchored matches.
ROSE_INSTR_SOM_ADJUST, //!< Set SOM from a distance to EOM.
u32 fail_jump; //!< Jump forward this many bytes on failure.
};
-struct ROSE_STRUCT_CHECK_LEFTFIX {
+struct ROSE_STRUCT_CHECK_INFIX {
+ u8 code; //!< From enum RoseInstructionCode.
+ u32 queue; //!< Queue of leftfix to check.
+ u32 lag; //!< Lag of leftfix for this case.
+ ReportID report; //!< ReportID of leftfix to check.
+ u32 fail_jump; //!< Jump forward this many bytes on failure.
+};
+
+struct ROSE_STRUCT_CHECK_PREFIX {
u8 code; //!< From enum RoseInstructionCode.
u32 queue; //!< Queue of leftfix to check.
u32 lag; //!< Lag of leftfix for this case.