// ConcurrentDictionary.cs // // Copyright (c) 2009 Jérémie "Garuma" Laval // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; namespace Xamarin.Forms { internal class ConcurrentDictionary : IDictionary, ICollection>, IEnumerable>, IDictionary, ICollection, IEnumerable { readonly IEqualityComparer _comparer; SplitOrderedList> _internalDictionary; public ConcurrentDictionary() : this(EqualityComparer.Default) { } public ConcurrentDictionary(IEnumerable> collection) : this(collection, EqualityComparer.Default) { } public ConcurrentDictionary(IEqualityComparer comparer) { _comparer = comparer; _internalDictionary = new SplitOrderedList>(comparer); } public ConcurrentDictionary(IEnumerable> collection, IEqualityComparer comparer) : this(comparer) { foreach (KeyValuePair pair in collection) Add(pair.Key, pair.Value); } // Parameters unused public ConcurrentDictionary(int concurrencyLevel, int capacity) : this(EqualityComparer.Default) { } public ConcurrentDictionary(int concurrencyLevel, IEnumerable> collection, IEqualityComparer comparer) : this(collection, comparer) { } // Parameters unused public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer comparer) : this(comparer) { } public bool IsEmpty { get { return Count == 0; } } void ICollection.CopyTo(Array array, int startIndex) { var arr = array as KeyValuePair[]; if (arr == null) return; CopyTo(arr, startIndex, Count); } bool ICollection.IsSynchronized { get { return true; } } object ICollection.SyncRoot { get { return this; } } void ICollection>.Add(KeyValuePair pair) { Add(pair.Key, pair.Value); } public void Clear() { // Pronk _internalDictionary = new SplitOrderedList>(_comparer); } bool ICollection>.Contains(KeyValuePair pair) { return ContainsKey(pair.Key); } void ICollection>.CopyTo(KeyValuePair[] array, int startIndex) { CopyTo(array, startIndex); } public int Count { get { return _internalDictionary.Count; } } bool ICollection>.IsReadOnly { get { return false; } } bool ICollection>.Remove(KeyValuePair pair) { return Remove(pair.Key); } void IDictionary.Add(object key, object value) { if (!(key is TKey) || !(value is TValue)) throw new ArgumentException("key or value aren't of correct type"); Add((TKey)key, (TValue)value); } bool IDictionary.Contains(object key) { if (!(key is TKey)) return false; return ContainsKey((TKey)key); } IDictionaryEnumerator IDictionary.GetEnumerator() { return new ConcurrentDictionaryEnumerator(GetEnumeratorInternal()); } bool IDictionary.IsFixedSize { get { return false; } } bool IDictionary.IsReadOnly { get { return false; } } object IDictionary.this[object key] { get { if (!(key is TKey)) throw new ArgumentException("key isn't of correct type", "key"); return this[(TKey)key]; } set { if (!(key is TKey) || !(value is TValue)) throw new ArgumentException("key or value aren't of correct type"); this[(TKey)key] = (TValue)value; } } ICollection IDictionary.Keys { get { return (ICollection)Keys; } } void IDictionary.Remove(object key) { if (!(key is TKey)) return; Remove((TKey)key); } ICollection IDictionary.Values { get { return (ICollection)Values; } } void IDictionary.Add(TKey key, TValue value) { Add(key, value); } public bool ContainsKey(TKey key) { CheckKey(key); KeyValuePair dummy; return _internalDictionary.Find(Hash(key), key, out dummy); } public TValue this[TKey key] { get { return GetValue(key); } set { AddOrUpdate(key, value, value); } } public ICollection Keys { get { return GetPart(kvp => kvp.Key); } } bool IDictionary.Remove(TKey key) { return Remove(key); } public bool TryGetValue(TKey key, out TValue value) { CheckKey(key); KeyValuePair pair; bool result = _internalDictionary.Find(Hash(key), key, out pair); value = pair.Value; return result; } public ICollection Values { get { return GetPart(kvp => kvp.Value); } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumeratorInternal(); } public IEnumerator> GetEnumerator() { return GetEnumeratorInternal(); } public TValue AddOrUpdate(TKey key, Func addValueFactory, Func updateValueFactory) { CheckKey(key); if (addValueFactory == null) throw new ArgumentNullException("addValueFactory"); if (updateValueFactory == null) throw new ArgumentNullException("updateValueFactory"); return _internalDictionary.InsertOrUpdate(Hash(key), key, () => Make(key, addValueFactory(key)), e => Make(key, updateValueFactory(key, e.Value))).Value; } public TValue AddOrUpdate(TKey key, TValue addValue, Func updateValueFactory) { return AddOrUpdate(key, _ => addValue, updateValueFactory); } public TValue GetOrAdd(TKey key, Func valueFactory) { CheckKey(key); return _internalDictionary.InsertOrGet(Hash(key), key, Make(key, default(TValue)), () => Make(key, valueFactory(key))).Value; } public TValue GetOrAdd(TKey key, TValue value) { CheckKey(key); return _internalDictionary.InsertOrGet(Hash(key), key, Make(key, value), null).Value; } public KeyValuePair[] ToArray() { // This is most certainly not optimum but there is // not a lot of possibilities return new List>(this).ToArray(); } public bool TryAdd(TKey key, TValue value) { CheckKey(key); return _internalDictionary.Insert(Hash(key), key, Make(key, value)); } public bool TryRemove(TKey key, out TValue value) { CheckKey(key); KeyValuePair data; bool result = _internalDictionary.Delete(Hash(key), key, out data); value = data.Value; return result; } public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue) { CheckKey(key); return _internalDictionary.CompareExchange(Hash(key), key, Make(key, newValue), e => e.Value.Equals(comparisonValue)); } void Add(TKey key, TValue value) { while (!TryAdd(key, value)) ; } TValue AddOrUpdate(TKey key, TValue addValue, TValue updateValue) { CheckKey(key); return _internalDictionary.InsertOrUpdate(Hash(key), key, Make(key, addValue), Make(key, updateValue)).Value; } void CheckKey(TKey key) { if (key == null) throw new ArgumentNullException("key"); } void CopyTo(KeyValuePair[] array, int startIndex) { CopyTo(array, startIndex, Count); } void CopyTo(KeyValuePair[] array, int startIndex, int num) { foreach (KeyValuePair kvp in this) { array[startIndex++] = kvp; if (--num <= 0) return; } } IEnumerator> GetEnumeratorInternal() { return _internalDictionary.GetEnumerator(); } ICollection GetPart(Func, T> extractor) { var temp = new List(); foreach (KeyValuePair kvp in this) temp.Add(extractor(kvp)); return new ReadOnlyCollection(temp); } TValue GetValue(TKey key) { TValue temp; if (!TryGetValue(key, out temp)) throw new KeyNotFoundException(key.ToString()); return temp; } uint Hash(TKey key) { return (uint)_comparer.GetHashCode(key); } static KeyValuePair Make(T key, V value) { return new KeyValuePair(key, value); } bool Remove(TKey key) { TValue dummy; return TryRemove(key, out dummy); } class ConcurrentDictionaryEnumerator : IDictionaryEnumerator { readonly IEnumerator> _internalEnum; public ConcurrentDictionaryEnumerator(IEnumerator> internalEnum) { _internalEnum = internalEnum; } public DictionaryEntry Entry { get { KeyValuePair current = _internalEnum.Current; return new DictionaryEntry(current.Key, current.Value); } } public object Key { get { return _internalEnum.Current.Key; } } public object Value { get { return _internalEnum.Current.Value; } } public object Current { get { return Entry; } } public bool MoveNext() { return _internalEnum.MoveNext(); } public void Reset() { _internalEnum.Reset(); } } } }