#region Copyright and License // // Fizzler - CSS Selector Engine for Microsoft .NET Framework // Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License as published by the Free // Software Foundation; either version 3 of the License, or (at your option) // any later version. // // This library is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more // details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // #endregion namespace Fizzler { #region Imports using System; using System.Collections; using System.Collections.Generic; #endregion /// /// Adds reading semantics to a base with the /// option to un-read and insert new elements while consuming the source. /// public sealed class Reader : IDisposable, IEnumerable { private IEnumerator _enumerator; private Stack _buffer; /// /// Initialize a new with a base /// object. /// public Reader(IEnumerable e) : this(CheckNonNull(e).GetEnumerator()) { } private static IEnumerable CheckNonNull(IEnumerable e) { if (e == null) throw new ArgumentNullException("e"); return e; } /// /// Initialize a new with a base /// object. /// public Reader(IEnumerator e) { if(e == null) throw new ArgumentNullException("e"); _enumerator = e; _buffer = new Stack(); RealRead(); } /// /// Indicates whether there is, at least, one value waiting to be read or not. /// public bool HasMore { get { EnsureAlive(); return _buffer.Count > 0; } } /// /// Pushes back a new value that will be returned on the next read. /// public void Unread(T value) { EnsureAlive(); _buffer.Push(value); } /// /// Reads and returns the next value. /// public T Read() { if (!HasMore) throw new InvalidOperationException(); var value = _buffer.Pop(); if (_buffer.Count == 0) RealRead(); return value; } /// /// Peeks the next value waiting to be read. /// /// /// Thrown if there is no value waiting to be read. /// public T Peek() { if (!HasMore) throw new InvalidOperationException(); return _buffer.Peek(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// Returns an enumerator that iterates through the remaining /// values to be read. /// public IEnumerator GetEnumerator() { EnsureAlive(); return GetEnumeratorImpl(); } private IEnumerator GetEnumeratorImpl() { while (HasMore) yield return Read(); } private void RealRead() { EnsureAlive(); if (_enumerator.MoveNext()) Unread(_enumerator.Current); } /// /// Disposes the enumerator used to initialize this object /// if that enumerator supports . /// public void Close() { Dispose(); } void IDisposable.Dispose() { Dispose(); } void Dispose() { if(_enumerator == null) return; _enumerator.Dispose(); _enumerator = null; _buffer = null; } private void EnsureAlive() { if (_enumerator == null) throw new ObjectDisposedException(GetType().Name); } } }