File: Language\Intermediate\IntermediateNodeWalker.Stack.cs
Web Access
Project: src\src\Razor\src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj (Microsoft.CodeAnalysis.Razor.Compiler)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
 
namespace Microsoft.AspNetCore.Razor.Language.Intermediate;
 
public abstract partial class IntermediateNodeWalker
{
    /// <summary>
    ///  Simple stack implementation that fills an array from end-to-start
    ///  to keep the items in the reverse order they were pushed. This ensures
    ///  that they are in the correct order to implement the <see cref="Ancestors"/>
    ///  property.
    /// </summary>
    private struct Stack
    {
        private const int InitialStackSize = 4;
 
        private IntermediateNode[]? _stack;
        private int _stackPointer;
 
        [MemberNotNullWhen(false, nameof(_stack))]
        public readonly bool IsEmpty
            => _stack is null || _stackPointer == _stack.Length;
 
        public readonly ReadOnlySpan<IntermediateNode> Span
            => IsEmpty
                ? ReadOnlySpan<IntermediateNode>.Empty
                : _stack.AsSpan()[_stackPointer..];
 
        public void Push(IntermediateNode node)
        {
            if (_stack is null || _stackPointer == 0)
            {
                Grow();
            }
 
            _stack[--_stackPointer] = node;
        }
 
        public void Pop()
        {
            Debug.Assert(!IsEmpty);
 
            _stack[_stackPointer++] = null!;
        }
 
        [MemberNotNull(nameof(_stack))]
        private void Grow()
        {
            // If we haven't initialized the stack, do so and set the stack pointer.
            if (_stack == null)
            {
                _stack = new IntermediateNode[InitialStackSize];
                _stackPointer = _stack.Length;
                return;
            }
 
            // Otherwise, double the size of the stack and copy the contents over.
 
            Debug.Assert(_stackPointer == 0, "We should only grow the ancestor stack when the stack pointer reaches 0.");
 
            var length = _stack.Length;
            var newStack = new IntermediateNode[length * 2];
 
            _stack.CopyTo(newStack, length);
 
            _stackPointer = length;
            _stack = newStack;
        }
    }
}