File: Syntax\InternalSyntax\SyntaxList.WithManyChildren.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 Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Syntax.InternalSyntax
{
    internal partial class SyntaxList
    {
        internal abstract class WithManyChildrenBase : SyntaxList
        {
            internal readonly ArrayElement<GreenNode>[] children;
 
            internal WithManyChildrenBase(ArrayElement<GreenNode>[] children)
            {
                this.children = children;
                this.InitializeChildren();
            }
 
            internal WithManyChildrenBase(DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations, ArrayElement<GreenNode>[] children)
                : base(diagnostics, annotations)
            {
                this.children = children;
                this.InitializeChildren();
            }
 
            private void InitializeChildren()
            {
                int n = children.Length;
 
                // Attempt to store small lengths directly into the storage provided within GreenNode. If, however, the
                // length is too long, we will store a special value in the space, which will `SlotCount` to call back
                // into `GetSlotCount` to retrieve the true length.
                this.SlotCount = n < SlotCountTooLarge
                    ? (byte)n
                    : SlotCountTooLarge;
 
                for (int i = 0; i < children.Length; i++)
                {
                    this.AdjustFlagsAndWidth(children[i]);
                }
            }
 
            protected override int GetSlotCount()
            {
                return children.Length;
            }
 
            internal override GreenNode GetSlot(int index)
            {
                return this.children[index];
            }
 
            internal override void CopyTo(ArrayElement<GreenNode>[] array, int offset)
            {
                Array.Copy(this.children, 0, array, offset, this.children.Length);
            }
 
            internal override SyntaxNode CreateRed(SyntaxNode? parent, int position)
            {
                var separated = this.SlotCount > 1 && HasNodeTokenPattern();
                if (parent != null && parent.ShouldCreateWeakList())
                {
                    return separated
                        ? new Syntax.SyntaxList.SeparatedWithManyWeakChildren(this, parent, position)
                        : (SyntaxNode)new Syntax.SyntaxList.WithManyWeakChildren(this, parent, position);
                }
                else
                {
                    return separated
                        ? new Syntax.SyntaxList.SeparatedWithManyChildren(this, parent, position)
                        : (SyntaxNode)new Syntax.SyntaxList.WithManyChildren(this, parent, position);
                }
            }
 
            private bool HasNodeTokenPattern()
            {
                for (int i = 0; i < this.SlotCount; i++)
                {
                    // even slots must not be tokens, odds slots must be tokens
                    if (this.GetSlot(i).IsToken == ((i & 1) == 0))
                    {
                        return false;
                    }
                }
 
                return true;
            }
        }
 
        internal sealed class WithManyChildren : WithManyChildrenBase
        {
            internal WithManyChildren(ArrayElement<GreenNode>[] children)
                : base(children)
            {
            }
 
            internal WithManyChildren(DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations, ArrayElement<GreenNode>[] children)
                : base(diagnostics, annotations, children)
            {
            }
 
            internal override GreenNode SetDiagnostics(DiagnosticInfo[]? errors)
            {
                return new WithManyChildren(errors, this.GetAnnotations(), children);
            }
 
            internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations)
            {
                return new WithManyChildren(GetDiagnostics(), annotations, children);
            }
        }
    }
}