Skip to content

perf: use ValueListBuilder for PrivatePrintLeadingTrivia #1532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
10 changes: 10 additions & 0 deletions Src/CSharpier/DocTypes/Doc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ public static Doc Concat(List<Doc> contents) =>

public static Doc Concat(params Doc[] contents) => new Concat(contents);

public static Doc Concat(ref ValueListBuilder<Doc> contents)
{
return contents.Length switch
{
0 => Null,
1 => contents[0],
_ => Concat(contents.AsSpan().ToArray()),
};
}

public static Doc Join(Doc separator, IEnumerable<Doc> enumerable)
{
var docs = new List<Doc>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@ public static Doc Print(CompilationUnitSyntax node, PrintingContext context)
&& previousList.Contents[^2] is HardLine
)
{
while (list.Contents[0] is HardLine { SkipBreakIfFirstInGroup: true })
for (
var i = 0;
i < list.Contents.Count
&& list.Contents[i] is HardLine { SkipBreakIfFirstInGroup: true };
i++
)
{
list.Contents.RemoveAt(0);
list.Contents[i] = Doc.Null;
}

docs.Add(finalTrivia);
Expand Down
42 changes: 21 additions & 21 deletions Src/CSharpier/SyntaxPrinter/Token.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ private static Doc PrivatePrintLeadingTrivia(
return Doc.Null;
}

var docs = new List<Doc>();
var docs = new ValueListBuilder<Doc>([null, null, null, null, null, null, null, null]);

// we don't print any new lines until we run into a comment or directive
// the PrintExtraNewLines method takes care of printing the initial new lines for a given node
Expand All @@ -246,28 +246,28 @@ private static Doc PrivatePrintLeadingTrivia(

if (printNewLines && kind == SyntaxKind.EndOfLineTrivia)
{
if (docs.Count > 0 && docs[^1] == Doc.HardLineSkipBreakIfFirstInGroup)
if (docs.Length > 0 && docs[^1] == Doc.HardLineSkipBreakIfFirstInGroup)
{
printNewLines = false;
}

if (
!(
docs.Count > 1
docs.Length > 1
&& docs[^1] == Doc.HardLineSkipBreakIfFirstInGroup
&& docs[^2] is LeadingComment { Type: CommentType.SingleLine }
)
)
{
docs.Add(Doc.HardLineSkipBreakIfFirstInGroup);
docs.Append(Doc.HardLineSkipBreakIfFirstInGroup);
}
}
if (kind is not (SyntaxKind.EndOfLineTrivia or SyntaxKind.WhitespaceTrivia))
{
printNewLines = true;
}

void AddLeadingComment(CommentType commentType)
void AddLeadingComment(CommentType commentType, ref ValueListBuilder<Doc> docs)
{
var comment = trivia.ToFullString().TrimEnd('\n', '\r');
if (
Expand All @@ -279,43 +279,43 @@ void AddLeadingComment(CommentType commentType)
comment = leadingTrivia[x - 1] + comment;
}

docs.Add(Doc.LeadingComment(comment, commentType));
docs.Append(Doc.LeadingComment(comment, commentType));
}

if (IsSingleLineComment(kind))
{
AddLeadingComment(CommentType.SingleLine);
docs.Add(
AddLeadingComment(CommentType.SingleLine, ref docs);
docs.Append(
kind == SyntaxKind.SingleLineDocumentationCommentTrivia
? Doc.HardLineSkipBreakIfFirstInGroup
: Doc.Null
);
}
else if (IsMultiLineComment(kind))
{
AddLeadingComment(CommentType.MultiLine);
AddLeadingComment(CommentType.MultiLine, ref docs);
}
else if (kind == SyntaxKind.DisabledTextTrivia)
{
docs.Add(Doc.Trim, trivia.ToString());
docs.Append(Doc.Trim, trivia.ToString());
}
else if (IsRegion(kind))
{
var triviaText = trivia.ToString();
docs.Add(Doc.HardLineIfNoPreviousLine);
docs.Add(Doc.Trim);
docs.Add(
docs.Append(Doc.HardLineIfNoPreviousLine);
docs.Append(Doc.Trim);
docs.Append(
kind == SyntaxKind.RegionDirectiveTrivia
? Doc.BeginRegion(triviaText)
: Doc.EndRegion(triviaText)
);
docs.Add(Doc.HardLine);
docs.Append(Doc.HardLine);
}
else if (trivia.IsDirective)
{
var triviaText = trivia.ToString();

docs.Add(
docs.Append(
// adding two of these to ensure we get a new line when a directive follows a trailing comment
Doc.HardLineIfNoPreviousLineSkipBreakIfFirstInGroup,
Doc.HardLineIfNoPreviousLineSkipBreakIfFirstInGroup,
Expand All @@ -333,16 +333,16 @@ void AddLeadingComment(CommentType commentType)
)
{
x++;
docs.Add(Doc.HardLineSkipBreakIfFirstInGroup);
docs.Append(Doc.HardLineSkipBreakIfFirstInGroup);
}
printNewLines = false;
}
}
}

while (skipLastHardline && docs.Count != 0 && docs.Last() is HardLine or NullDoc)
while (skipLastHardline && docs.Length != 0 && docs[^1] is HardLine or NullDoc)
{
docs.RemoveAt(docs.Count - 1);
docs.Pop();
}

if (context.State.NextTriviaNeedsLine)
Expand All @@ -353,7 +353,7 @@ void AddLeadingComment(CommentType commentType)
}
else
{
var index = docs.Count - 1;
var index = docs.Length - 1;
while (
index >= 0
&& (docs[index] is HardLine or LeadingComment || docs[index] == Doc.Null)
Expand All @@ -364,7 +364,7 @@ void AddLeadingComment(CommentType commentType)
// this handles an edge case where we get here but already added the line
// it relates to the fact that single line comments include new line directives
if (
index + 2 >= docs.Count
index + 2 >= docs.Length
|| !(docs[index + 1] is HardLine && docs[index + 2] is HardLine)
)
{
Expand All @@ -374,7 +374,7 @@ void AddLeadingComment(CommentType commentType)
context.State.NextTriviaNeedsLine = false;
}

return docs.Count > 0 ? Doc.Concat(docs) : Doc.Null;
return Doc.Concat(ref docs);
}

private static bool IsSingleLineComment(SyntaxKind kind) =>
Expand Down
22 changes: 14 additions & 8 deletions Src/CSharpier/Utilities/ValueListBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,17 @@ private void AppendMultiChar(scoped ReadOnlySpan<T> source)
_pos += source.Length;
}

public void Insert(int index, scoped ReadOnlySpan<T> source)
public void Insert(int index, T item)
{
Debug.Assert(index == 0, "Implementation currently only supports index == 0");

if ((uint)(_pos + source.Length) > (uint)_span.Length)
int pos = _pos;
if ((uint)pos >= (uint)_span.Length)
{
Grow(source.Length);
Grow(1);
}

_span.Slice(0, _pos).CopyTo(_span.Slice(source.Length));
source.CopyTo(_span);
_pos += source.Length;
_span.Slice(index, _pos - index).CopyTo(_span.Slice(index + 1));
_span[index] = item;
_pos += 1;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down Expand Up @@ -141,6 +140,13 @@ private void AddWithResize(T item)
_pos = pos + 1;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Pop()
{
_pos--;
return _span[_pos];
}

public ReadOnlySpan<T> AsSpan()
{
return _span.Slice(0, _pos);
Expand Down