From 12756a29d84a183a0ab28e9a2d5e36543a92467e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Dec 2025 20:24:24 +0000 Subject: [PATCH] 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> --- Terminal.Gui/Drawing/Cell.cs | 2 +- Terminal.Gui/Drawing/GraphemeHelper.cs | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Terminal.Gui/Drawing/Cell.cs b/Terminal.Gui/Drawing/Cell.cs index f7da577ad..6e9aff593 100644 --- a/Terminal.Gui/Drawing/Cell.cs +++ b/Terminal.Gui/Drawing/Cell.cs @@ -27,7 +27,7 @@ public record struct Cell (Attribute? Attribute = null, bool IsDirty = false, st readonly get => _grapheme; 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."); } diff --git a/Terminal.Gui/Drawing/GraphemeHelper.cs b/Terminal.Gui/Drawing/GraphemeHelper.cs index 4ae00148c..918270727 100644 --- a/Terminal.Gui/Drawing/GraphemeHelper.cs +++ b/Terminal.Gui/Drawing/GraphemeHelper.cs @@ -46,4 +46,27 @@ public static class GraphemeHelper yield return element; } } + + /// + /// Counts the number of grapheme clusters in a string without allocating intermediate collections. + /// + /// The string to count graphemes in. + /// The number of grapheme clusters, or 0 if the string is null or empty. + 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; + } }