Reduce memory usage for rune width cache. (#1756)

This commit is contained in:
Pannoniae
2025-06-20 11:49:45 +01:00
committed by GitHub
parent d77bfb6391
commit 7f3ebe02c4

View File

@ -2,7 +2,26 @@ namespace Spectre.Console;
internal static class Cell internal static class Cell
{ {
private static readonly int?[] _runeWidthCache = new int?[char.MaxValue]; private const sbyte Sentinel = -2;
/// <summary>
/// UnicodeCalculator.GetWidth documents the width as (-1, 0, 1, 2). We only need space for these values and a sentinel for uninitialized values.
/// This is only five values in total so we are storing one byte per value. We could store 2 per byte but that would add more logic to the retrieval.
/// We should add one to char.MaxValue because the total number of characters includes \0 too so there are 65536 valid chars.
/// </summary>
private static readonly sbyte[] _runeWidthCache = new sbyte[char.MaxValue + 1];
static Cell()
{
#if !NETSTANDARD2_0
Array.Fill(_runeWidthCache, Sentinel);
#else
for (var i = 0; i < _runeWidthCache.Length; i++)
{
_runeWidthCache[i] = Sentinel;
}
#endif
}
public static int GetCellLength(string text) public static int GetCellLength(string text)
{ {
@ -29,6 +48,13 @@ internal static class Cell
return 1; return 1;
} }
return _runeWidthCache[rune] ??= UnicodeCalculator.GetWidth(rune); var width = _runeWidthCache[rune];
if (width == Sentinel)
{
_runeWidthCache[rune] = (sbyte)UnicodeCalculator.GetWidth(rune);
return _runeWidthCache[rune];
}
return _runeWidthCache[rune];
} }
} }