From 3640d4dc1bb300162fa3b86bbcb797fb889ced3e Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 6 Sep 2016 12:14:38 -0500 Subject: [PATCH] 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). --- src/Avalonia.Base/Avalonia.Base.csproj | 1 + src/Avalonia.Base/PriorityValue.cs | 2 +- .../Utilities/SingleOrDictionary.cs | 147 ++++++++++++++++++ 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 src/Avalonia.Base/Utilities/SingleOrDictionary.cs diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj index 887d3ff9bd..46e24aa15a 100644 --- a/src/Avalonia.Base/Avalonia.Base.csproj +++ b/src/Avalonia.Base/Avalonia.Base.csproj @@ -118,6 +118,7 @@ + diff --git a/src/Avalonia.Base/PriorityValue.cs b/src/Avalonia.Base/PriorityValue.cs index a7eb4465b3..3f4b405de9 100644 --- a/src/Avalonia.Base/PriorityValue.cs +++ b/src/Avalonia.Base/PriorityValue.cs @@ -28,7 +28,7 @@ namespace Avalonia { private readonly IPriorityValueOwner _owner; private readonly Type _valueType; - private readonly Dictionary _levels = new Dictionary(); + private readonly SingleOrDictionary _levels = new SingleOrDictionary(); private object _value; private readonly Func _validate; diff --git a/src/Avalonia.Base/Utilities/SingleOrDictionary.cs b/src/Avalonia.Base/Utilities/SingleOrDictionary.cs new file mode 100644 index 0000000000..97d6b9ac95 --- /dev/null +++ b/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 +{ + /// + /// Stores either a single key value pair or constructs a dictionary when more than one value is stored. + /// + /// The type of the key. + /// The type of the value. + public class SingleOrDictionary : IEnumerable> + { + private KeyValuePair? singleValue; + private Dictionary dictionary; + + private bool useDictionary = false; + + public void Add(TKey key, TValue value) + { + if (singleValue != null) + { + dictionary = new Dictionary(); + ((ICollection>)dictionary).Add(singleValue.Value); + useDictionary = true; + singleValue = null; + } + + if (useDictionary) + { + dictionary.Add(key, value); + } + else + { + singleValue = new KeyValuePair(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> GetEnumerator() + { + if (!useDictionary) + { + if (singleValue.HasValue) + { + return new SingleEnumerator>(singleValue.Value); + } + } + else + { + return dictionary.GetEnumerator(); + } + return Enumerable.Empty>().GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerable Values + { + get + { + if(!useDictionary) + { + if (singleValue.HasValue) + { + return new[] { singleValue.Value.Value }; + } + } + else + { + return dictionary.Values; + } + return Enumerable.Empty(); + } + } + + private class SingleEnumerator : IEnumerator + { + 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; + } + } + + } +}