File: Operations\IOperation.OperationList.cs
Web Access
Project: src\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis)
// 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;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis
{
    public partial interface IOperation
    {
        /// <summary>
        /// Implements a struct-based collection of <see cref="Operation"/> nodes. This collection is ordered, but
        /// random access into the collection is not provided.
        /// </summary>
        [NonDefaultable]
        public readonly partial struct OperationList : IReadOnlyCollection<IOperation>
        {
            private readonly Operation _operation;
 
            internal OperationList(Operation operation)
            {
                _operation = operation;
            }
 
            public int Count => _operation.ChildOperationsCount;
 
            public Enumerator GetEnumerator() => new Enumerator(_operation);
 
            public ImmutableArray<IOperation> ToImmutableArray()
            {
                switch (_operation)
                {
                    case { ChildOperationsCount: 0 }:
                        return ImmutableArray<IOperation>.Empty;
                    case NoneOperation { Children: var children }:
                        return children;
                    case InvalidOperation { Children: var children }:
                        return children;
                    default:
                        var builder = ArrayBuilder<IOperation>.GetInstance(Count);
                        foreach (var child in this)
                        {
                            builder.Add(child);
                        }
                        return builder.ToImmutableAndFree();
                }
            }
 
            IEnumerator<IOperation> IEnumerable<IOperation>.GetEnumerator()
            {
                if (this.Count == 0)
                {
                    return SpecializedCollections.EmptyEnumerator<IOperation>();
                }
 
                return new EnumeratorImpl(new Enumerator(_operation));
            }
 
            IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<IOperation>)this).GetEnumerator();
 
            public bool Any() => Count > 0;
 
            public IOperation First()
            {
                var enumerator = GetEnumerator();
                if (enumerator.MoveNext())
                {
                    return enumerator.Current;
                }
 
                throw new InvalidOperationException();
            }
 
            public Reversed Reverse() => new Reversed(_operation);
 
            public IOperation Last()
            {
                var enumerator = Reverse().GetEnumerator();
                if (enumerator.MoveNext())
                {
                    return enumerator.Current;
                }
 
                throw new InvalidOperationException();
            }
 
            /// <summary>
            /// Implements a struct-based enumerator for <see cref="Operation"/> nodes. This type is not hardened
            /// to <code>default(Enumerator)</code>, and will null reference in these cases. Calling <see cref="Current"/> after
            /// <see cref="Enumerator.MoveNext"/> has returned false will throw an <see cref="InvalidOperationException"/>.
            /// </summary>
            [NonDefaultable]
            public struct Enumerator
            {
                /// <summary>
                /// Implementation of the <see cref="Enumerator.MoveNext"/> and <see cref="Enumerator.Current"/>
                /// members are delegated to the virtual <see cref="Operation.MoveNext(int, int)"/> and
                /// <see cref="Operation.GetCurrent(int, int)"/> methods, respectively.
                /// </summary>
                private readonly Operation _operation;
                /// <summary>
                /// 
                /// </summary>
                private int _currentSlot;
                private int _currentIndex;
 
                internal Enumerator(Operation operation)
                {
                    _operation = operation;
                    _currentSlot = -1;
                    _currentIndex = -1;
                }
 
                public IOperation Current
                {
                    get
                    {
                        Debug.Assert(_operation != null && _currentSlot >= 0 && _currentIndex >= 0);
                        return _operation.GetCurrent(_currentSlot, _currentIndex);
                    }
                }
 
                public bool MoveNext()
                {
                    bool result;
                    (result, _currentSlot, _currentIndex) = _operation.MoveNext(_currentSlot, _currentIndex);
                    return result;
                }
 
                public void Reset()
                {
                    _currentSlot = -1;
                    _currentIndex = -1;
                }
            }
 
            private sealed class EnumeratorImpl : IEnumerator<IOperation>
            {
                private Enumerator _enumerator;
 
                public EnumeratorImpl(Enumerator enumerator)
                {
                    _enumerator = enumerator;
                }
 
                public IOperation Current => _enumerator.Current;
                object? IEnumerator.Current => _enumerator.Current;
                public void Dispose() { }
                public bool MoveNext() => _enumerator.MoveNext();
                public void Reset() => _enumerator.Reset();
            }
        }
    }
}