Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
@@ -0,0 +1,91 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;

namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration;

public sealed partial class CodeWriter
{
private sealed class IndentCache
{
private const int MaxCachedIndentSize = 80;

// Caches for combination of common tab sizes (2, 4) and the _useTabs bool
private static readonly IndentCache?[] s_caches = new IndentCache?[4];

private readonly ReadOnlyMemory<char>?[] _indents;
private readonly bool _useTabs;
private readonly int _tabSize;
Comment thread
ToddGrun marked this conversation as resolved.
Outdated

private IndentCache(bool useTabs, int tabSize)
{
_useTabs = useTabs;
_tabSize = tabSize;

_indents = new ReadOnlyMemory<char>?[MaxCachedIndentSize + 1];
}

public static ReadOnlyMemory<char> GetIndentString(int size, bool useTabs, int tabSize)
{
var cacheIndex = tabSize switch
{
2 => useTabs ? 0 : 1,
4 => useTabs ? 2 : 3,
_ => -1,
};

// Only cache common tab sizes and small indents
if (cacheIndex == -1 || size > MaxCachedIndentSize)
{
return CreateIndent(size, useTabs, tabSize);
}

if (s_caches[cacheIndex] is not IndentCache indentCache)
{
indentCache = new IndentCache(useTabs, tabSize);
s_caches[cacheIndex] = indentCache;
}

return indentCache.GetOrCacheIndent(size);
}

private ReadOnlyMemory<char> GetOrCacheIndent(int size)
{
if (_indents[size] is not ReadOnlyMemory<char> cachedIndent)
{
cachedIndent = CreateIndent(size, _useTabs, _tabSize);
_indents[size] = cachedIndent;
}

return cachedIndent;
}

private static ReadOnlyMemory<char> CreateIndent(int size, bool useTabs, int tabSize)
{
if (useTabs)
{
var tabCount = size / tabSize;
var spaceCount = size % tabSize;

return string.Create(tabCount + spaceCount, (tabCount, spaceCount), static (destination, state) =>
Comment thread
ToddGrun marked this conversation as resolved.
Outdated
{
var (tabCount, spaceCount) = state;
var index = 0;

for (var i = 0; i < tabCount; i++)
{
destination[index++] = '\t';
}

for (var i = 0; i < spaceCount; i++)
{
destination[index++] = ' ';
}
}).AsMemory();
}

return new string(' ', size).AsMemory();
}
}
Comment thread
ToddGrun marked this conversation as resolved.
Outdated
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration;
Expand Down Expand Up @@ -118,7 +117,7 @@ public int CurrentIndent
if (_indentSize != value)
{
_indentSize = value;
_indentString = ComputeIndent(value, IndentWithTabs, TabSize);
_indentString = IndentCache.GetIndentString(value, IndentWithTabs, TabSize);
}
}
}
Expand Down Expand Up @@ -189,7 +188,7 @@ public CodeWriter Indent(int size)

var indentString = size == _indentSize
? _indentString
: ComputeIndent(size, IndentWithTabs, TabSize);
: IndentCache.GetIndentString(size, IndentWithTabs, TabSize);

AddTextChunk(indentString);

Expand All @@ -200,30 +199,6 @@ public CodeWriter Indent(int size)
return this;
}

private static ReadOnlyMemory<char> ComputeIndent(int size, bool useTabs, int tabSize)
{
if (size == 0)
{
return ReadOnlyMemory<char>.Empty;
}

if (useTabs)
{
var tabCount = size / tabSize;
var spaceCount = size % tabSize;

using var _ = StringBuilderPool.GetPooledObject(out var builder);
builder.SetCapacityIfLarger(tabCount + spaceCount);

builder.Append('\t', tabCount);
builder.Append(' ', spaceCount);

return builder.ToString().AsMemory();
}

return new string(' ', size).AsMemory();
}

public CodeWriter Write(string value)
{
ArgHelper.ThrowIfNull(value);
Expand Down