Why my own custom iterator interfaces instead of implementing IEnumerable<T>
I felt this should be addressed in depth -- added as a matter of interest
The problem is iterating two sequences (seqA, a.k.a. Source and seqB, a.k.a. Mask)
- The
Maskmust be satisfied in whole (byte for byte in sequence) - Reset
Maskstack when matching fails on a sequence - Increment the
Maskstack asSourcesequences match - Stop matches if
Sourcestack is at the end
This boils down to needing 2 state machines to handle the logic of iterating an inner set of conditions (a.k.a. maskTokens) for evaluation. A maskToken is then used to match against a specified Source sequence - which is iterated by the outer state machine.
I used interfaces to build two rudimentary state-machines implementing IEnumerator<T>. For the record, I am weighing the implementation of IEnumerable<T>; at the time of design I was not convinced of how intuitive the interface would be when considering the assumptions made while using an IEnumerable<T>.
The inner state machine - MaskIterator - doesn't really have any special logic but exposes some additional members:
// `ControlChar` is a custom value type representing a byte[4]
interface IMaskSequenceIterator : IEnumerator<ControlChar> {
#region properties
ControlChar Current { get; }
int Index { get; }
IMaskToken MaskToken { get; }
#endregion
#region members
void Dispose();
bool IsFirst();
bool IsLast();
long Length();
void MoveFirst();
bool MoveNext();
void Reset();
#endregion
}
The outer state machine - MatchIterator - has quite a bit more logic:
A. Manipulate and Interpret MaskIterator properties
B. Find Match Sequence: logic black box
// IMetaToken holds [start, length] info of sequence matches
interface IMatchSequenceIterator : IEnumerator<IMetaToken> {
#region properties
IMetaToken Current { get; }
bool EndOfSequence { get; set; }
bool IsSequenceMatch { get; }
IMaskSequenceIterator MaskIterator { get; }
#endregion
#region members
void Dispose();
bool MoveNext();
void Reset();
#endregion
}
Basically, I am taking advantage of the state-machine characteristics of the IEnumerator (as a pattern, so to speak). The idea of this project is that I can build a mask, or sequence of bytes - say, 91-00-00-00; 16-00-00-00; 58-00-00-00 - and match a source byte stream looking for every occurrence of 91-00-00-00-16-00-00-00-58-00-00-00.
The mask formatter can use wildcards specifying a length so I can format something like: 91-00-00-00 42-42 42-42-16-00 58-00-00-00
... where 42 is *. The MatchIterator will return meta data for anything that matches the pattern 91-00-00-00-42-42-42-42-16-00-58-00-00-00 and 42 can be replaced by any byte.
Feedback is welcome!