Browse Source
Merge pull request #3015 from MarchingCube/alloc-priorityobjects
Reduce closure allocations for priority level and entry.
pull/3024/head
Dariusz Komosiński
6 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with
49 additions and
23 deletions
-
src/Avalonia.Base/PriorityBindingEntry.cs
-
src/Avalonia.Base/PriorityLevel.cs
|
|
|
@ -99,37 +99,42 @@ namespace Avalonia |
|
|
|
|
|
|
|
void IObserver<object>.OnNext(object value) |
|
|
|
{ |
|
|
|
void Signal() |
|
|
|
void Signal(PriorityBindingEntry instance, object newValue) |
|
|
|
{ |
|
|
|
var notification = value as BindingNotification; |
|
|
|
var notification = newValue as BindingNotification; |
|
|
|
|
|
|
|
if (notification != null) |
|
|
|
{ |
|
|
|
if (notification.HasValue || notification.ErrorType == BindingErrorType.Error) |
|
|
|
{ |
|
|
|
Value = notification.Value; |
|
|
|
_owner.Changed(this); |
|
|
|
instance.Value = notification.Value; |
|
|
|
instance._owner.Changed(instance); |
|
|
|
} |
|
|
|
|
|
|
|
if (notification.ErrorType != BindingErrorType.None) |
|
|
|
{ |
|
|
|
_owner.Error(this, notification); |
|
|
|
instance._owner.Error(instance, notification); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Value = value; |
|
|
|
_owner.Changed(this); |
|
|
|
instance.Value = newValue; |
|
|
|
instance._owner.Changed(instance); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (Dispatcher.UIThread.CheckAccess()) |
|
|
|
{ |
|
|
|
Signal(); |
|
|
|
Signal(this, value); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Dispatcher.UIThread.Post(Signal); |
|
|
|
// To avoid allocating closure in the outer scope we need to capture variables
|
|
|
|
// locally. This allows us to skip most of the allocations when on UI thread.
|
|
|
|
var instance = this; |
|
|
|
var newValue = value; |
|
|
|
|
|
|
|
Dispatcher.UIThread.Post(() => Signal(instance, newValue)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -110,20 +110,7 @@ namespace Avalonia |
|
|
|
|
|
|
|
entry.Start(binding); |
|
|
|
|
|
|
|
return Disposable.Create(() => |
|
|
|
{ |
|
|
|
if (!entry.HasCompleted) |
|
|
|
{ |
|
|
|
Bindings.Remove(node); |
|
|
|
|
|
|
|
entry.Dispose(); |
|
|
|
|
|
|
|
if (entry.Index >= ActiveBindingIndex) |
|
|
|
{ |
|
|
|
ActivateFirstBinding(); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
return new RemoveBindingDisposable(node, Bindings, this); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -191,5 +178,39 @@ namespace Avalonia |
|
|
|
ActiveBindingIndex = -1; |
|
|
|
Owner.LevelValueChanged(this); |
|
|
|
} |
|
|
|
|
|
|
|
private sealed class RemoveBindingDisposable : IDisposable |
|
|
|
{ |
|
|
|
private readonly LinkedListNode<PriorityBindingEntry> _binding; |
|
|
|
private readonly LinkedList<PriorityBindingEntry> _bindings; |
|
|
|
private readonly PriorityLevel _priorityLevel; |
|
|
|
|
|
|
|
public RemoveBindingDisposable( |
|
|
|
LinkedListNode<PriorityBindingEntry> binding, |
|
|
|
LinkedList<PriorityBindingEntry> bindings, |
|
|
|
PriorityLevel priorityLevel) |
|
|
|
{ |
|
|
|
_binding = binding; |
|
|
|
_bindings = bindings; |
|
|
|
_priorityLevel = priorityLevel; |
|
|
|
} |
|
|
|
|
|
|
|
public void Dispose() |
|
|
|
{ |
|
|
|
PriorityBindingEntry entry = _binding.Value; |
|
|
|
|
|
|
|
if (!entry.HasCompleted) |
|
|
|
{ |
|
|
|
_bindings.Remove(_binding); |
|
|
|
|
|
|
|
entry.Dispose(); |
|
|
|
|
|
|
|
if (entry.Index >= _priorityLevel.ActiveBindingIndex) |
|
|
|
{ |
|
|
|
_priorityLevel.ActivateFirstBinding(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|