Skip to content

Commit

Permalink
Change Slot lookup to use BinarySearchUpperBound
Browse files Browse the repository at this point in the history
  • Loading branch information
mattwar committed Feb 23, 2015
1 parent 3799cae commit b106d3d
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,7 @@ public override int GetSlotOffset(int index)
public override int FindSlotIndexContainingOffset(int offset)
{
Debug.Assert(offset >= 0 && offset < FullWidth);
int idx = _childOffsets.BinarySearch(offset);

if (idx < 0)
{
idx = (~idx - 1);
}

// skip zero-length nodes (they won't ever contain the offset)
while (idx < _childOffsets.Length - 1 && _childOffsets[idx] == _childOffsets[idx + 1])
{
idx++;
}

return idx;
return _childOffsets.BinarySearchUpperBound(offset) - 1;
}

private static int[] CalculateOffsets(ArrayElement<CSharpSyntaxNode>[] children)
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ public void TestFindTokenInLargeList()

private void CheckFindToken(SyntaxNode node)
{
for (int i = node.FullSpan.End - 1; i >= 0; i--)
for (int i = 0; i < node.FullSpan.End; i++)
{
var token = node.FindToken(i);
Assert.Equal(true, token.FullSpan.Contains(i));
Expand Down
30 changes: 30 additions & 0 deletions src/Compilers/Core/Portable/InternalUtilities/ArrayExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,5 +173,35 @@ internal static int BinarySearch(this int[] array, int value)

return ~low;
}

/// <summary>
/// Search a sorted integer array for the target value in O(log N) time.
/// </summary>
/// <param name="array">The array of integers which must be sorted in ascending order.</param>
/// <param name="value">The target value.</param>
/// <returns>An index in the array pointing to the position where <paramref name="value"/> should be
/// inserted in order to maintain the sorted order. All values to the right of this position will be
/// strictly greater than <paramref name="value"/>. Note that this may return a position off the end
/// of the array if all elements are less than or equal to <paramref name="value"/>.</returns>
internal static int BinarySearchUpperBound(this int[] array, int value)
{
int low = 0;
int high = array.Length - 1;

while (low <= high)
{
int middle = low + ((high - low) >> 1);
if (array[middle] > value)
{
high = middle - 1;
}
else
{
low = middle + 1;
}
}

return low;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
''' </remarks>
Public Overrides Function FindSlotIndexContainingOffset(offset As Integer) As Integer
Debug.Assert(offset >= 0 AndAlso offset < FullWidth)
Dim idx = _childOffsets.BinarySearch(offset)
Return If(idx >= 0, idx, (Not idx) - 1)
Return _childOffsets.BinarySearchUpperBound(offset) - 1
End Function

Friend Overrides Function SetDiagnostics(errors() As DiagnosticInfo) As GreenNode
Expand Down
35 changes: 35 additions & 0 deletions src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb
Original file line number Diff line number Diff line change
Expand Up @@ -2114,6 +2114,41 @@ End Class]]>
Assert.Throws(Of ArgumentOutOfRangeException)(Sub() classDecl.FindNode(root.FullSpan))
End Sub

<Fact>
Public Sub TestFindTokenInLargeList()
Dim identifier = SyntaxFactory.Identifier("x")
Dim missingIdentifier = SyntaxFactory.MissingToken(SyntaxKind.IdentifierToken)
Dim name = SyntaxFactory.IdentifierName(identifier)
Dim missingName = SyntaxFactory.IdentifierName(missingIdentifier)
Dim comma = SyntaxFactory.Token(SyntaxKind.CommaToken)
Dim missingComma = SyntaxFactory.MissingToken(SyntaxKind.CommaToken)
Dim argument = SyntaxFactory.SimpleArgument(name)
Dim missingArgument = SyntaxFactory.SimpleArgument(missingName)

'' make a large list that has lots of zero-length nodes (that shouldn't be found)
Dim nodesAndTokens = SyntaxFactory.NodeOrTokenList(
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
argument)

Dim argumentList = SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(Of ArgumentSyntax)(SyntaxFactory.NodeOrTokenList(nodesAndTokens)))
Dim invocation = SyntaxFactory.InvocationExpression(name, argumentList)
CheckFindToken(invocation)
End Sub

Private Sub CheckFindToken(node As SyntaxNode)
For i As Integer = 1 To node.FullSpan.End - 1
Dim token = node.FindToken(i)
Assert.Equal(True, token.FullSpan.Contains(i))
Next
End Sub

<WorkItem(539940, "DevDiv")>
<Fact>
Public Sub TestFindTriviaNoTriviaExistsAtPosition()
Expand Down

0 comments on commit b106d3d

Please sign in to comment.