Browse Source

Implemented optimization to only construct a dictionary for priority levels if there is more than one in use. This drops memory consumption in most applications by a reasonable amount since most don't use multiple bindings on single properties (like animation and a local binding).

pull/721/head
Jeremy Koritzinsky 10 years ago
parent
commit
3640d4dc1b
  1. 1
      src/Avalonia.Base/Avalonia.Base.csproj
  2. 2
      src/Avalonia.Base/PriorityValue.cs
  3. 147
      src/Avalonia.Base/Utilities/SingleOrDictionary.cs

1
src/Avalonia.Base/Avalonia.Base.csproj

@ -118,6 +118,7 @@
<Compile Include="Utilities\ExceptionUtilities.cs" />
<Compile Include="Utilities\IWeakSubscriber.cs" />
<Compile Include="Utilities\MathUtilities.cs" />
<Compile Include="Utilities\SingleOrDictionary.cs" />
<Compile Include="Utilities\TypeUtilities.cs" />
<Compile Include="Utilities\WeakObservable.cs" />
<Compile Include="Utilities\WeakSubscriptionManager.cs" />

2
src/Avalonia.Base/PriorityValue.cs

@ -28,7 +28,7 @@ namespace Avalonia
{
private readonly IPriorityValueOwner _owner;
private readonly Type _valueType;
private readonly Dictionary<int, PriorityLevel> _levels = new Dictionary<int, PriorityLevel>();
private readonly SingleOrDictionary<int, PriorityLevel> _levels = new SingleOrDictionary<int, PriorityLevel>();
private object _value;
private readonly Func<object, object> _validate;

147
src/Avalonia.Base/Utilities/SingleOrDictionary.cs

@ -0,0 +1,147 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Utilities
{
/// <summary>
/// Stores either a single key value pair or constructs a dictionary when more than one value is stored.
/// </summary>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
public class SingleOrDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
private KeyValuePair<TKey, TValue>? singleValue;
private Dictionary<TKey, TValue> dictionary;
private bool useDictionary = false;
public void Add(TKey key, TValue value)
{
if (singleValue != null)
{
dictionary = new Dictionary<TKey, TValue>();
((ICollection<KeyValuePair<TKey, TValue>>)dictionary).Add(singleValue.Value);
useDictionary = true;
singleValue = null;
}
if (useDictionary)
{
dictionary.Add(key, value);
}
else
{
singleValue = new KeyValuePair<TKey, TValue>(key, value);
}
}
public bool TryGetValue(TKey key, out TValue value)
{
if (!useDictionary)
{
if (!singleValue.HasValue || !singleValue.Value.Key.Equals(key))
{
value = default(TValue);
return false;
}
else
{
value = singleValue.Value.Value;
return true;
}
}
else
{
return dictionary.TryGetValue(key, out value);
}
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
if (!useDictionary)
{
if (singleValue.HasValue)
{
return new SingleEnumerator<KeyValuePair<TKey, TValue>>(singleValue.Value);
}
}
else
{
return dictionary.GetEnumerator();
}
return Enumerable.Empty<KeyValuePair<TKey, TValue>>().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerable<TValue> Values
{
get
{
if(!useDictionary)
{
if (singleValue.HasValue)
{
return new[] { singleValue.Value.Value };
}
}
else
{
return dictionary.Values;
}
return Enumerable.Empty<TValue>();
}
}
private class SingleEnumerator<T> : IEnumerator<T>
{
private T value;
private int index = -1;
public SingleEnumerator(T value)
{
this.value = value;
}
public T Current
{
get
{
if (index == 0)
{
return value;
}
else
{
throw new InvalidOperationException();
}
}
}
object IEnumerator.Current => Current;
public void Dispose()
{
}
public bool MoveNext()
{
index++;
return index < 1;
}
public void Reset()
{
index = -1;
}
}
}
}
Loading…
Cancel
Save