Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using System.Threading;

namespace Microsoft.AspNetCore.Razor;

internal static class InterlockedOperations
{
public static T Initialize<T>([NotNull] ref T? target, T value) where T : class
{
return Interlocked.CompareExchange(ref target, value, null) ?? value;
}
}
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);
}
}
}
}
Loading