Skip to content

Commit f1d6ec1

Browse files
Use more efficient stack for FlattenSpansInReverse
1 parent 8db435e commit f1d6ec1

File tree

3 files changed

+113
-60
lines changed

3 files changed

+113
-60
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Diagnostics.CodeAnalysis;
6+
using Microsoft.AspNetCore.Razor.Language.Syntax;
7+
8+
namespace Microsoft.AspNetCore.Razor.Language.Legacy;
9+
10+
internal static partial class LegacySyntaxNodeExtensions
11+
{
12+
/// <summary>
13+
/// This is similar to <see cref="SyntaxNode.ChildSyntaxListEnumeratorStack"/>.
14+
/// However, instead of enumerating descendant nodes in a top-down, left-to-right
15+
/// fashion, the process is reversed; it operates right-to-left and bottom-up.
16+
/// </summary>
17+
private struct ChildSyntaxListReversedEnumeratorStack : IDisposable
18+
{
19+
private const int MaxArraySize = 256;
20+
21+
private static readonly ObjectPool<ChildSyntaxList.Reversed.Enumerator[]> s_stackPool = new(() => new ChildSyntaxList.Reversed.Enumerator[16]);
22+
23+
private ChildSyntaxList.Reversed.Enumerator[] _stack;
24+
private int _stackPtr;
25+
26+
public ChildSyntaxListReversedEnumeratorStack(SyntaxNode node)
27+
{
28+
_stack = s_stackPool.Allocate();
29+
_stackPtr = -1;
30+
31+
PushRightmostChildren(node);
32+
}
33+
34+
private void PushRightmostChildren(SyntaxNode node)
35+
{
36+
var current = node;
37+
do
38+
{
39+
var children = current.ChildNodes();
40+
if (children.Count == 0)
41+
{
42+
break;
43+
}
44+
45+
if (++_stackPtr == _stack.Length)
46+
{
47+
Array.Resize(ref _stack, _stack.Length * 2);
48+
}
49+
50+
_stack[_stackPtr] = children.Reverse().GetEnumerator();
51+
52+
current = children.Last();
53+
}
54+
while (current is not null);
55+
}
56+
57+
private bool TryMoveNextAndGetCurrent([NotNullWhen(true)] out SyntaxNode? node)
58+
{
59+
if (_stackPtr < 0)
60+
{
61+
node = null;
62+
return false;
63+
}
64+
65+
ref var enumerator = ref _stack[_stackPtr];
66+
67+
if (!enumerator.MoveNext())
68+
{
69+
node = null;
70+
return false;
71+
}
72+
73+
node = enumerator.Current;
74+
return true;
75+
}
76+
77+
public bool TryGetNextNode([NotNullWhen(true)] out SyntaxNode? node)
78+
{
79+
while (!TryMoveNextAndGetCurrent(out node))
80+
{
81+
_stackPtr--;
82+
83+
if (_stackPtr < 0)
84+
{
85+
node = null;
86+
return false;
87+
}
88+
}
89+
90+
PushRightmostChildren(node);
91+
return true;
92+
}
93+
94+
public bool IsEmpty
95+
=> _stackPtr < 0;
96+
97+
public void Dispose()
98+
{
99+
// Return only reasonably-sized stacks to the pool.
100+
if (_stack.Length < MaxArraySize)
101+
{
102+
Array.Clear(_stack, 0, _stack.Length);
103+
s_stackPool.Free(_stack);
104+
}
105+
}
106+
}
107+
}

src/Compiler/Microsoft.AspNetCore.Razor.Language/src/Legacy/LegacySyntaxNodeExtensions.NodeStack.cs

Lines changed: 0 additions & 51 deletions
This file was deleted.

src/Compiler/Microsoft.AspNetCore.Razor.Language/src/Legacy/LegacySyntaxNodeExtensions.cs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,11 @@ public static bool IsSpanKind(this SyntaxNode node)
242242

243243
private static IEnumerable<SyntaxNode> FlattenSpansInReverse(this SyntaxNode node)
244244
{
245-
using var stack = new NodeStack(node.DescendantNodes());
245+
using var stack = new ChildSyntaxListReversedEnumeratorStack(node);
246246

247-
// Iterate through stack.
248-
while (!stack.IsEmpty)
247+
while (stack.TryGetNextNode(out var nextNode))
249248
{
250-
var child = stack.Pop();
251-
252-
if (child is MarkupStartTagSyntax startTag)
249+
if (nextNode is MarkupStartTagSyntax startTag)
253250
{
254251
var children = startTag.Children;
255252

@@ -262,7 +259,7 @@ private static IEnumerable<SyntaxNode> FlattenSpansInReverse(this SyntaxNode nod
262259
}
263260
}
264261
}
265-
else if (child is MarkupEndTagSyntax endTag)
262+
else if (nextNode is MarkupEndTagSyntax endTag)
266263
{
267264
var children = endTag.Children;
268265

@@ -275,9 +272,9 @@ private static IEnumerable<SyntaxNode> FlattenSpansInReverse(this SyntaxNode nod
275272
}
276273
}
277274
}
278-
else if (child.IsSpanKind())
275+
else if (nextNode.IsSpanKind())
279276
{
280-
yield return child;
277+
yield return nextNode;
281278
}
282279
}
283280
}

0 commit comments

Comments
 (0)