/// <summary> /// Find the longest match starting at a given position. /// /// If there is a non-empty match for the DFA in the source string starting at startPos, /// then the LastMatchStart position is set to startPos, the LastMatchEnd position is set /// to the end of the longest such match, and the TResult from that match is returned. /// </summary> /// <param name="state">The start state of the DFA for the patterns you want to match</param> /// <param name="startPos">the position in the source string to test for a match</param> /// <param name="val">The TResult that the pattern matches</param> /// <returns>True if the source string matches a pattern in the DFA at startPos. Otherwise false.</returns> public bool MatchAt(DfaState <TResult> state, int startPos, out TResult val) { val = default; var ret = false; var newNmmSize = 0; var writeNmmNext = startPos + 4; for (var pos = startPos; pos < limit;) { state = state.GetNextState(src[pos]); pos++; if (state == null) { break; } if (state.IsAccepting) { ret = true; val = state.Match; LastMatchEnd = pos; newNmmSize = 0; continue; } //Check and update the non-matching memo, to accelerate processing long sequences //of non-accepting states at multiple positions //Many DFAs simply don't have long sequences of non-accepting states, so we only //want to incur this overhead when we're actually in a non-accepting state bool exitPosLoop = false; while (!exitPosLoop && nmmStart < NmmSize && nmmPositions[nmmStart] <= pos) { if (nmmPositions[nmmStart] == pos && nmmStates[nmmStart] == state) { //hit the memo -- we won't find a match. exitPosLoop = true; } //we passed this memo entry without using it -- remove it. ++nmmStart; } if (exitPosLoop) { break; } if (pos >= writeNmmNext && newNmmSize < NmmSize) { nmmPositions[newNmmSize] = pos; nmmStates[newNmmSize] = state; ++newNmmSize; writeNmmNext = pos + (2 << newNmmSize); if (nmmStart < newNmmSize) { nmmStart = newNmmSize; } } } //successful or not, we're done. Merge in our new entries for the non-matching memo while (nmmStart < NmmSize && nmmPositions[nmmStart] < writeNmmNext) { ++nmmStart; } while (newNmmSize > 0) { --newNmmSize; --nmmStart; nmmPositions[nmmStart] = nmmPositions[newNmmSize]; nmmStates[nmmStart] = nmmStates[newNmmSize]; } if (ret) { LastMatchStart = startPos; } return(ret); }