-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reduce allocations from newline information allocated by ChangedText.…
…GetLinesCore (#74728) * Reduce allocations from newline information allocated by ChangedText.GetLinesCore. The typing scenario in the speedometer scrolling test shows this as 10% of allocations. The general idea here is that ChangedText doesn't need to keep track of line information as the SourceText that it wraps has that information. The complexity that was in ChangedText around newline splitting now needs to sit in both CompositeText and SubText as they need to understand how to expose their line collections.
- Loading branch information
Showing
5 changed files
with
419 additions
and
106 deletions.
There are no files selected for viewing
90 changes: 90 additions & 0 deletions
90
src/Compilers/Core/CodeAnalysisTest/Text/CompositeTextTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis.PooledObjects; | ||
using Microsoft.CodeAnalysis.Text; | ||
using Xunit; | ||
|
||
namespace Microsoft.CodeAnalysis.UnitTests.Text; | ||
|
||
public sealed class CompositeTextTests | ||
{ | ||
[Theory] | ||
[InlineData("abcdefghijkl")] | ||
[InlineData(["\r\r\r\r\r\r\r\r\r\r\r\r"])] | ||
[InlineData(["\n\n\n\n\n\n\n\n\n\n\n\n"])] | ||
[InlineData(["\r\n\r\n\r\n\r\n\r\n\r\n"])] | ||
[InlineData(["\n\r\n\r\n\r\n\r\n\r\n\r"])] | ||
[InlineData(["a\r\nb\r\nc\r\nd\r\n"])] | ||
[InlineData(["\ra\n\rb\n\rc\n\rd\n"])] | ||
[InlineData(["\na\r\nb\r\nc\r\nd\r"])] | ||
[InlineData(["ab\r\ncd\r\nef\r\n"])] | ||
[InlineData(["ab\r\r\ncd\r\r\nef"])] | ||
[InlineData(["ab\n\n\rcd\n\n\ref"])] | ||
[InlineData(["ab\u0085cdef\u2028ijkl\u2029op"])] | ||
[InlineData(["\u0085\u2028\u2029\u0085\u2028\u2029\u0085\u2028\u2029\u0085\u2028\u2029"])] | ||
public void CompositeTextLinesEqualSourceTextLinesPermutations(string contents) | ||
{ | ||
// Please try to limit the inputs to this method to around 12 chars or less, as much longer than that | ||
// will blow up the number of potential permutations. | ||
foreach (var (sourceText, compositeText) in CreateSourceAndCompositeTexts(contents)) | ||
{ | ||
var sourceLinesText = GetLinesTexts(sourceText.Lines); | ||
var compositeLinesText = GetLinesTexts(compositeText.Lines); | ||
|
||
Assert.True(sourceLinesText.SequenceEqual(compositeLinesText)); | ||
|
||
for (var i = 0; i < sourceText.Length; i++) | ||
{ | ||
Assert.Equal(sourceText.Lines.IndexOf(i), compositeText.Lines.IndexOf(i)); | ||
} | ||
} | ||
} | ||
|
||
private static IEnumerable<string> GetLinesTexts(TextLineCollection textLines) | ||
{ | ||
return textLines.Select(l => l.Text!.ToString(l.SpanIncludingLineBreak)); | ||
} | ||
|
||
// Returns all possible permutations of contents into SourceText arrays of length between minSourceTextCount and maxSourceTextCount | ||
private static IEnumerable<(SourceText, CompositeText)> CreateSourceAndCompositeTexts(string contents, int minSourceTextCount = 2, int maxSourceTextCount = 4) | ||
{ | ||
var sourceText = SourceText.From(contents); | ||
|
||
for (var sourceTextCount = minSourceTextCount; sourceTextCount <= Math.Min(maxSourceTextCount, contents.Length); sourceTextCount++) | ||
{ | ||
foreach (var sourceTexts in CreateSourceTextPermutations(contents, sourceTextCount)) | ||
{ | ||
var sourceTextsBuilder = ArrayBuilder<SourceText>.GetInstance(); | ||
sourceTextsBuilder.AddRange(sourceTexts); | ||
|
||
var compositeText = (CompositeText)CompositeText.ToSourceText(sourceTextsBuilder, sourceText, adjustSegments: false); | ||
yield return (sourceText, compositeText); | ||
} | ||
} | ||
} | ||
|
||
private static IEnumerable<SourceText[]> CreateSourceTextPermutations(string contents, int requestedSourceTextCount) | ||
{ | ||
if (requestedSourceTextCount == 1) | ||
{ | ||
yield return [SourceText.From(contents)]; | ||
} | ||
else | ||
{ | ||
var maximalSourceTextLength = (contents.Length - requestedSourceTextCount) + 1; | ||
for (int i = 1; i <= maximalSourceTextLength; i++) | ||
{ | ||
var sourceText = SourceText.From(contents[..i]); | ||
foreach (var otherSourceTexts in CreateSourceTextPermutations(contents.Substring(i), requestedSourceTextCount - 1)) | ||
{ | ||
yield return [sourceText, .. otherSourceTexts]; | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.