Array.Enumerators.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. namespace System
  8. {
  9. internal sealed class ArrayEnumerator : IEnumerator, ICloneable
  10. {
  11. private Array array;
  12. private int index;
  13. private int endIndex;
  14. private int startIndex; // Save for Reset.
  15. private int[] _indices; // The current position in a multidim array
  16. private bool _complete;
  17. internal ArrayEnumerator(Array array, int index, int count)
  18. {
  19. this.array = array;
  20. this.index = index - 1;
  21. startIndex = index;
  22. endIndex = index + count;
  23. _indices = new int[array.Rank];
  24. int checkForZero = 1; // Check for dimensions of size 0.
  25. for (int i = 0; i < array.Rank; i++)
  26. {
  27. _indices[i] = array.GetLowerBound(i);
  28. checkForZero *= array.GetLength(i);
  29. }
  30. // To make MoveNext simpler, decrement least significant index.
  31. _indices[_indices.Length - 1]--;
  32. _complete = (checkForZero == 0);
  33. }
  34. private void IncArray()
  35. {
  36. // This method advances us to the next valid array index,
  37. // handling all the multiple dimension & bounds correctly.
  38. // Think of it like an odometer in your car - we start with
  39. // the last digit, increment it, and check for rollover. If
  40. // it rolls over, we set all digits to the right and including
  41. // the current to the appropriate lower bound. Do these overflow
  42. // checks for each dimension, and if the most significant digit
  43. // has rolled over it's upper bound, we're done.
  44. //
  45. int rank = array.Rank;
  46. _indices[rank - 1]++;
  47. for (int dim = rank - 1; dim >= 0; dim--)
  48. {
  49. if (_indices[dim] > array.GetUpperBound(dim))
  50. {
  51. if (dim == 0)
  52. {
  53. _complete = true;
  54. break;
  55. }
  56. for (int j = dim; j < rank; j++)
  57. _indices[j] = array.GetLowerBound(j);
  58. _indices[dim - 1]++;
  59. }
  60. }
  61. }
  62. public object Clone()
  63. {
  64. return MemberwiseClone();
  65. }
  66. public bool MoveNext()
  67. {
  68. if (_complete)
  69. {
  70. index = endIndex;
  71. return false;
  72. }
  73. index++;
  74. IncArray();
  75. return !_complete;
  76. }
  77. public object Current
  78. {
  79. get
  80. {
  81. if (index < startIndex) ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumNotStarted();
  82. if (_complete) ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumEnded();
  83. return array.GetValue(_indices);
  84. }
  85. }
  86. public void Reset()
  87. {
  88. index = startIndex - 1;
  89. int checkForZero = 1;
  90. for (int i = 0; i < array.Rank; i++)
  91. {
  92. _indices[i] = array.GetLowerBound(i);
  93. checkForZero *= array.GetLength(i);
  94. }
  95. _complete = (checkForZero == 0);
  96. // To make MoveNext simpler, decrement least significant index.
  97. _indices[_indices.Length - 1]--;
  98. }
  99. }
  100. internal sealed class SZArrayEnumerator : IEnumerator, ICloneable
  101. {
  102. private readonly Array _array;
  103. private int _index;
  104. private int _endIndex; // Cache Array.Length, since it's a little slow.
  105. internal SZArrayEnumerator(Array array)
  106. {
  107. Debug.Assert(array.Rank == 1 && array.GetLowerBound(0) == 0, "SZArrayEnumerator only works on single dimension arrays w/ a lower bound of zero.");
  108. _array = array;
  109. _index = -1;
  110. _endIndex = array.Length;
  111. }
  112. public object Clone()
  113. {
  114. return MemberwiseClone();
  115. }
  116. public bool MoveNext()
  117. {
  118. if (_index < _endIndex)
  119. {
  120. _index++;
  121. return (_index < _endIndex);
  122. }
  123. return false;
  124. }
  125. public object Current
  126. {
  127. get
  128. {
  129. if (_index < 0)
  130. ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumNotStarted();
  131. if (_index >= _endIndex)
  132. ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumEnded();
  133. return _array.GetValue(_index);
  134. }
  135. }
  136. public void Reset()
  137. {
  138. _index = -1;
  139. }
  140. }
  141. internal sealed class SZGenericArrayEnumerator<T> : IEnumerator<T>
  142. {
  143. private readonly T[] _array;
  144. private int _index;
  145. // Array.Empty is intentionally omitted here, since we don't want to pay for generic instantiations that
  146. // wouldn't have otherwise been used.
  147. internal static readonly SZGenericArrayEnumerator<T> Empty = new SZGenericArrayEnumerator<T>(new T[0]);
  148. internal SZGenericArrayEnumerator(T[] array)
  149. {
  150. Debug.Assert(array != null);
  151. _array = array;
  152. _index = -1;
  153. }
  154. public bool MoveNext()
  155. {
  156. int index = _index + 1;
  157. if ((uint)index >= (uint)_array.Length)
  158. {
  159. _index = _array.Length;
  160. return false;
  161. }
  162. _index = index;
  163. return true;
  164. }
  165. public T Current
  166. {
  167. get
  168. {
  169. int index = _index;
  170. T[] array = _array;
  171. if ((uint)index >= (uint)array.Length)
  172. {
  173. ThrowHelper.ThrowInvalidOperationException_EnumCurrent(index);
  174. }
  175. return array[index];
  176. }
  177. }
  178. object IEnumerator.Current => Current;
  179. void IEnumerator.Reset() => _index = -1;
  180. public void Dispose()
  181. {
  182. }
  183. }
  184. }