File: System\Collections\Immutable\ImmutableStack_1.Enumerator.cs
Web Access
Project: src\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 ImmutableStack<T>
    {
        /// <summary>
        /// Enumerates a stack with no memory allocations.
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public struct Enumerator
        {
            /// <summary>
            /// The original stack being enumerated.
            /// </summary>
            private readonly ImmutableStack<T> _originalStack;
 
            /// <summary>
            /// The remaining stack not yet enumerated.
            /// </summary>
            private ImmutableStack<T>? _remainingStack;
 
            /// <summary>
            /// Initializes a new instance of the <see cref="Enumerator"/> struct.
            /// </summary>
            /// <param name="stack">The stack to enumerator.</param>
            internal Enumerator(ImmutableStack<T> stack)
            {
                Requires.NotNull(stack, nameof(stack));
                _originalStack = stack;
                _remainingStack = null;
            }
 
            /// <summary>
            /// Gets the current element.
            /// </summary>
            public T Current
            {
                get
                {
                    if (_remainingStack == null || _remainingStack.IsEmpty)
                    {
                        throw new InvalidOperationException();
                    }
                    else
                    {
                        return _remainingStack.Peek();
                    }
                }
            }
 
            /// <summary>
            /// Moves to the first or next element.
            /// </summary>
            /// <returns>A value indicating whether there are any more elements.</returns>
            public bool MoveNext()
            {
                if (_remainingStack == null)
                {
                    // initial move
                    _remainingStack = _originalStack;
                }
                else if (!_remainingStack.IsEmpty)
                {
                    _remainingStack = _remainingStack.Pop();
                }
 
                return !_remainingStack.IsEmpty;
            }
        }
 
        /// <summary>
        /// Enumerates a stack with no memory allocations.
        /// </summary>
        private sealed class EnumeratorObject : IEnumerator<T>
        {
            /// <summary>
            /// The original stack being enumerated.
            /// </summary>
            private readonly ImmutableStack<T> _originalStack;
 
            /// <summary>
            /// The remaining stack not yet enumerated.
            /// </summary>
            private ImmutableStack<T>? _remainingStack;
 
            /// <summary>
            /// A flag indicating whether this enumerator has been disposed.
            /// </summary>
            private bool _disposed;
 
            /// <summary>
            /// Initializes a new instance of the <see cref="EnumeratorObject"/> class.
            /// </summary>
            /// <param name="stack">The stack to enumerator.</param>
            internal EnumeratorObject(ImmutableStack<T> stack)
            {
                Requires.NotNull(stack, nameof(stack));
                _originalStack = stack;
            }
 
            /// <summary>
            /// Gets the current element.
            /// </summary>
            public T Current
            {
                get
                {
                    this.ThrowIfDisposed();
                    if (_remainingStack == null || _remainingStack.IsEmpty)
                    {
                        throw new InvalidOperationException();
                    }
                    else
                    {
                        return _remainingStack.Peek();
                    }
                }
            }
 
            /// <summary>
            /// Gets the current element.
            /// </summary>
            object? IEnumerator.Current
            {
                get { return this.Current; }
            }
 
            /// <summary>
            /// Moves to the first or next element.
            /// </summary>
            /// <returns>A value indicating whether there are any more elements.</returns>
            public bool MoveNext()
            {
                this.ThrowIfDisposed();
 
                if (_remainingStack == null)
                {
                    // initial move
                    _remainingStack = _originalStack;
                }
                else if (!_remainingStack.IsEmpty)
                {
                    _remainingStack = _remainingStack.Pop();
                }
 
                return !_remainingStack.IsEmpty;
            }
 
            /// <summary>
            /// Resets the position to just before the first element in the list.
            /// </summary>
            public void Reset()
            {
                this.ThrowIfDisposed();
                _remainingStack = 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);
                }
            }
        }
    }
}