Fix Cell.Grapheme validation allocation by adding GetGraphemeCount

Added allocation-free grapheme counting to GraphemeHelper:
- New GetGraphemeCount() method counts graphemes without materializing array
- Uses TextElementEnumerator directly, avoiding .ToArray() allocation
- Updated Cell.Grapheme setter to use GetGraphemeCount() instead of .ToArray().Length

Impact: Eliminates allocation on every Cell.Grapheme property set
- Validation now happens without intermediate array allocation
- Particularly beneficial for cell-based operations and grid rendering

All unit tests pass (12,055 parallelizable + 1,173 non-parallel)

Co-authored-by: tig <585482+tig@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-12-03 20:24:24 +00:00
parent 9feac09e13
commit 12756a29d8
2 changed files with 24 additions and 1 deletions

View File

@@ -27,7 +27,7 @@ public record struct Cell (Attribute? Attribute = null, bool IsDirty = false, st
readonly get => _grapheme; readonly get => _grapheme;
set set
{ {
if (GraphemeHelper.GetGraphemes(value).ToArray().Length > 1) if (GraphemeHelper.GetGraphemeCount (value) > 1)
{ {
throw new InvalidOperationException ($"Only a single {nameof (Grapheme)} cluster is allowed per Cell."); throw new InvalidOperationException ($"Only a single {nameof (Grapheme)} cluster is allowed per Cell.");
} }

View File

@@ -46,4 +46,27 @@ public static class GraphemeHelper
yield return element; yield return element;
} }
} }
/// <summary>
/// Counts the number of grapheme clusters in a string without allocating intermediate collections.
/// </summary>
/// <param name="text">The string to count graphemes in.</param>
/// <returns>The number of grapheme clusters, or 0 if the string is null or empty.</returns>
public static int GetGraphemeCount (string text)
{
if (string.IsNullOrEmpty (text))
{
return 0;
}
TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator (text);
var count = 0;
while (enumerator.MoveNext ())
{
count++;
}
return count;
}
} }