Browse Source

Implement simple struct wrapping a single value or List.

pull/3474/head
Dariusz Komosinski 6 years ago
parent
commit
beea785f30
  1. 94
      src/Avalonia.Base/Utilities/ValueSingleOrList.cs
  2. 33
      src/Avalonia.Styling/Styling/Selector.cs

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;
}
}
}

33
src/Avalonia.Styling/Styling/Selector.cs

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

Loading…
Cancel
Save