| File: System\Collections\Immutable\ImmutableArray_1.Enumerator.cs | Web Access |
| Project: src\runtime\src\libraries\System.Collections.Immutable\src\System.Collections.Immutable.csproj (System.Collections.Immutable) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; namespace System.Collections.Immutable { public partial struct ImmutableArray<T> { /// <summary> /// An array enumerator. /// </summary> /// <remarks> /// It is important that this enumerator does NOT implement <see cref="IDisposable"/>. /// We want the iterator to inline when we do foreach and to not result in /// a try/finally frame in the client. /// </remarks> public struct Enumerator { /// <summary> /// The array being enumerated. /// </summary> private readonly T[] _array; /// <summary> /// The currently enumerated position. /// </summary> /// <value> /// -1 before the first call to <see cref="MoveNext"/>. /// >= this.array.Length after <see cref="MoveNext"/> returns false. /// </value> private int _index; /// <summary> /// Initializes a new instance of the <see cref="Enumerator"/> struct. /// </summary> /// <param name="array">The array to enumerate.</param> internal Enumerator(T[] array) { _array = array; _index = -1; } /// <summary> /// Gets the currently enumerated value. /// </summary> public T Current { get { // PERF: no need to do a range check, we already did in MoveNext. // if user did not call MoveNext or ignored its result (incorrect use) // they will still get an exception from the array access range check. return _array[_index]; } } /// <summary> /// Advances to the next value to be enumerated. /// </summary> /// <returns><c>true</c> if another item exists in the array; <c>false</c> otherwise.</returns> public bool MoveNext() { return ++_index < _array.Length; } } /// <summary> /// An array enumerator that implements <see cref="IEnumerator{T}"/> pattern (including <see cref="IDisposable"/>). /// </summary> private sealed class EnumeratorObject : IEnumerator<T> { /// <summary> /// A shareable singleton for enumerating empty arrays. /// </summary> private static readonly IEnumerator<T> s_EmptyEnumerator = new EnumeratorObject(ImmutableArray<T>.Empty.array!); /// <summary> /// The array being enumerated. /// </summary> private readonly T[] _array; /// <summary> /// The currently enumerated position. /// </summary> /// <value> /// -1 before the first call to <see cref="MoveNext"/>. /// this.array.Length - 1 after MoveNext returns false. /// </value> private int _index; /// <summary> /// Initializes a new instance of the <see cref="Enumerator"/> class. /// </summary> private EnumeratorObject(T[] array) { _index = -1; _array = array; } /// <summary> /// Gets the currently enumerated value. /// </summary> public T Current { get { // unsigned compare performs the range check in one compare if (unchecked((uint)_index) >= (uint)_array.Length) { // Before first or after last MoveNext. ThrowHelper.ThrowInvalidOperationException(); } return _array[_index]; } } /// <summary> /// Gets the currently enumerated value. /// </summary> object? IEnumerator.Current { get { return this.Current; } } /// <summary> /// If another item exists in the array, advances to the next value to be enumerated. /// </summary> /// <returns><c>true</c> if another item exists in the array; <c>false</c> otherwise.</returns> public bool MoveNext() { int newIndex = _index + 1; int length = _array.Length; // unsigned math is used to prevent false positive if index + 1 overflows. if ((uint)newIndex <= (uint)length) { _index = newIndex; return (uint)newIndex < (uint)length; } return false; } /// <summary> /// Resets enumeration to the start of the array. /// </summary> void IEnumerator.Reset() { _index = -1; } /// <summary> /// Disposes this enumerator. /// </summary> /// <remarks> /// Currently has no action. /// </remarks> public void Dispose() { // we do not have any native or disposable resources. // nothing to do here. } /// <summary> /// Creates an enumerator for the specified array. /// </summary> internal static IEnumerator<T> Create(T[] array) { if (array.Length != 0) { return new EnumeratorObject(array); } else { return s_EmptyEnumerator; } } } } }