Browse Source

Use UnsafeAsSpan while iterating over LogicalChildren

UnsafeAsSpan-logical-children
Max Katz 3 years ago
parent
commit
b147f0d883
  1. 6
      src/Avalonia.Base/Collections/AvaloniaList.cs
  2. 50
      src/Avalonia.Base/Compatibility/CollectionCompatibilityExtensions.cs
  3. 63
      src/Avalonia.Base/StyledElement.cs

6
src/Avalonia.Base/Collections/AvaloniaList.cs

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using Avalonia.Diagnostics; using Avalonia.Diagnostics;
namespace Avalonia.Collections namespace Avalonia.Collections
@ -742,6 +743,11 @@ namespace Avalonia.Collections
NotifyCountChanged(); NotifyCountChanged();
} }
internal Span<T> UnsafeAsSpan()
{
return CollectionsMarshal.AsSpan(_inner);
}
/// <summary> /// <summary>
/// Enumerates the elements of a <see cref="AvaloniaList{T}"/>. /// Enumerates the elements of a <see cref="AvaloniaList{T}"/>.
/// </summary> /// </summary>

50
src/Avalonia.Base/Compatibility/CollectionCompatibilityExtensions.cs

@ -1,32 +1,44 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace System;
#if !NET6_0_OR_GREATER #if !NET6_0_OR_GREATER
internal static class CollectionCompatibilityExtensions namespace System
{ {
public static bool Remove<TKey, TValue>( internal static class CollectionCompatibilityExtensions
this Dictionary<TKey, TValue> o,
TKey key,
[MaybeNullWhen(false)] out TValue value)
where TKey : notnull
{ {
if (o.TryGetValue(key, out value)) public static bool Remove<TKey, TValue>(
return o.Remove(key); this Dictionary<TKey, TValue> o,
return false; TKey key,
} [MaybeNullWhen(false)] out TValue value)
where TKey : notnull
{
if (o.TryGetValue(key, out value))
return o.Remove(key);
return false;
}
public static bool TryAdd<TKey, TValue>(this Dictionary<TKey, TValue> o, TKey key, TValue value) public static bool TryAdd<TKey, TValue>(this Dictionary<TKey, TValue> o, TKey key, TValue value)
where TKey : notnull where TKey : notnull
{
if (!o.ContainsKey(key))
{
o.Add(key, value);
return true;
}
return false;
}
}
namespace Runtime.InteropServices
{ {
if (!o.ContainsKey(key)) public static class CollectionsMarshal
{ {
o.Add(key, value); public static Span<T> AsSpan<T>(List<T>? list)
return true; => list is null ? default : new Span<T>(Unsafe.As<StrongBox<T[]>>(list).Value, 0, list.Count);
} }
return false;
} }
} }
#endif #endif

63
src/Avalonia.Base/StyledElement.cs

@ -5,8 +5,10 @@ using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using Avalonia.Animation; using Avalonia.Animation;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Collections.Pooled;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Diagnostics; using Avalonia.Diagnostics;
@ -82,7 +84,7 @@ namespace Avalonia
private string? _name; private string? _name;
private Classes? _classes; private Classes? _classes;
private ILogicalRoot? _logicalRoot; private ILogicalRoot? _logicalRoot;
private IAvaloniaList<ILogical>? _logicalChildren; private AvaloniaList<ILogical>? _logicalChildren;
private IResourceDictionary? _resources; private IResourceDictionary? _resources;
private Styles? _styles; private Styles? _styles;
private bool _stylesApplied; private bool _stylesApplied;
@ -558,18 +560,13 @@ namespace Avalonia
/// <param name="e">The event args.</param> /// <param name="e">The event args.</param>
internal virtual void NotifyChildResourcesChanged(ResourcesChangedEventArgs e) internal virtual void NotifyChildResourcesChanged(ResourcesChangedEventArgs e)
{ {
if (_logicalChildren is object) if (_logicalChildren is { Count: > 0 })
{ {
var count = _logicalChildren.Count; e ??= ResourcesChangedEventArgs.Empty;
if (count > 0) foreach (var child in _logicalChildren.UnsafeAsSpan())
{ {
e ??= ResourcesChangedEventArgs.Empty; child.NotifyResourcesChanged(e);
for (var i = 0; i < count; ++i)
{
_logicalChildren[i].NotifyResourcesChanged(e);
}
} }
} }
} }
@ -747,16 +744,16 @@ namespace Avalonia
element._dataContextUpdating = true; element._dataContextUpdating = true;
element.OnDataContextBeginUpdate(); element.OnDataContextBeginUpdate();
var logicalChildren = element.LogicalChildren; if (element._logicalChildren is {} children)
var logicalChildrenCount = logicalChildren.Count;
for (var i = 0; i < logicalChildrenCount; i++)
{ {
if (element.LogicalChildren[i] is StyledElement s && foreach (var child in children.UnsafeAsSpan())
s.InheritanceParent == element &&
!s.IsSet(DataContextProperty))
{ {
DataContextNotifying(s, updateStarted); if (child is StyledElement s &&
s.InheritanceParent == element &&
!s.IsSet(DataContextProperty))
{
DataContextNotifying(s, updateStarted);
}
} }
} }
} }
@ -903,14 +900,14 @@ namespace Avalonia
AttachedToLogicalTree?.Invoke(this, e); AttachedToLogicalTree?.Invoke(this, e);
} }
var logicalChildren = LogicalChildren; if (_logicalChildren is { } children)
var logicalChildrenCount = logicalChildren.Count;
for (var i = 0; i < logicalChildrenCount; i++)
{ {
if (logicalChildren[i] is StyledElement child && child._logicalRoot != e.Root) // child may already have been attached within an event handler foreach (var child in children.UnsafeAsSpan())
{ {
child.OnAttachedToLogicalTreeCore(e); if (child is StyledElement s && s._logicalRoot != e.Root)
{
s.OnAttachedToLogicalTreeCore(e);
}
} }
} }
} }
@ -924,14 +921,14 @@ namespace Avalonia
OnDetachedFromLogicalTree(e); OnDetachedFromLogicalTree(e);
DetachedFromLogicalTree?.Invoke(this, e); DetachedFromLogicalTree?.Invoke(this, e);
var logicalChildren = LogicalChildren; if (_logicalChildren is { } children)
var logicalChildrenCount = logicalChildren.Count;
for (var i = 0; i < logicalChildrenCount; i++)
{ {
if (logicalChildren[i] is StyledElement child) foreach (var child in children.UnsafeAsSpan())
{ {
child.OnDetachedFromLogicalTreeCore(e); if (child is StyledElement s)
{
s.OnDetachedFromLogicalTreeCore(e);
}
} }
} }
@ -991,11 +988,9 @@ namespace Avalonia
if (_logicalChildren is not null) if (_logicalChildren is not null)
{ {
var childCount = _logicalChildren.Count; foreach (var child in _logicalChildren.UnsafeAsSpan())
for (var i = 0; i < childCount; ++i)
{ {
(_logicalChildren[i] as StyledElement)?.DetachStyles(styles); (child as StyledElement)?.DetachStyles(styles);
} }
} }
} }

Loading…
Cancel
Save