Skip to content

Commit

Permalink
Use segmented arrays for VirtualChar storage
Browse files Browse the repository at this point in the history
  • Loading branch information
sharwell committed Feb 23, 2022
1 parent 587388c commit e6d73d1
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Collections;

#if DEBUG
using System.Linq;
Expand Down Expand Up @@ -862,5 +863,33 @@ internal static int BinarySearch<TElement, TValue>(this ReadOnlySpan<TElement> a

return ~low;
}

internal static int BinarySearch<TElement, TValue>(this ImmutableSegmentedList<TElement> array, TValue value, Func<TElement, TValue, int> comparer)
{
int low = 0;
int high = array.Count - 1;

while (low <= high)
{
int middle = low + ((high - low) >> 1);
int comparison = comparer(array[middle], value);

if (comparison == 0)
{
return middle;
}

if (comparison > 0)
{
high = middle - 1;
}
else
{
low = middle + 1;
}
}

return ~low;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System.Diagnostics;
using System.Text;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.LanguageServices;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars;
Expand Down Expand Up @@ -102,7 +103,7 @@ private static VirtualCharSequence TryConvertRawStringToVirtualChars(
var tokenText = token.Text;
var offset = token.SpanStart;

using var _ = ArrayBuilder<VirtualChar>.GetInstance(out var result);
var result = ImmutableSegmentedList.CreateBuilder<VirtualChar>();

var startIndexInclusive = 0;
var endIndexExclusive = tokenText.Length;
Expand Down Expand Up @@ -186,14 +187,14 @@ private static VirtualCharSequence CreateVirtualCharSequence(
string tokenText, int offset, int startIndexInclusive, int endIndexExclusive, ArrayBuilder<(char ch, TextSpan span)> charResults)
{
// Second pass. Convert those characters to Runes.
using var _ = ArrayBuilder<VirtualChar>.GetInstance(out var runeResults);
var runeResults = ImmutableSegmentedList.CreateBuilder<VirtualChar>();

ConvertCharactersToRunes(charResults, runeResults);

return CreateVirtualCharSequence(tokenText, offset, startIndexInclusive, endIndexExclusive, runeResults);
}

private static void ConvertCharactersToRunes(ArrayBuilder<(char ch, TextSpan span)> charResults, ArrayBuilder<VirtualChar> runeResults)
private static void ConvertCharactersToRunes(ArrayBuilder<(char ch, TextSpan span)> charResults, ImmutableSegmentedList<VirtualChar>.Builder runeResults)
{
for (var i = 0; i < charResults.Count;)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Diagnostics;
using System.Text;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Text;
Expand Down Expand Up @@ -147,7 +148,7 @@ protected static VirtualCharSequence TryConvertSimpleDoubleQuoteString(
var startIndexInclusive = startDelimiter.Length;
var endIndexExclusive = tokenText.Length - endDelimiter.Length;

using var _ = ArrayBuilder<VirtualChar>.GetInstance(out var result);
var result = ImmutableSegmentedList.CreateBuilder<VirtualChar>();
var offset = token.SpanStart;

for (var index = startIndexInclusive; index < endIndexExclusive;)
Expand All @@ -164,7 +165,7 @@ protected static VirtualCharSequence TryConvertSimpleDoubleQuoteString(
return default;

result.Add(VirtualChar.Create(new Rune(tokenText[index]), span));
index += result.Last().Span.Length;
index += result[^1].Span.Length;
continue;
}

Expand All @@ -178,7 +179,7 @@ protected static VirtualCharSequence TryConvertSimpleDoubleQuoteString(
/// <summary>
/// Returns the number of characters to jump forward (either 1 or 2);
/// </summary>
protected static int ConvertTextAtIndexToRune(string tokenText, int index, ArrayBuilder<VirtualChar> result, int offset)
protected static int ConvertTextAtIndexToRune(string tokenText, int index, ImmutableSegmentedList<VirtualChar>.Builder result, int offset)
{
if (Rune.TryCreate(tokenText[index], out var rune))
{
Expand Down Expand Up @@ -208,7 +209,7 @@ protected static bool IsOpenOrCloseBrace(char ch)
protected static VirtualCharSequence CreateVirtualCharSequence(
string tokenText, int offset,
int startIndexInclusive, int endIndexExclusive,
ArrayBuilder<VirtualChar> result)
ImmutableSegmentedList<VirtualChar>.Builder result)
{
// Check if we actually needed to create any special virtual chars.
// if not, we can avoid the entire array allocation and just wrap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Text;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars
Expand All @@ -29,23 +30,23 @@ protected Chunk()
}

/// <summary>
/// Thin wrapper over an actual <see cref="ImmutableArray{VirtualChar}"/>.
/// Thin wrapper over an actual <see cref="ImmutableSegmentedList{T}"/>.
/// This will be the common construct we generate when getting the
/// <see cref="Chunk"/> for a string token that has escapes in it.
/// </summary>
private class ImmutableArrayChunk : Chunk
private class ImmutableSegmentedListChunk : Chunk
{
private readonly ImmutableArray<VirtualChar> _array;
private readonly ImmutableSegmentedList<VirtualChar> _array;

public ImmutableArrayChunk(ImmutableArray<VirtualChar> array)
public ImmutableSegmentedListChunk(ImmutableSegmentedList<VirtualChar> array)
=> _array = array;

public override int Length => _array.Length;
public override int Length => _array.Count;
public override VirtualChar this[int index] => _array[index];

public override VirtualChar? Find(int position)
{
if (_array.Length == 0)
if (_array.IsEmpty)
return null;

if (position < _array[0].Span.Start || position >= _array[^1].Span.End)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Text;

Expand All @@ -27,10 +28,10 @@ namespace Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars
/// </summary>
internal partial struct VirtualCharSequence
{
public static readonly VirtualCharSequence Empty = Create(ImmutableArray<VirtualChar>.Empty);
public static readonly VirtualCharSequence Empty = Create(ImmutableSegmentedList<VirtualChar>.Empty);

public static VirtualCharSequence Create(ImmutableArray<VirtualChar> virtualChars)
=> new(new ImmutableArrayChunk(virtualChars));
public static VirtualCharSequence Create(ImmutableSegmentedList<VirtualChar> virtualChars)
=> new(new ImmutableSegmentedListChunk(virtualChars));

public static VirtualCharSequence Create(int firstVirtualCharPosition, string underlyingData)
=> new(new StringChunk(firstVirtualCharPosition, underlyingData));
Expand Down

0 comments on commit e6d73d1

Please sign in to comment.