/// <summary> /// This method matches the sequence against the source array. /// </summary> /// <typeparam name="TSource">The source array type.</typeparam> /// <typeparam name="TMatch">The match array type.</typeparam> /// <param name="source">The source array.</param> /// <param name="match">The source array.</param> /// <param name="predicate">The prediciate used to match the source and match array elements.</param> /// <param name="state">The current match state. This can be passed in when matching chucks of data from multiple source arrays.</param> /// <returns>The outgoing match state. This will indicate whether the match was successful or partially successful, i.e. there /// is a partial match at the end of the array that cannot be fully resolved.</returns> public static MatchState <TSource> MatchSequence <TSource, TMatch>( this IEnumerable <TSource> source, IEnumerable <TMatch> match, Func <TSource, TMatch, bool> predicate, MatchState <TSource> state) { IEnumerator <TSource> sourceEnum = source.GetEnumerator(); return(sourceEnum.MatchSequence(match, predicate, state)); }
/// <summary> /// /// </summary> /// <typeparam name="TSource"></typeparam> /// <typeparam name="TMatch"></typeparam> /// <param name="sourceEnum"></param> /// <param name="match"></param> /// <param name="predicate"></param> /// <param name="state"></param> /// <returns></returns> public static MatchState <TSource> MatchSequence <TSource, TMatch>( this IEnumerator <TSource> sourceEnum, IEnumerable <TMatch> match, Func <TSource, TMatch, bool> predicate, MatchState <TSource> state) { try { //Get an internal state to track the match progress, //either create a new one, or get one from the incoming state object. MatchState <TSource> stateInternal; if (state == null) { stateInternal = new MatchState <TSource>(); } else { stateInternal = state; } //Shortcut to skip checking if the match has already been reached in the collection. if (stateInternal.IsMatch) { return(stateInternal); } //Check whether we are currently matching a block, this can happen when //matches are split over chunks of source arrays, such as a byte block passed from a remote socket. bool matchActive = stateInternal.CarryOver > 0; //Get the match array enumerator at the correct position. IEnumerator <TMatch> matchEnum = match.GetEnumeratorAtPosition(stateInternal.CarryOver); //Get the current record in the match array. TMatch matchItem = matchEnum.Current; int posSource = 0; int posMatch = stateInternal.CarryOver; //Ok, loop through each record in the source and compare against the match array. //foreach (TSource item in source) while (sourceEnum.MoveNext()) { TSource item = sourceEnum.Current; //This method logs the data item from the current enumeration if this state is set to record it. stateInternal.DataLog(item); //OK, do we have a match? bool isMatch = predicate(item, matchItem); if (isMatch) { matchActive = true; stateInternal.Length++; stateInternal.SlidingWindow.Enqueue(item); if (matchEnum.MoveNext()) { //Add the item to the sliding window for back checking matchItem = matchEnum.Current; posMatch++; } else { matchActive = false; //Ok, we have completed a match. stateInternal.SetMatch(posSource - posMatch); break; } } else { if (matchActive) { if (stateInternal.MultipartMatch) { //We cannot continue as we are only matching part of the records. matchActive = false; stateInternal.Success = false; break; } //We need to check the previous record to see whether there is a partial match in there. //This method will also set the match enumerator to the correct position posMatch = ValidateSlidingWindow <TSource, TMatch>(stateInternal, matchEnum, predicate); stateInternal.Length = posMatch; //OK, no match so reset the match buffer to its default position matchItem = matchEnum.Current; //Set the match to active as we have matched based on the previous set of bytes. matchActive = posMatch > 0; } } posSource++; } //If the match is still active then we have a partial match and need to pass this out. if (matchActive) { stateInternal.SetPartialMatch(posSource, posMatch); } return(stateInternal); } catch (Exception ex) { throw ex; } }