Skip to content

Commit

Permalink
Use more efficient stack for FlattenSpansInReverse
Browse files Browse the repository at this point in the history
  • Loading branch information
DustinCampbell committed Feb 9, 2023
1 parent 63a4cfa commit 4e3fc99
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// 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.CodeAnalysis;
using Microsoft.AspNetCore.Razor.Language.Syntax;

namespace Microsoft.AspNetCore.Razor.Language.Legacy;

internal static partial class LegacySyntaxNodeExtensions
{
/// <summary>
/// This is similar to <see cref="SyntaxNode.ChildSyntaxListEnumeratorStack"/>.
/// However, instead of enumerating descendant nodes in a top-down, left-to-right
/// fashion, the process is reversed; it operates right-to-left and bottom-up.
/// </summary>
private struct ChildSyntaxListReversedEnumeratorStack : IDisposable
{
private const int MaxArraySize = 256;

private static readonly ObjectPool<ChildSyntaxList.Reversed.Enumerator[]> s_stackPool = new(() => new ChildSyntaxList.Reversed.Enumerator[16]);

private ChildSyntaxList.Reversed.Enumerator[] _stack;
private int _stackPtr;

public ChildSyntaxListReversedEnumeratorStack(SyntaxNode node)
{
_stack = s_stackPool.Allocate();
_stackPtr = -1;

PushRightmostChildren(node);
}

private void PushRightmostChildren(SyntaxNode node)
{
var current = node;
do
{
var children = current.ChildNodes();
if (children.Count == 0)
{
break;
}

if (++_stackPtr == _stack.Length)
{
Array.Resize(ref _stack, _stack.Length * 2);
}

_stack[_stackPtr] = children.Reverse().GetEnumerator();

current = children.Last();
}
while (current is not null);
}

private bool TryMoveNextAndGetCurrent([NotNullWhen(true)] out SyntaxNode? node)
{
if (_stackPtr < 0)
{
node = null;
return false;
}

ref var enumerator = ref _stack[_stackPtr];

if (!enumerator.MoveNext())
{
node = null;
return false;
}

node = enumerator.Current;
return true;
}

public bool TryGetNextNode([NotNullWhen(true)] out SyntaxNode? node)
{
while (!TryMoveNextAndGetCurrent(out node))
{
_stackPtr--;

if (_stackPtr < 0)
{
node = null;
return false;
}
}

PushRightmostChildren(node);
return true;
}

public bool IsEmpty
=> _stackPtr < 0;

public void Dispose()
{
// Return only reasonably-sized stacks to the pool.
if (_stack.Length < MaxArraySize)
{
Array.Clear(_stack, 0, _stack.Length);
s_stackPool.Free(_stack);
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,11 @@ public static bool IsSpanKind(this SyntaxNode node)

private static IEnumerable<SyntaxNode> FlattenSpansInReverse(this SyntaxNode node)
{
using var stack = new NodeStack(node.DescendantNodes());
using var stack = new ChildSyntaxListReversedEnumeratorStack(node);

// Iterate through stack.
while (!stack.IsEmpty)
while (stack.TryGetNextNode(out var nextNode))
{
var child = stack.Pop();

if (child is MarkupStartTagSyntax startTag)
if (nextNode is MarkupStartTagSyntax startTag)
{
var children = startTag.Children;

Expand All @@ -262,7 +259,7 @@ private static IEnumerable<SyntaxNode> FlattenSpansInReverse(this SyntaxNode nod
}
}
}
else if (child is MarkupEndTagSyntax endTag)
else if (nextNode is MarkupEndTagSyntax endTag)
{
var children = endTag.Children;

Expand All @@ -275,9 +272,9 @@ private static IEnumerable<SyntaxNode> FlattenSpansInReverse(this SyntaxNode nod
}
}
}
else if (child.IsSpanKind())
else if (nextNode.IsSpanKind())
{
yield return child;
yield return nextNode;
}
}
}
Expand Down

0 comments on commit 4e3fc99

Please sign in to comment.