Browse Source

Use UnsafeAsSpan while iterating over LogicalChildren

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

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

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

63
src/Avalonia.Base/StyledElement.cs

@ -5,8 +5,10 @@ using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Avalonia.Animation;
using Avalonia.Collections;
using Avalonia.Collections.Pooled;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Diagnostics;
@ -82,7 +84,7 @@ namespace Avalonia
private string? _name;
private Classes? _classes;
private ILogicalRoot? _logicalRoot;
private IAvaloniaList<ILogical>? _logicalChildren;
private AvaloniaList<ILogical>? _logicalChildren;
private IResourceDictionary? _resources;
private Styles? _styles;
private bool _stylesApplied;
@ -558,18 +560,13 @@ namespace Avalonia
/// <param name="e">The event args.</param>
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;
for (var i = 0; i < count; ++i)
{
_logicalChildren[i].NotifyResourcesChanged(e);
}
child.NotifyResourcesChanged(e);
}
}
}
@ -747,16 +744,16 @@ namespace Avalonia
element._dataContextUpdating = true;
element.OnDataContextBeginUpdate();
var logicalChildren = element.LogicalChildren;
var logicalChildrenCount = logicalChildren.Count;
for (var i = 0; i < logicalChildrenCount; i++)
if (element._logicalChildren is {} children)
{
if (element.LogicalChildren[i] is StyledElement s &&
s.InheritanceParent == element &&
!s.IsSet(DataContextProperty))
foreach (var child in children.UnsafeAsSpan())
{
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);
}
var logicalChildren = LogicalChildren;
var logicalChildrenCount = logicalChildren.Count;
for (var i = 0; i < logicalChildrenCount; i++)
if (_logicalChildren is { } children)
{
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);
DetachedFromLogicalTree?.Invoke(this, e);
var logicalChildren = LogicalChildren;
var logicalChildrenCount = logicalChildren.Count;
for (var i = 0; i < logicalChildrenCount; i++)
if (_logicalChildren is { } children)
{
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)
{
var childCount = _logicalChildren.Count;
for (var i = 0; i < childCount; ++i)
foreach (var child in _logicalChildren.UnsafeAsSpan())
{
(_logicalChildren[i] as StyledElement)?.DetachStyles(styles);
(child as StyledElement)?.DetachStyles(styles);
}
}
}

Loading…
Cancel
Save