public MotifRunner(Motif <TElement> motif, IReadOnlyList <TElement> sequence) { Length = sequence.Count; LastCodeIndex = motif.Code.Length - 1; RemainingLength = Length; GetMotif = () => motif; GetSequence = () => sequence; }
private bool Loop(Motif <TElement> motif, int opIndex, int startIndex, int remainingLength) { var func = motif.Delegates[opIndex]; int initialRemainingLength = remainingLength; int opMatches = 0; var op = motif.Code[opIndex]; int minFinalIndex = startIndex + op.Lower; bool isMatch = true; TElement current = default(TElement); for (int i = startIndex; isMatch && i <= minFinalIndex; ++i) { current = Sequence[i]; if (!func(current)) { isMatch = false; } } if (isMatch) { // if a range instead of a set count if (op.Upper != -1) { // doesn't bother running ranges that leave insufficient length for remaining code // remainingLength includes the lower bound of this loop op int maxFinalIndex = Math.Min(startIndex + op.Upper, startIndex + remainingLength); int index; bool nextIsLoop = motif.Code[opIndex + 1].Code.HasFlag(MotifCode.Loop); isMatch = false; // potential range includes the previously-confirmed match at the end of the lower bound // sets the index to the maximum of the range for (index = minFinalIndex; func(current) && index <= maxFinalIndex; ++index) { } if (opIndex == LastCodeIndex) { EndMatch(index); return(true); } for (; index >= minFinalIndex; --index) // greedy by default { // forbids matches from being subsequences of each other by default if (nextIsLoop) { if ( Loop( motif, opIndex + 1, index + 1, remainingLength - (index - startIndex) ) ) { return(true); } } else { if ( Go( motif, opIndex + 1, index + 1, remainingLength - (index - startIndex) ) ) { return(true); } } } } else if (opIndex == LastCodeIndex) { EndMatch(minFinalIndex); return(true); } } return(isMatch); }
private bool Go(Motif <TElement> motif, int opIndex, int startIndex, int remainingLength) { return(false); }