Reader.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #region Copyright and License
  2. //
  3. // Fizzler - CSS Selector Engine for Microsoft .NET Framework
  4. // Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved.
  5. //
  6. // This library is free software; you can redistribute it and/or modify it under
  7. // the terms of the GNU Lesser General Public License as published by the Free
  8. // Software Foundation; either version 3 of the License, or (at your option)
  9. // any later version.
  10. //
  11. // This library is distributed in the hope that it will be useful, but WITHOUT
  12. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  13. // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  14. // details.
  15. //
  16. // You should have received a copy of the GNU Lesser General Public License
  17. // along with this library; if not, write to the Free Software Foundation, Inc.,
  18. // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. //
  20. #endregion
  21. #pragma warning disable
  22. namespace Fizzler
  23. {
  24. #region Imports
  25. using System;
  26. using System.Collections;
  27. using System.Collections.Generic;
  28. #endregion
  29. /// <summary>
  30. /// Adds reading semantics to a base <see cref="IEnumerator{T}"/> with the
  31. /// option to un-read and insert new elements while consuming the source.
  32. /// </summary>
  33. public sealed class Reader<T> : IDisposable, IEnumerable<T>
  34. {
  35. private IEnumerator<T> _enumerator;
  36. private Stack<T> _buffer;
  37. /// <summary>
  38. /// Initialize a new <see cref="Reader{T}"/> with a base
  39. /// <see cref="IEnumerable{T}"/> object.
  40. /// </summary>
  41. public Reader(IEnumerable<T> e) :
  42. this(CheckNonNull(e).GetEnumerator())
  43. { }
  44. private static IEnumerable<T> CheckNonNull(IEnumerable<T> e)
  45. {
  46. if (e == null) throw new ArgumentNullException("e");
  47. return e;
  48. }
  49. /// <summary>
  50. /// Initialize a new <see cref="Reader{T}"/> with a base
  51. /// <see cref="IEnumerator{T}"/> object.
  52. /// </summary>
  53. public Reader(IEnumerator<T> e)
  54. {
  55. if (e == null) throw new ArgumentNullException("e");
  56. _enumerator = e;
  57. _buffer = new Stack<T>();
  58. RealRead();
  59. }
  60. /// <summary>
  61. /// Indicates whether there is, at least, one value waiting to be read or not.
  62. /// </summary>
  63. public bool HasMore
  64. {
  65. get
  66. {
  67. EnsureAlive();
  68. return _buffer.Count > 0;
  69. }
  70. }
  71. /// <summary>
  72. /// Pushes back a new value that will be returned on the next read.
  73. /// </summary>
  74. public void Unread(T value)
  75. {
  76. EnsureAlive();
  77. _buffer.Push(value);
  78. }
  79. /// <summary>
  80. /// Reads and returns the next value.
  81. /// </summary>
  82. public T Read()
  83. {
  84. if (!HasMore)
  85. throw new InvalidOperationException();
  86. var value = _buffer.Pop();
  87. if (_buffer.Count == 0)
  88. RealRead();
  89. return value;
  90. }
  91. /// <summary>
  92. /// Peeks the next value waiting to be read.
  93. /// </summary>
  94. /// <exception cref="InvalidOperationException">
  95. /// Thrown if there is no value waiting to be read.
  96. /// </exception>
  97. public T Peek()
  98. {
  99. if (!HasMore)
  100. throw new InvalidOperationException();
  101. return _buffer.Peek();
  102. }
  103. IEnumerator IEnumerable.GetEnumerator()
  104. {
  105. return GetEnumerator();
  106. }
  107. /// <summary>
  108. /// Returns an enumerator that iterates through the remaining
  109. /// values to be read.
  110. /// </summary>
  111. public IEnumerator<T> GetEnumerator()
  112. {
  113. EnsureAlive();
  114. return GetEnumeratorImpl();
  115. }
  116. private IEnumerator<T> GetEnumeratorImpl()
  117. {
  118. while (HasMore)
  119. yield return Read();
  120. }
  121. private void RealRead()
  122. {
  123. EnsureAlive();
  124. if (_enumerator.MoveNext())
  125. Unread(_enumerator.Current);
  126. }
  127. /// <summary>
  128. /// Disposes the enumerator used to initialize this object
  129. /// if that enumerator supports <see cref="IDisposable"/>.
  130. /// </summary>
  131. public void Close()
  132. {
  133. Dispose();
  134. }
  135. void IDisposable.Dispose()
  136. {
  137. Dispose();
  138. }
  139. void Dispose()
  140. {
  141. if (_enumerator == null)
  142. return;
  143. _enumerator.Dispose();
  144. _enumerator = null;
  145. _buffer = null;
  146. }
  147. private void EnsureAlive()
  148. {
  149. if (_enumerator == null)
  150. throw new ObjectDisposedException(GetType().Name);
  151. }
  152. }
  153. }
  154. #pragma warning restore