Parcourir la source

Reuse empty value store arrays.

Dariusz Komosinski il y a 5 ans
Parent
commit
dc698b3b1d

+ 20 - 4
src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs

@@ -1,5 +1,8 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+
+#nullable enable
 
 
 namespace Avalonia.Utilities
 namespace Avalonia.Utilities
 {
 {
@@ -9,12 +12,14 @@ namespace Avalonia.Utilities
     /// <typeparam name="TValue">Stored value type.</typeparam>
     /// <typeparam name="TValue">Stored value type.</typeparam>
     internal sealed class AvaloniaPropertyValueStore<TValue>
     internal sealed class AvaloniaPropertyValueStore<TValue>
     {
     {
+        // The last item in the list is always int.MaxValue.
+        private static readonly Entry[] s_emptyEntries = { new Entry { PropertyId = int.MaxValue, Value = default! } };
+        
         private Entry[] _entries;
         private Entry[] _entries;
 
 
         public AvaloniaPropertyValueStore()
         public AvaloniaPropertyValueStore()
         {
         {
-            // The last item in the list is always int.MaxValue
-            _entries = new[] { new Entry { PropertyId = int.MaxValue, Value = default } };
+            _entries = s_emptyEntries;
         }
         }
 
 
         private (int, bool) TryFindEntry(int propertyId)
         private (int, bool) TryFindEntry(int propertyId)
@@ -86,7 +91,7 @@ namespace Avalonia.Utilities
             return (0, false);
             return (0, false);
         }
         }
 
 
-        public bool TryGetValue(AvaloniaProperty property, out TValue value)
+        public bool TryGetValue(AvaloniaProperty property, [MaybeNull] out TValue value)
         {
         {
             (int index, bool found) = TryFindEntry(property.Id);
             (int index, bool found) = TryFindEntry(property.Id);
             if (!found)
             if (!found)
@@ -132,7 +137,18 @@ namespace Avalonia.Utilities
 
 
             if (found)
             if (found)
             {
             {
-                Entry[] entries = new Entry[_entries.Length - 1];
+                var newLength = _entries.Length - 1;
+                
+                // Special case - one element left means that value store is empty so we can just reuse our "empty" array.
+                if (newLength == 1)
+                {
+                    _entries = s_emptyEntries;
+                    
+                    return;
+                }
+                
+                var entries = new Entry[newLength];
+
                 int ix = 0;
                 int ix = 0;
 
 
                 for (int i = 0; i < _entries.Length; ++i)
                 for (int i = 0; i < _entries.Length; ++i)

+ 2 - 1
tests/Avalonia.Benchmarks/Layout/ControlsBenchmark.cs

@@ -17,7 +17,8 @@ namespace Avalonia.Benchmarks.Layout
             _app = UnitTestApplication.Start(
             _app = UnitTestApplication.Start(
                 TestServices.StyledWindow.With(
                 TestServices.StyledWindow.With(
                     renderInterface: new NullRenderingPlatform(),
                     renderInterface: new NullRenderingPlatform(),
-                    threadingInterface: new NullThreadingPlatform()));
+                    threadingInterface: new NullThreadingPlatform(),
+                    standardCursorFactory: new NullCursorFactory()));
 
 
             _root = new TestRoot(true, null)
             _root = new TestRoot(true, null)
             {
             {

+ 14 - 0
tests/Avalonia.Benchmarks/NullCursorFactory.cs

@@ -0,0 +1,14 @@
+using System;
+using Avalonia.Input;
+using Avalonia.Platform;
+
+namespace Avalonia.Benchmarks
+{
+    internal class NullCursorFactory : IStandardCursorFactory
+    {
+        public IPlatformHandle GetCursor(StandardCursorType cursorType)
+        {
+            return new PlatformHandle(IntPtr.Zero, "null");
+        }
+    }
+}