| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using System.Collections;
- using System.Collections.Generic;
- using System.Diagnostics;
- namespace System
- {
- internal sealed class ArrayEnumerator : IEnumerator, ICloneable
- {
- private Array array;
- private int index;
- private int endIndex;
- private int startIndex; // Save for Reset.
- private int[] _indices; // The current position in a multidim array
- private bool _complete;
- internal ArrayEnumerator(Array array, int index, int count)
- {
- this.array = array;
- this.index = index - 1;
- startIndex = index;
- endIndex = index + count;
- _indices = new int[array.Rank];
- int checkForZero = 1; // Check for dimensions of size 0.
- for (int i = 0; i < array.Rank; i++)
- {
- _indices[i] = array.GetLowerBound(i);
- checkForZero *= array.GetLength(i);
- }
- // To make MoveNext simpler, decrement least significant index.
- _indices[_indices.Length - 1]--;
- _complete = (checkForZero == 0);
- }
- private void IncArray()
- {
- // This method advances us to the next valid array index,
- // handling all the multiple dimension & bounds correctly.
- // Think of it like an odometer in your car - we start with
- // the last digit, increment it, and check for rollover. If
- // it rolls over, we set all digits to the right and including
- // the current to the appropriate lower bound. Do these overflow
- // checks for each dimension, and if the most significant digit
- // has rolled over it's upper bound, we're done.
- //
- int rank = array.Rank;
- _indices[rank - 1]++;
- for (int dim = rank - 1; dim >= 0; dim--)
- {
- if (_indices[dim] > array.GetUpperBound(dim))
- {
- if (dim == 0)
- {
- _complete = true;
- break;
- }
- for (int j = dim; j < rank; j++)
- _indices[j] = array.GetLowerBound(j);
- _indices[dim - 1]++;
- }
- }
- }
- public object Clone()
- {
- return MemberwiseClone();
- }
- public bool MoveNext()
- {
- if (_complete)
- {
- index = endIndex;
- return false;
- }
- index++;
- IncArray();
- return !_complete;
- }
- public object Current
- {
- get
- {
- if (index < startIndex) ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumNotStarted();
- if (_complete) ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumEnded();
- return array.GetValue(_indices);
- }
- }
- public void Reset()
- {
- index = startIndex - 1;
- int checkForZero = 1;
- for (int i = 0; i < array.Rank; i++)
- {
- _indices[i] = array.GetLowerBound(i);
- checkForZero *= array.GetLength(i);
- }
- _complete = (checkForZero == 0);
- // To make MoveNext simpler, decrement least significant index.
- _indices[_indices.Length - 1]--;
- }
- }
- internal sealed class SZArrayEnumerator : IEnumerator, ICloneable
- {
- private readonly Array _array;
- private int _index;
- private int _endIndex; // Cache Array.Length, since it's a little slow.
- internal SZArrayEnumerator(Array array)
- {
- Debug.Assert(array.Rank == 1 && array.GetLowerBound(0) == 0, "SZArrayEnumerator only works on single dimension arrays w/ a lower bound of zero.");
- _array = array;
- _index = -1;
- _endIndex = array.Length;
- }
- public object Clone()
- {
- return MemberwiseClone();
- }
- public bool MoveNext()
- {
- if (_index < _endIndex)
- {
- _index++;
- return (_index < _endIndex);
- }
- return false;
- }
- public object Current
- {
- get
- {
- if (_index < 0)
- ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumNotStarted();
- if (_index >= _endIndex)
- ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumEnded();
- return _array.GetValue(_index);
- }
- }
- public void Reset()
- {
- _index = -1;
- }
- }
- internal sealed class SZGenericArrayEnumerator<T> : IEnumerator<T>
- {
- private readonly T[] _array;
- private int _index;
- // Array.Empty is intentionally omitted here, since we don't want to pay for generic instantiations that
- // wouldn't have otherwise been used.
- internal static readonly SZGenericArrayEnumerator<T> Empty = new SZGenericArrayEnumerator<T>(new T[0]);
- internal SZGenericArrayEnumerator(T[] array)
- {
- Debug.Assert(array != null);
- _array = array;
- _index = -1;
- }
- public bool MoveNext()
- {
- int index = _index + 1;
- if ((uint)index >= (uint)_array.Length)
- {
- _index = _array.Length;
- return false;
- }
- _index = index;
- return true;
- }
- public T Current
- {
- get
- {
- int index = _index;
- T[] array = _array;
- if ((uint)index >= (uint)array.Length)
- {
- ThrowHelper.ThrowInvalidOperationException_EnumCurrent(index);
- }
- return array[index];
- }
- }
- object IEnumerator.Current => Current;
- void IEnumerator.Reset() => _index = -1;
- public void Dispose()
- {
- }
- }
- }
|