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
Expand Up @@ -16,12 +16,14 @@ public struct Enumerator
private SyntaxNode _node;
private int _count;
private int _childIndex;
private SlotData _slotData;

internal Enumerator(SyntaxNode node, int count)
{
_node = node;
_count = count;
_childIndex = -1;
_slotData = new SlotData(node);
}

// PERF: Initialize an Enumerator directly from a SyntaxNode without going
Expand All @@ -31,6 +33,7 @@ internal void InitializeFrom(SyntaxNode node)
_node = node;
_count = CountNodes(node.Green);
_childIndex = -1;
_slotData = new SlotData(node);
}

/// <summary>
Expand Down Expand Up @@ -58,8 +61,8 @@ public bool MoveNext()
/// <returns>
/// The element in the <see cref="ChildSyntaxList" /> at the current position of the enumerator.
/// </returns>
public readonly SyntaxNodeOrToken Current
=> ItemInternal(_node, _childIndex);
public SyntaxNodeOrToken Current
=> ItemInternal(_node, _childIndex, ref _slotData);

/// <summary>
/// Sets the enumerator to its initial position, which is before the first element in the collection.
Expand All @@ -77,15 +80,15 @@ internal bool TryMoveNextAndGetCurrent(out SyntaxNodeOrToken current)
return false;
}

current = ItemInternal(_node, _childIndex);
current = ItemInternal(_node, _childIndex, ref _slotData);
return true;
}

internal SyntaxNode? TryMoveNextAndGetCurrentAsNode()
{
while (MoveNext())
{
var nodeValue = ItemInternalAsNode(_node, _childIndex);
var nodeValue = ItemInternalAsNode(_node, _childIndex, ref _slotData);
if (nodeValue != null)
{
return nodeValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,60 @@ private static int Occupancy(GreenNode green)
return green.IsList ? green.SlotCount : 1;
}

internal readonly struct SlotData
{
/// <summary>
/// The green node slot index at which to start the search
/// </summary>
public readonly int SlotIndex;

/// <summary>
/// Indicates the total number of occupants in preceding slots
/// </summary>
public readonly int PrecedingOccupantSlotCount;

/// <summary>
/// Indicates the node start position plus any prior slot full widths
/// </summary>
public readonly int PositionAtSlotIndex;

public SlotData(SyntaxNode node)
: this(slotIndex: 0, precedingOccupantSlotCount: 0, node.Position)
{
}

public SlotData(int slotIndex, int precedingOccupantSlotCount, int positionAtSlotIndex)
{
SlotIndex = slotIndex;
PrecedingOccupantSlotCount = precedingOccupantSlotCount;
PositionAtSlotIndex = positionAtSlotIndex;
}
}

internal static SyntaxNodeOrToken ItemInternal(SyntaxNode node, int index)
{
var slotData = new SlotData(node);

return ItemInternal(node, index, ref slotData);
}

/// <summary>
/// An internal indexer that does not verify index.
/// Used when caller has already ensured that index is within bounds.
/// </summary>
internal static SyntaxNodeOrToken ItemInternal(SyntaxNode node, int index)
internal static SyntaxNodeOrToken ItemInternal(SyntaxNode node, int index, ref SlotData slotData)
{
GreenNode greenChild;
var green = node.Green;
var idx = index;
var slotIndex = 0;
var position = node.Position;

// slotData may contain information that allows us to start the loop below using data
// calculated during a previous call. As index represents the offset into all children of
// node, idx represents the offset requested relative to the given slot index.
var idx = index - slotData.PrecedingOccupantSlotCount;
var slotIndex = slotData.SlotIndex;
var position = slotData.PositionAtSlotIndex;

Debug.Assert(idx >= 0);

// find a slot that contains the node or its parent list (if node is in a list)
// we will be skipping whole slots here so we will not loop for long
Expand All @@ -112,6 +155,12 @@ internal static SyntaxNodeOrToken ItemInternal(SyntaxNode node, int index)
slotIndex++;
}

if (slotIndex != slotData.SlotIndex)
{
// (index - idx) represents the number of occupants prior to this new slotIndex
slotData = new SlotData(slotIndex, index - idx, position);
}

// get node that represents this slot
var red = node.GetNodeSlot(slotIndex);
if (!greenChild.IsList)
Expand All @@ -132,6 +181,7 @@ internal static SyntaxNodeOrToken ItemInternal(SyntaxNode node, int index)
// this is our node
return redChild;
}

// must be a separator
// update greenChild and position and let it be handled as a token
greenChild = greenChild.GetSlot(idx);
Expand Down Expand Up @@ -237,12 +287,15 @@ internal static SyntaxNodeOrToken ChildThatContainsPosition(SyntaxNode node, int
/// An internal indexer that does not verify index.
/// Used when caller has already ensured that index is within bounds.
/// </summary>
internal static SyntaxNode? ItemInternalAsNode(SyntaxNode node, int index)
internal static SyntaxNode? ItemInternalAsNode(SyntaxNode node, int index, ref SlotData slotData)
{
GreenNode greenChild;
var green = node.Green;
var idx = index;
var slotIndex = 0;
var idx = index - slotData.PrecedingOccupantSlotCount;
var slotIndex = slotData.SlotIndex;
var position = slotData.PositionAtSlotIndex;

Debug.Assert(idx >= 0);

// find a slot that contains the node or its parent list (if node is in a list)
// we will be skipping whole slots here so we will not loop for long
Expand All @@ -262,11 +315,18 @@ internal static SyntaxNodeOrToken ChildThatContainsPosition(SyntaxNode node, int
}

idx -= currentOccupancy;
position += greenChild.Width;
}

slotIndex++;
}

if (slotIndex != slotData.SlotIndex)
{
// (index - idx) represents the number of occupants prior to this new slotIndex
slotData = new SlotData(slotIndex, index - idx, position);
}

// get node that represents this slot
var red = node.GetNodeSlot(slotIndex);
if (greenChild.IsList && red != null)
Expand Down
Loading