From 85ffed056a2f74fe344b46e444d9743d1e403775 Mon Sep 17 00:00:00 2001 From: Alexandre Mutel Date: Wed, 26 Feb 2025 13:40:20 +0100 Subject: [PATCH] Remove `List>.ToArray()` allocations in `LightweightObservableBase` (#18316) * Remove `List>.ToArray()` allocations in `LightweightObservableBase` * Cleanup code * Remove unused code * Remove space --- .../Reactive/LightweightObservableBase.cs | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/Avalonia.Base/Reactive/LightweightObservableBase.cs b/src/Avalonia.Base/Reactive/LightweightObservableBase.cs index cf20f20172..04759e314d 100644 --- a/src/Avalonia.Base/Reactive/LightweightObservableBase.cs +++ b/src/Avalonia.Base/Reactive/LightweightObservableBase.cs @@ -1,7 +1,7 @@ using System; +using System.Buffers; using System.Collections.Generic; using System.Threading; -using Avalonia.Threading; namespace Avalonia.Reactive { @@ -118,32 +118,59 @@ namespace Avalonia.Reactive if (Volatile.Read(ref _observers) != null) { IObserver[]? observers = null; - IObserver? singleObserver = null; + int count = 0; + + // Optimize for the common case of 1/2/3 observers. + IObserver? observer0 = null; + IObserver? observer1 = null; + IObserver? observer2 = null; lock (this) { if (_observers == null) { return; } - if (_observers.Count == 1) - { - singleObserver = _observers[0]; - } - else + + count = _observers.Count; + switch (count) { - observers = _observers.ToArray(); + case 3: + observer0 = _observers[0]; + observer1 = _observers[1]; + observer2 = _observers[2]; + break; + case 2: + observer0 = _observers[0]; + observer1 = _observers[1]; + break; + case 1: + observer0 = _observers[0]; + break; + case 0: + return; + default: + { + observers = ArrayPool>.Shared.Rent(count); + _observers.CopyTo(observers); + break; + } } } - if (singleObserver != null) + + if (observer0 != null) { - singleObserver.OnNext(value); + observer0.OnNext(value); + observer1?.OnNext(value); + observer2?.OnNext(value); } - else + else if (observers != null) { - foreach (var observer in observers!) + for(int i = 0; i < count; i++) { - observer.OnNext(value); + observers[i].OnNext(value); } + + ArrayPool>.Shared.Return(observers); } } }