#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);
}
}
}