Browse Source

Merge branch 'master' into avalonialist-ensurecapacity

pull/3475/head
Dariusz Komosiński 7 years ago
committed by GitHub
parent
commit
1fc2372567
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/Avalonia.Base/AvaloniaProperty.cs
  2. 32
      src/Avalonia.Base/Utilities/TypeUtilities.cs
  3. 94
      src/Avalonia.Base/Utilities/ValueSingleOrList.cs
  4. 1
      src/Avalonia.Native/PlatformThreadingInterface.cs
  5. 17
      src/Avalonia.Styling/Styling/Selector.cs
  6. 52
      tests/Avalonia.Benchmarks/Styling/SelectorBenchmark.cs

4
src/Avalonia.Base/AvaloniaProperty.cs

@ -3,9 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reactive.Subjects;
using System.Reflection;
using Avalonia.Data;
using Avalonia.Utilities;
@ -602,7 +600,7 @@ namespace Avalonia
return result;
}
currentType = currentType.GetTypeInfo().BaseType;
currentType = currentType.BaseType;
}
_metadataCache[type] = _defaultMetadata;

32
src/Avalonia.Base/Utilities/TypeUtilities.cs

@ -92,8 +92,7 @@ namespace Avalonia.Utilities
/// <returns>True if the type accepts null values; otherwise false.</returns>
public static bool AcceptsNull(Type type)
{
var t = type.GetTypeInfo();
return !t.IsValueType || (t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(Nullable<>)));
return !type.IsValueType || IsNullableType(type);
}
/// <summary>
@ -119,10 +118,8 @@ namespace Avalonia.Utilities
}
var from = value.GetType();
var fromTypeInfo = from.GetTypeInfo();
var toTypeInfo = to.GetTypeInfo();
if (toTypeInfo.IsAssignableFrom(fromTypeInfo))
if (to.IsAssignableFrom(from))
{
result = value;
return true;
@ -134,7 +131,7 @@ namespace Avalonia.Utilities
return true;
}
if (toTypeInfo.IsEnum && from == typeof(string))
if (to.IsEnum && from == typeof(string))
{
if (Enum.IsDefined(to, (string)value))
{
@ -143,7 +140,7 @@ namespace Avalonia.Utilities
}
}
if (!fromTypeInfo.IsEnum && toTypeInfo.IsEnum)
if (!from.IsEnum && to.IsEnum)
{
result = null;
@ -154,7 +151,7 @@ namespace Avalonia.Utilities
}
}
if (fromTypeInfo.IsEnum && IsNumeric(to))
if (from.IsEnum && IsNumeric(to))
{
try
{
@ -223,10 +220,8 @@ namespace Avalonia.Utilities
}
var from = value.GetType();
var fromTypeInfo = from.GetTypeInfo();
var toTypeInfo = to.GetTypeInfo();
if (toTypeInfo.IsAssignableFrom(fromTypeInfo))
if (to.IsAssignableFrom(from))
{
result = value;
return true;
@ -307,9 +302,7 @@ namespace Avalonia.Utilities
/// <returns>The default value.</returns>
public static object Default(Type type)
{
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsValueType)
if (type.IsValueType)
{
return Activator.CreateInstance(type);
}
@ -335,9 +328,11 @@ namespace Avalonia.Utilities
return false;
}
if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
Type underlyingType = Nullable.GetUnderlyingType(type);
if (underlyingType != null)
{
return IsNumeric(Nullable.GetUnderlyingType(type));
return IsNumeric(underlyingType);
}
else
{
@ -352,6 +347,11 @@ namespace Avalonia.Utilities
Explicit = 2
}
private static bool IsNullableType(Type type)
{
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
private static MethodInfo FindTypeConversionOperatorMethod(Type fromType, Type toType, OperatorType operatorType)
{
const string implicitName = "op_Implicit";

94
src/Avalonia.Base/Utilities/ValueSingleOrList.cs

@ -0,0 +1,94 @@
using System.Collections.Generic;
namespace Avalonia.Utilities
{
/// <summary>
/// A list like struct optimized for holding zero or one items.
/// </summary>
/// <typeparam name="T">The type of items held in the list.</typeparam>
/// <remarks>
/// Once more than value has been added to this storage it will switch to using <see cref="List"/> internally.
/// </remarks>
public ref struct ValueSingleOrList<T>
{
private bool _isSingleSet;
/// <summary>
/// Single contained value. Only valid if <see cref="IsSingle"/> is set.
/// </summary>
public T Single { get; private set; }
/// <summary>
/// List of values.
/// </summary>
public List<T> List { get; private set; }
/// <summary>
/// If this struct is backed by a list.
/// </summary>
public bool HasList => List != null;
/// <summary>
/// If this struct contains only single value and storage was not promoted to a list.
/// </summary>
public bool IsSingle => List == null && _isSingleSet;
/// <summary>
/// Adds a value.
/// </summary>
/// <param name="value">Value to add.</param>
public void Add(T value)
{
if (List != null)
{
List.Add(value);
}
else
{
if (!_isSingleSet)
{
Single = value;
_isSingleSet = true;
}
else
{
List = new List<T>();
List.Add(Single);
List.Add(value);
Single = default;
}
}
}
/// <summary>
/// Removes a value.
/// </summary>
/// <param name="value">Value to remove.</param>
public bool Remove(T value)
{
if (List != null)
{
return List.Remove(value);
}
if (!_isSingleSet)
{
return false;
}
if (EqualityComparer<T>.Default.Equals(Single, value))
{
Single = default;
_isSingleSet = false;
return true;
}
return false;
}
}
}

1
src/Avalonia.Native/PlatformThreadingInterface.cs

@ -60,6 +60,7 @@ namespace Avalonia.Native
public void RunLoop(CancellationToken cancellationToken)
{
_exceptionDispatchInfo?.Throw();
var l = new object();
_exceptionCancellationSource = new CancellationTokenSource();

17
src/Avalonia.Styling/Styling/Selector.cs

@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Avalonia.Utilities;
namespace Avalonia.Styling
{
@ -41,7 +43,8 @@ namespace Avalonia.Styling
/// <returns>A <see cref="SelectorMatch"/>.</returns>
public SelectorMatch Match(IStyleable control, bool subscribe = true)
{
var inputs = new List<IObservable<bool>>();
ValueSingleOrList<IObservable<bool>> inputs = default;
var selector = this;
var alwaysThisType = true;
var hitCombinator = false;
@ -66,19 +69,25 @@ namespace Avalonia.Styling
}
else if (match.Result == SelectorMatchResult.Sometimes)
{
Debug.Assert(match.Activator != null);
inputs.Add(match.Activator);
}
selector = selector.MovePrevious();
}
if (inputs.Count > 0)
if (inputs.HasList)
{
return new SelectorMatch(StyleActivator.And(inputs.List));
}
else if (inputs.IsSingle)
{
return new SelectorMatch(StyleActivator.And(inputs));
return new SelectorMatch(inputs.Single);
}
else
{
return alwaysThisType && !hitCombinator ?
return alwaysThisType && !hitCombinator ?
SelectorMatch.AlwaysThisType :
SelectorMatch.AlwaysThisInstance;
}

52
tests/Avalonia.Benchmarks/Styling/SelectorBenchmark.cs

@ -0,0 +1,52 @@
using Avalonia.Controls;
using Avalonia.Styling;
using BenchmarkDotNet.Attributes;
namespace Avalonia.Benchmarks.Styling
{
[MemoryDiagnoser]
public class SelectorBenchmark
{
private readonly Control _notMatchingControl;
private readonly Calendar _matchingControl;
private readonly Selector _isCalendarSelector;
private readonly Selector _classSelector;
public SelectorBenchmark()
{
_notMatchingControl = new Control();
_matchingControl = new Calendar();
const string className = "selector-class";
_matchingControl.Classes.Add(className);
_isCalendarSelector = Selectors.Is<Calendar>(null);
_classSelector = Selectors.Class(null, className);
}
[Benchmark]
public SelectorMatch IsSelector_NoMatch()
{
return _isCalendarSelector.Match(_notMatchingControl);
}
[Benchmark]
public SelectorMatch IsSelector_Match()
{
return _isCalendarSelector.Match(_matchingControl);
}
[Benchmark]
public SelectorMatch ClassSelector_NoMatch()
{
return _classSelector.Match(_notMatchingControl);
}
[Benchmark]
public SelectorMatch ClassSelector_Match()
{
return _classSelector.Match(_matchingControl);
}
}
}
Loading…
Cancel
Save