diff --git a/src/Spectre.Console/Internal/Cell.cs b/src/Spectre.Console/Internal/Cell.cs index b79e7e5..78037a0 100644 --- a/src/Spectre.Console/Internal/Cell.cs +++ b/src/Spectre.Console/Internal/Cell.cs @@ -2,7 +2,26 @@ namespace Spectre.Console; internal static class Cell { - private static readonly int?[] _runeWidthCache = new int?[char.MaxValue]; + private const sbyte Sentinel = -2; + + /// + /// 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. + /// + 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) { @@ -29,6 +48,13 @@ internal static class Cell 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]; } } \ No newline at end of file