using System; using System.Collections; using System.Collections.Generic; namespace PKHeX.Core { /// /// Iterates a generic collection with the ability to peek into the collection to see if the next element exists. /// /// Generic Collection Element Type public class PeekEnumerator : IEnumerator { private readonly IEnumerator Enumerator; private T peek; private bool didPeek; #region IEnumerator Implementation /// /// Advances the enumerator to the next element in the collection. /// /// Indication if there are more elements in the collection. public bool MoveNext() { if (!didPeek) return Enumerator.MoveNext(); didPeek = false; return true; } /// /// Sets the enumerator to its initial position, which is before the first element in the collection. /// public void Reset() { Enumerator.Reset(); didPeek = false; } object IEnumerator.Current => Current; public void Dispose() => Enumerator.Dispose(); public T Current => didPeek ? peek : Enumerator.Current; #endregion public PeekEnumerator(IEnumerator enumerator) => Enumerator = enumerator ?? throw new ArgumentNullException(nameof(enumerator)); public PeekEnumerator(IEnumerable enumerable) => Enumerator = enumerable.GetEnumerator(); /// /// Fetch the next element, if not already performed. /// /// True/False that a Next element exists /// Advances the enumerator if Next has not been peeked already private bool TryFetchPeek() { if (!didPeek && (didPeek = Enumerator.MoveNext())) peek = Enumerator.Current; return didPeek; } /// /// Peeks to the next element /// /// Next element /// Throws an exception if no element exists public T Peek() { if (!TryFetchPeek()) throw new InvalidOperationException("Enumeration already finished."); return peek; } public T PeekOrDefault() => !TryFetchPeek() ? default(T) : peek; /// /// Checks if a Next element exists /// /// True/False that a Next element exists public bool PeekIsNext() => TryFetchPeek(); } }