Esempio n. 1
0
        /// <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);
        }