From d98c1f5ec47aeb0ab83829ae889d2e28ae128d91 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 5 Jan 2024 11:31:57 +0100 Subject: [PATCH] Add a pooled option in BindingExpressionGrammar. Micro-optimization. --- src/Markup/Avalonia.Markup/Data/Binding.cs | 7 ++++--- .../Parsers/BindingExpressionGrammar.cs | 21 +++++++++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/Markup/Avalonia.Markup/Data/Binding.cs b/src/Markup/Avalonia.Markup/Data/Binding.cs index bf89694d1d..143d037959 100644 --- a/src/Markup/Avalonia.Markup/Data/Binding.cs +++ b/src/Markup/Avalonia.Markup/Data/Binding.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using Avalonia.Collections.Pooled; using Avalonia.Controls; using Avalonia.Data.Converters; using Avalonia.Data.Core; @@ -104,7 +105,7 @@ namespace Avalonia.Data if (!string.IsNullOrEmpty(Path)) { var reader = new CharacterReader(Path.AsSpan()); - var (astNodes, sourceMode) = BindingExpressionGrammar.Parse(ref reader); + var (astNodes, sourceMode) = BindingExpressionGrammar.ParseToPooledList(ref reader); nodes = ExpressionNodeFactory.CreateFromAst( astNodes, TypeResolver, @@ -137,9 +138,9 @@ namespace Avalonia.Data if (!string.IsNullOrEmpty(Path)) { var reader = new CharacterReader(Path.AsSpan()); - var (astNodes, sourceMode) = BindingExpressionGrammar.Parse(ref reader); + var (astPool, sourceMode) = BindingExpressionGrammar.ParseToPooledList(ref reader); nodes = ExpressionNodeFactory.CreateFromAst( - astNodes, + astPool, TypeResolver, GetNameScope(), out isRooted); diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs index c73063a4f0..5a4a56b746 100644 --- a/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs +++ b/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs @@ -16,9 +16,26 @@ namespace Avalonia.Markup.Parsers internal static class BindingExpressionGrammar { + private static readonly List s_pool = new(); + public static (List Nodes, SourceMode Mode) Parse(ref CharacterReader r) { - var nodes = new List(); + var result = new List(); + var mode = Parse(ref r, result); + return (result, mode); + } + + public static (List Nodes, SourceMode Mode) ParseToPooledList(ref CharacterReader r) + { + // Most of the time the list will be passed to `ExpressionNodeFactory.CreateFromAst` + // and then discarded so as a micro-optimization we can reuse the list. + s_pool.Clear(); + var mode = Parse(ref r, s_pool); + return (s_pool, mode); + } + + private static SourceMode Parse(ref CharacterReader r, List nodes) + { var state = State.Start; var mode = SourceMode.Data; @@ -72,7 +89,7 @@ namespace Avalonia.Markup.Parsers throw new ExpressionParseException(r.Position, "Unexpected end of expression."); } - return (nodes, mode); + return mode; } private static State ParseStart(ref CharacterReader r, IList nodes)