| File: System\Collections\Immutable\ImmutableQueue_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; using System.ComponentModel; namespace System.Collections.Immutable { public sealed partial class ImmutableQueue<T> { /// <summary> /// A memory allocation-free enumerator of <see cref="ImmutableQueue{T}"/>. /// </summary> [EditorBrowsable(EditorBrowsableState.Advanced)] public struct Enumerator { /// <summary> /// The original queue being enumerated. /// </summary> private readonly ImmutableQueue<T> _originalQueue; /// <summary> /// The remaining forwards stack of the queue being enumerated. /// </summary> private ImmutableStack<T>? _remainingForwardsStack; /// <summary> /// The remaining backwards stack of the queue being enumerated. /// Its order is reversed when the field is first initialized. /// </summary> private ImmutableStack<T>? _remainingBackwardsStack; /// <summary> /// Initializes a new instance of the <see cref="Enumerator"/> struct. /// </summary> /// <param name="queue">The queue to enumerate.</param> internal Enumerator(ImmutableQueue<T> queue) { _originalQueue = queue; // The first call to MoveNext will initialize these. _remainingForwardsStack = null; _remainingBackwardsStack = null; } /// <summary> /// The current element. /// </summary> public T Current { get { if (_remainingForwardsStack == null) { // The initial call to MoveNext has not yet been made. throw new InvalidOperationException(); } if (!_remainingForwardsStack.IsEmpty) { return _remainingForwardsStack.Peek(); } else if (!_remainingBackwardsStack!.IsEmpty) { return _remainingBackwardsStack.Peek(); } else { // We've advanced beyond the end of the queue. throw new InvalidOperationException(); } } } /// <summary> /// Advances enumeration to the next element. /// </summary> /// <returns>A value indicating whether there is another element in the enumeration.</returns> public bool MoveNext() { if (_remainingForwardsStack == null) { // This is the initial step. // Empty queues have no forwards or backwards _remainingForwardsStack = _originalQueue._forwards; _remainingBackwardsStack = _originalQueue.BackwardsReversed; } else if (!_remainingForwardsStack.IsEmpty) { _remainingForwardsStack = _remainingForwardsStack.Pop(); } else if (!_remainingBackwardsStack!.IsEmpty) { _remainingBackwardsStack = _remainingBackwardsStack.Pop(); } return !_remainingForwardsStack.IsEmpty || !_remainingBackwardsStack!.IsEmpty; } } /// <summary> /// A memory allocation-free enumerator of <see cref="ImmutableQueue{T}"/>. /// </summary> private sealed class EnumeratorObject : IEnumerator<T> { /// <summary> /// The original queue being enumerated. /// </summary> private readonly ImmutableQueue<T> _originalQueue; /// <summary> /// The remaining forwards stack of the queue being enumerated. /// </summary> private ImmutableStack<T>? _remainingForwardsStack; /// <summary> /// The remaining backwards stack of the queue being enumerated. /// Its order is reversed when the field is first initialized. /// </summary> private ImmutableStack<T>? _remainingBackwardsStack; /// <summary> /// A value indicating whether this enumerator has been disposed. /// </summary> private bool _disposed; /// <summary> /// Initializes a new instance of the <see cref="Enumerator"/> struct. /// </summary> /// <param name="queue">The queue to enumerate.</param> internal EnumeratorObject(ImmutableQueue<T> queue) { _originalQueue = queue; } /// <summary> /// The current element. /// </summary> public T Current { get { this.ThrowIfDisposed(); if (_remainingForwardsStack == null) { // The initial call to MoveNext has not yet been made. throw new InvalidOperationException(); } if (!_remainingForwardsStack.IsEmpty) { return _remainingForwardsStack.Peek(); } else if (!_remainingBackwardsStack!.IsEmpty) { return _remainingBackwardsStack.Peek(); } else { // We've advanced beyond the end of the queue. throw new InvalidOperationException(); } } } /// <summary> /// The current element. /// </summary> object IEnumerator.Current { get { return this.Current!; } } /// <summary> /// Advances enumeration to the next element. /// </summary> /// <returns>A value indicating whether there is another element in the enumeration.</returns> public bool MoveNext() { this.ThrowIfDisposed(); if (_remainingForwardsStack == null) { // This is the initial step. // Empty queues have no forwards or backwards _remainingForwardsStack = _originalQueue._forwards; _remainingBackwardsStack = _originalQueue.BackwardsReversed; } else if (!_remainingForwardsStack.IsEmpty) { _remainingForwardsStack = _remainingForwardsStack.Pop(); } else if (!_remainingBackwardsStack!.IsEmpty) { _remainingBackwardsStack = _remainingBackwardsStack.Pop(); } return !_remainingForwardsStack.IsEmpty || !_remainingBackwardsStack!.IsEmpty; } /// <summary> /// Restarts enumeration. /// </summary> public void Reset() { this.ThrowIfDisposed(); _remainingBackwardsStack = null; _remainingForwardsStack = null; } /// <summary> /// Disposes this instance. /// </summary> public void Dispose() { _disposed = true; } /// <summary> /// Throws an <see cref="ObjectDisposedException"/> if this /// enumerator has already been disposed. /// </summary> private void ThrowIfDisposed() { if (_disposed) { Requires.FailObjectDisposed(this); } } } } }