#if MONO using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Runtime; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Security.Permissions; using System.Threading; namespace System.Collections.Concurrent { /// Represents a thread-safe collection of key-value pairs that can be accessed by multiple threads concurrently. /// The type of the keys in the dictionary. /// The type of the values in the dictionary. [__DynamicallyInvokable, DebuggerDisplay("Count = {Count}"), ComVisible(false)] [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] [Serializable] public class ConcurrentDictionary : IDictionary, ICollection>, IEnumerable>, IDictionary, ICollection, IEnumerable { private class Tables { internal readonly ConcurrentDictionary.Node[] m_buckets; internal readonly object[] m_locks; internal volatile int[] m_countPerLock; internal Tables(ConcurrentDictionary.Node[] buckets, object[] locks, int[] countPerLock) { this.m_buckets = buckets; this.m_locks = locks; this.m_countPerLock = countPerLock; } } private class Node { internal TKey m_key; internal TValue m_value; internal volatile ConcurrentDictionary.Node m_next; internal int m_hashcode; internal Node(TKey key, TValue value, int hashcode, ConcurrentDictionary.Node next) { this.m_key = key; this.m_value = value; this.m_next = next; this.m_hashcode = hashcode; } } private class DictionaryEnumerator : IDictionaryEnumerator, IEnumerator { private IEnumerator> m_enumerator; public DictionaryEntry Entry { get { KeyValuePair current = this.m_enumerator.Current; object arg_30_0 = current.Key; KeyValuePair current2 = this.m_enumerator.Current; return new DictionaryEntry(arg_30_0, current2.Value); } } public object Key { get { KeyValuePair current = this.m_enumerator.Current; return current.Key; } } public object Value { get { KeyValuePair current = this.m_enumerator.Current; return current.Value; } } public object Current { get { return this.Entry; } } internal DictionaryEnumerator(ConcurrentDictionary dictionary) { this.m_enumerator = dictionary.GetEnumerator(); } public bool MoveNext() { return this.m_enumerator.MoveNext(); } public void Reset() { this.m_enumerator.Reset(); } } [NonSerialized] private volatile ConcurrentDictionary.Tables m_tables; private readonly IEqualityComparer m_comparer; [NonSerialized] private readonly bool m_growLockArray; [NonSerialized] private int m_budget; private KeyValuePair[] m_serializationArray; private int m_serializationConcurrencyLevel; private int m_serializationCapacity; private static readonly bool s_isValueWriteAtomic = ConcurrentDictionary.IsValueWriteAtomic(); private const int DEFAULT_CONCURRENCY_MULTIPLIER = 4; private const int DEFAULT_CAPACITY = 31; private const int MAX_LOCK_NUMBER = 1024; /// Gets or sets the value associated with the specified key. /// Returns the Value property of the at the specified index. /// The key of the value to get or set. /// /// is a null reference (Nothing in Visual Basic). /// The property is retrieved and does not exist in the collection. [__DynamicallyInvokable] public TValue this[TKey key] { [__DynamicallyInvokable] get { TValue result; if (!this.TryGetValue(key, out result)) { throw new KeyNotFoundException(); } return result; } [__DynamicallyInvokable] set { if (key == null) { throw new ArgumentNullException("key"); } TValue tValue; this.TryAddInternal(key, value, true, true, out tValue); } } /// Gets the number of key/value pairs contained in the . /// The number of key/value pairs contained in the . /// The dictionary already contains the maximum number of elements, . [__DynamicallyInvokable] public int Count { [__DynamicallyInvokable] get { int num = 0; int toExclusive = 0; try { this.AcquireAllLocks(ref toExclusive); for (int i = 0; i < this.m_tables.m_countPerLock.Length; i++) { num += this.m_tables.m_countPerLock[i]; } } finally { this.ReleaseLocks(0, toExclusive); } return num; } } /// Gets a value that indicates whether the is empty. /// true if the is empty; otherwise, false. [__DynamicallyInvokable] public bool IsEmpty { [__DynamicallyInvokable] get { int toExclusive = 0; try { this.AcquireAllLocks(ref toExclusive); for (int i = 0; i < this.m_tables.m_countPerLock.Length; i++) { if (this.m_tables.m_countPerLock[i] != 0) { return false; } } } finally { this.ReleaseLocks(0, toExclusive); } return true; } } /// Gets a collection containing the keys in the . /// An containing the keys in the . [__DynamicallyInvokable] public ICollection Keys { [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get { return this.GetKeys(); } } /// Gets a collection containing the values in the . /// An containing the values in the . [__DynamicallyInvokable] public ICollection Values { [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get { return this.GetValues(); } } [__DynamicallyInvokable] bool ICollection>.IsReadOnly { [__DynamicallyInvokable] get { return false; } } /// Gets a value indicating whether the has a fixed size. /// true if the has a fixed size; otherwise, false. For , this property always returns false. [__DynamicallyInvokable] bool IDictionary.IsFixedSize { [__DynamicallyInvokable] get { return false; } } /// Gets a value indicating whether the is read-only. /// true if the is read-only; otherwise, false. For , this property always returns false. [__DynamicallyInvokable] bool IDictionary.IsReadOnly { [__DynamicallyInvokable] get { return false; } } /// Gets an containing the keys of the . /// An containing the keys of the . [__DynamicallyInvokable] ICollection IDictionary.Keys { [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get { return this.GetKeys(); } } /// Gets an containing the values in the . /// An containing the values in the . [__DynamicallyInvokable] ICollection IDictionary.Values { [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get { return this.GetValues(); } } /// Gets or sets the value associated with the specified key. /// The value associated with the specified key, or a null reference (Nothing in Visual Basic) if is not in the dictionary or is of a type that is not assignable to the key type of the . /// The key of the value to get or set. /// /// is a null reference (Nothing in Visual Basic). /// A value is being assigned, and is of a type that is not assignable to the key type of the . -or- A value is being assigned, and is of a type that is not assignable to the value type of the [__DynamicallyInvokable] object IDictionary.this[object key] { [__DynamicallyInvokable] get { if (key == null) { throw new ArgumentNullException("key"); } TValue tValue; if (key is TKey && this.TryGetValue((TKey)((object)key), out tValue)) { return tValue; } return null; } [__DynamicallyInvokable] set { if (key == null) { throw new ArgumentNullException("key"); } if (!(key is TKey)) { throw new ArgumentException(this.GetResource("ConcurrentDictionary_TypeOfKeyIncorrect")); } if (!(value is TValue)) { throw new ArgumentException(this.GetResource("ConcurrentDictionary_TypeOfValueIncorrect")); } this[(TKey)((object)key)] = (TValue)((object)value); } } /// Gets a value indicating whether access to the is synchronized with the SyncRoot. /// true if access to the is synchronized (thread safe); otherwise, false. For , this property always returns false. [__DynamicallyInvokable] bool ICollection.IsSynchronized { [__DynamicallyInvokable] get { return false; } } /// Gets an object that can be used to synchronize access to the . This property is not supported. /// Always returns null. /// The SyncRoot property is not supported. [__DynamicallyInvokable] object ICollection.SyncRoot { [__DynamicallyInvokable] get { throw new NotSupportedException("ConcurrentCollection_SyncRoot_NotSupported"); } } private static int DefaultConcurrencyLevel { get { return 4 * PlatformHelper.ProcessorCount; } } private static bool IsValueWriteAtomic() { Type typeFromHandle = typeof(TValue); bool flag = typeFromHandle.IsClass || typeFromHandle == typeof(bool) || typeFromHandle == typeof(char) || typeFromHandle == typeof(byte) || typeFromHandle == typeof(sbyte) || typeFromHandle == typeof(short) || typeFromHandle == typeof(ushort) || typeFromHandle == typeof(int) || typeFromHandle == typeof(uint) || typeFromHandle == typeof(float); if (!flag && IntPtr.Size == 8) { flag |= (typeFromHandle == typeof(double) || typeFromHandle == typeof(long)); } return flag; } /// Initializes a new instance of the class that is empty, has the default concurrency level, has the default initial capacity, and uses the default comparer for the key type. [__DynamicallyInvokable] public ConcurrentDictionary() : this(ConcurrentDictionary.DefaultConcurrencyLevel, 31, true, EqualityComparer.Default) { } /// Initializes a new instance of the class that is empty, has the specified concurrency level and capacity, and uses the default comparer for the key type. /// The estimated number of threads that will update the concurrently. /// The initial number of elements that the can contain. /// /// is less than 1.-or- is less than 0. [__DynamicallyInvokable] public ConcurrentDictionary(int concurrencyLevel, int capacity) : this(concurrencyLevel, capacity, false, EqualityComparer.Default) { } /// Initializes a new instance of the class that contains elements copied from the specified , has the default concurrency level, has the default initial capacity, and uses the default comparer for the key type. /// The whose elements are copied to the new . /// /// or any of its keys is a null reference (Nothing in Visual Basic) /// /// contains one or more duplicate keys. [__DynamicallyInvokable] public ConcurrentDictionary(IEnumerable> collection) : this(collection, EqualityComparer.Default) { } /// Initializes a new instance of the class that is empty, has the default concurrency level and capacity, and uses the specified . /// The implementation to use when comparing keys. /// /// is a null reference (Nothing in Visual Basic). [__DynamicallyInvokable] public ConcurrentDictionary(IEqualityComparer comparer) : this(ConcurrentDictionary.DefaultConcurrencyLevel, 31, true, comparer) { } /// Initializes a new instance of the class that contains elements copied from the specified , has the default concurrency level, has the default initial capacity, and uses the specified . /// The whose elements are copied to the new . /// The implementation to use when comparing keys. /// /// is a null reference (Nothing in Visual Basic). -or- is a null reference (Nothing in Visual Basic). [__DynamicallyInvokable] public ConcurrentDictionary(IEnumerable> collection, IEqualityComparer comparer) : this(comparer) { if (collection == null) { throw new ArgumentNullException("collection"); } this.InitializeFromCollection(collection); } /// Initializes a new instance of the class that contains elements copied from the specified , and uses the specified . /// The estimated number of threads that will update the concurrently. /// The whose elements are copied to the new . /// The implementation to use when comparing keys. /// /// is a null reference (Nothing in Visual Basic). -or- is a null reference (Nothing in Visual Basic). /// /// is less than 1. /// /// contains one or more duplicate keys. [__DynamicallyInvokable] public ConcurrentDictionary(int concurrencyLevel, IEnumerable> collection, IEqualityComparer comparer) : this(concurrencyLevel, 31, false, comparer) { if (collection == null) { throw new ArgumentNullException("collection"); } if (comparer == null) { throw new ArgumentNullException("comparer"); } this.InitializeFromCollection(collection); } private void InitializeFromCollection(IEnumerable> collection) { foreach (KeyValuePair current in collection) { if (current.Key == null) { throw new ArgumentNullException("key"); } TValue tValue; if (!this.TryAddInternal(current.Key, current.Value, false, false, out tValue)) { throw new ArgumentException(this.GetResource("ConcurrentDictionary_SourceContainsDuplicateKeys")); } } if (this.m_budget == 0) { this.m_budget = this.m_tables.m_buckets.Length / this.m_tables.m_locks.Length; } } /// Initializes a new instance of the class that is empty, has the specified concurrency level, has the specified initial capacity, and uses the specified . /// The estimated number of threads that will update the concurrently. /// The initial number of elements that the can contain. /// The implementation to use when comparing keys. /// /// is a null reference (Nothing in Visual Basic). /// /// is less than 1. -or- is less than 0. [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer comparer) : this(concurrencyLevel, capacity, false, comparer) { } internal ConcurrentDictionary(int concurrencyLevel, int capacity, bool growLockArray, IEqualityComparer comparer) { if (concurrencyLevel < 1) { throw new ArgumentOutOfRangeException("concurrencyLevel", this.GetResource("ConcurrentDictionary_ConcurrencyLevelMustBePositive")); } if (capacity < 0) { throw new ArgumentOutOfRangeException("capacity", this.GetResource("ConcurrentDictionary_CapacityMustNotBeNegative")); } if (comparer == null) { throw new ArgumentNullException("comparer"); } if (capacity < concurrencyLevel) { capacity = concurrencyLevel; } object[] array = new object[concurrencyLevel]; for (int i = 0; i < array.Length; i++) { array[i] = new object(); } int[] countPerLock = new int[array.Length]; ConcurrentDictionary.Node[] array2 = new ConcurrentDictionary.Node[capacity]; this.m_tables = new ConcurrentDictionary.Tables(array2, array, countPerLock); this.m_comparer = comparer; this.m_growLockArray = growLockArray; this.m_budget = array2.Length / array.Length; } /// Attempts to add the specified key and value to the . /// true if the key/value pair was added to the successfully. If the key already exists, this method returns false. /// The key of the element to add. /// The value of the element to add. The value can be a null reference (Nothing in Visual Basic) for reference types. /// /// is null reference (Nothing in Visual Basic). /// The dictionary already contains the maximum number of elements, . [__DynamicallyInvokable] public bool TryAdd(TKey key, TValue value) { if (key == null) { throw new ArgumentNullException("key"); } TValue tValue; return this.TryAddInternal(key, value, false, true, out tValue); } /// Determines whether the contains the specified key. /// true if the contains an element with the specified key; otherwise, false. /// The key to locate in the . /// /// is a null reference (Nothing in Visual Basic). [__DynamicallyInvokable] public bool ContainsKey(TKey key) { if (key == null) { throw new ArgumentNullException("key"); } TValue tValue; return this.TryGetValue(key, out tValue); } /// Attempts to remove and return the value with the specified key from the . /// true if an object was removed successfully; otherwise, false. /// The key of the element to remove and return. /// When this method returns, contains the object removed from the or the default value of if the operation failed. /// /// is a null reference (Nothing in Visual Basic). [__DynamicallyInvokable] public bool TryRemove(TKey key, out TValue value) { if (key == null) { throw new ArgumentNullException("key"); } return this.TryRemoveInternal(key, out value, false, default(TValue)); } private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue) { while (true) { ConcurrentDictionary.Tables tables = this.m_tables; int num; int num2; this.GetBucketAndLockNo(this.m_comparer.GetHashCode(key), out num, out num2, tables.m_buckets.Length, tables.m_locks.Length); lock (tables.m_locks[num2]) { if (tables != this.m_tables) { continue; } ConcurrentDictionary.Node node = null; ConcurrentDictionary.Node node2 = tables.m_buckets[num]; while (node2 != null) { if (this.m_comparer.Equals(node2.m_key, key)) { bool result; if (matchValue && !EqualityComparer.Default.Equals(oldValue, node2.m_value)) { value = default(TValue); result = false; return result; } if (node == null) { Volatile.Write.Node>(ref tables.m_buckets[num], node2.m_next); } else { node.m_next = node2.m_next; } value = node2.m_value; tables.m_countPerLock[num2]--; result = true; return result; } else { node = node2; node2 = node2.m_next; } } } break; } value = default(TValue); return false; } /// Attempts to get the value associated with the specified key from the . /// true if the key was found in the ; otherwise, false. /// The key of the value to get. /// When this method returns, contains the object from the with the specified key or the default value of , if the operation failed. /// /// is a null reference (Nothing in Visual Basic). [__DynamicallyInvokable] public bool TryGetValue(TKey key, out TValue value) { if (key == null) { throw new ArgumentNullException("key"); } ConcurrentDictionary.Tables tables = this.m_tables; int num; int num2; this.GetBucketAndLockNo(this.m_comparer.GetHashCode(key), out num, out num2, tables.m_buckets.Length, tables.m_locks.Length); for (ConcurrentDictionary.Node node = Volatile.Read.Node>(ref tables.m_buckets[num]); node != null; node = node.m_next) { if (this.m_comparer.Equals(node.m_key, key)) { value = node.m_value; return true; } } value = default(TValue); return false; } /// Compares the existing value for the specified key with a specified value, and if they are equal, updates the key with a third value. /// true if the value with was equal to and replaced with ; otherwise, false. /// The key whose value is compared with and possibly replaced. /// The value that replaces the value of the element with if the comparison results in equality. /// The value that is compared to the value of the element with . /// /// is a null reference. [__DynamicallyInvokable] public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue) { if (key == null) { throw new ArgumentNullException("key"); } int hashCode = this.m_comparer.GetHashCode(key); IEqualityComparer @default = EqualityComparer.Default; bool result; while (true) { ConcurrentDictionary.Tables tables = this.m_tables; int num; int num2; this.GetBucketAndLockNo(hashCode, out num, out num2, tables.m_buckets.Length, tables.m_locks.Length); lock (tables.m_locks[num2]) { if (tables != this.m_tables) { continue; } ConcurrentDictionary.Node node = null; ConcurrentDictionary.Node node2 = tables.m_buckets[num]; while (node2 != null) { if (this.m_comparer.Equals(node2.m_key, key)) { if (@default.Equals(node2.m_value, comparisonValue)) { if (ConcurrentDictionary.s_isValueWriteAtomic) { node2.m_value = newValue; } else { ConcurrentDictionary.Node node3 = new ConcurrentDictionary.Node(node2.m_key, newValue, hashCode, node2.m_next); if (node == null) { tables.m_buckets[num] = node3; } else { node.m_next = node3; } } result = true; return result; } result = false; return result; } else { node = node2; node2 = node2.m_next; } } result = false; } break; } return result; } /// Removes all keys and values from the . [__DynamicallyInvokable] public void Clear() { int toExclusive = 0; try { this.AcquireAllLocks(ref toExclusive); ConcurrentDictionary.Tables tables = new ConcurrentDictionary.Tables(new ConcurrentDictionary.Node[31], this.m_tables.m_locks, new int[this.m_tables.m_countPerLock.Length]); this.m_tables = tables; this.m_budget = Math.Max(1, tables.m_buckets.Length / tables.m_locks.Length); } finally { this.ReleaseLocks(0, toExclusive); } } [__DynamicallyInvokable] void ICollection>.CopyTo(KeyValuePair[] array, int index) { if (array == null) { throw new ArgumentNullException("array"); } if (index < 0) { throw new ArgumentOutOfRangeException("index", this.GetResource("ConcurrentDictionary_IndexIsNegative")); } int toExclusive = 0; try { this.AcquireAllLocks(ref toExclusive); int num = 0; int num2 = 0; while (num2 < this.m_tables.m_locks.Length && num >= 0) { num += this.m_tables.m_countPerLock[num2]; num2++; } if (array.Length - num < index || num < 0) { throw new ArgumentException(this.GetResource("ConcurrentDictionary_ArrayNotLargeEnough")); } this.CopyToPairs(array, index); } finally { this.ReleaseLocks(0, toExclusive); } } /// Copies the key and value pairs stored in the to a new array. /// A new array containing a snapshot of key and value pairs copied from the . [__DynamicallyInvokable] public KeyValuePair[] ToArray() { int toExclusive = 0; checked { KeyValuePair[] result; try { this.AcquireAllLocks(ref toExclusive); int num = 0; for (int i = 0; i < this.m_tables.m_locks.Length; i++) { num += this.m_tables.m_countPerLock[i]; } KeyValuePair[] array = new KeyValuePair[num]; this.CopyToPairs(array, 0); result = array; } finally { this.ReleaseLocks(0, toExclusive); } return result; } } private void CopyToPairs(KeyValuePair[] array, int index) { ConcurrentDictionary.Node[] buckets = this.m_tables.m_buckets; for (int i = 0; i < buckets.Length; i++) { for (ConcurrentDictionary.Node node = buckets[i]; node != null; node = node.m_next) { array[index] = new KeyValuePair(node.m_key, node.m_value); index++; } } } private void CopyToEntries(DictionaryEntry[] array, int index) { ConcurrentDictionary.Node[] buckets = this.m_tables.m_buckets; for (int i = 0; i < buckets.Length; i++) { for (ConcurrentDictionary.Node node = buckets[i]; node != null; node = node.m_next) { array[index] = new DictionaryEntry(node.m_key, node.m_value); index++; } } } private void CopyToObjects(object[] array, int index) { ConcurrentDictionary.Node[] buckets = this.m_tables.m_buckets; for (int i = 0; i < buckets.Length; i++) { for (ConcurrentDictionary.Node node = buckets[i]; node != null; node = node.m_next) { array[index] = new KeyValuePair(node.m_key, node.m_value); index++; } } } /// Returns an enumerator that iterates through the . /// An enumerator for the . [__DynamicallyInvokable] public IEnumerator> GetEnumerator() { ConcurrentDictionary.Node[] buckets = this.m_tables.m_buckets; for (int i = 0; i < buckets.Length; i++) { for (ConcurrentDictionary.Node node = Volatile.Read.Node>(ref buckets[i]); node != null; node = node.m_next) { yield return new KeyValuePair(node.m_key, node.m_value); } } yield break; } private bool TryAddInternal(TKey key, TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue) { int hashCode = this.m_comparer.GetHashCode(key); checked { ConcurrentDictionary.Tables tables; bool flag; while (true) { tables = this.m_tables; int num; int num2; this.GetBucketAndLockNo(hashCode, out num, out num2, tables.m_buckets.Length, tables.m_locks.Length); flag = false; bool flag2 = false; try { if (acquireLock) { Monitor.Enter(tables.m_locks[num2]); flag2 = true; } if (tables != this.m_tables) { continue; } ConcurrentDictionary.Node node = null; for (ConcurrentDictionary.Node node2 = tables.m_buckets[num]; node2 != null; node2 = node2.m_next) { if (this.m_comparer.Equals(node2.m_key, key)) { if (updateIfExists) { if (ConcurrentDictionary.s_isValueWriteAtomic) { node2.m_value = value; } else { ConcurrentDictionary.Node node3 = new ConcurrentDictionary.Node(node2.m_key, value, hashCode, node2.m_next); if (node == null) { tables.m_buckets[num] = node3; } else { node.m_next = node3; } } resultingValue = value; } else { resultingValue = node2.m_value; } return false; } node = node2; } Volatile.Write.Node>(ref tables.m_buckets[num], new ConcurrentDictionary.Node(key, value, hashCode, tables.m_buckets[num])); tables.m_countPerLock[num2]++; if (tables.m_countPerLock[num2] > this.m_budget) { flag = true; } } finally { if (flag2) { Monitor.Exit(tables.m_locks[num2]); } } break; } if (flag) { this.GrowTable(tables); } resultingValue = value; return true; } } /// Adds a key/value pair to the if the key does not already exist. /// The value for the key. This will be either the existing value for the key if the key is already in the dictionary, or the new value for the key as returned by valueFactory if the key was not in the dictionary. /// The key of the element to add. /// The function used to generate a value for the key /// /// is a null reference (Nothing in Visual Basic).-or- is a null reference (Nothing in Visual Basic). /// The dictionary already contains the maximum number of elements, . [__DynamicallyInvokable] public TValue GetOrAdd(TKey key, Func valueFactory) { if (key == null) { throw new ArgumentNullException("key"); } if (valueFactory == null) { throw new ArgumentNullException("valueFactory"); } TValue result; if (this.TryGetValue(key, out result)) { return result; } this.TryAddInternal(key, valueFactory(key), false, true, out result); return result; } /// Adds a key/value pair to the if the key does not already exist. /// The value for the key. This will be either the existing value for the key if the key is already in the dictionary, or the new value if the key was not in the dictionary. /// The key of the element to add. /// the value to be added, if the key does not already exist /// /// is a null reference (Nothing in Visual Basic). /// The dictionary already contains the maximum number of elements, . [__DynamicallyInvokable] public TValue GetOrAdd(TKey key, TValue value) { if (key == null) { throw new ArgumentNullException("key"); } TValue result; this.TryAddInternal(key, value, false, true, out result); return result; } /// Adds a key/value pair to the if the key does not already exist, or updates a key/value pair in the if the key already exists. /// The new value for the key. This will be either be the result of addValueFactory (if the key was absent) or the result of updateValueFactory (if the key was present). /// The key to be added or whose value should be updated /// The function used to generate a value for an absent key /// The function used to generate a new value for an existing key based on the key's existing value /// /// is a null reference (Nothing in Visual Basic).-or- is a null reference (Nothing in Visual Basic).-or- is a null reference (Nothing in Visual Basic). /// The dictionary already contains the maximum number of elements, . [__DynamicallyInvokable] public TValue AddOrUpdate(TKey key, Func addValueFactory, Func updateValueFactory) { if (key == null) { throw new ArgumentNullException("key"); } if (addValueFactory == null) { throw new ArgumentNullException("addValueFactory"); } if (updateValueFactory == null) { throw new ArgumentNullException("updateValueFactory"); } TValue tValue2; while (true) { TValue tValue; if (this.TryGetValue(key, out tValue)) { tValue2 = updateValueFactory(key, tValue); if (this.TryUpdate(key, tValue2, tValue)) { break; } } else { tValue2 = addValueFactory(key); TValue result; if (this.TryAddInternal(key, tValue2, false, true, out result)) { return result; } } } return tValue2; } /// Adds a key/value pair to the if the key does not already exist, or updates a key/value pair in the if the key already exists. /// The new value for the key. This will be either be addValue (if the key was absent) or the result of updateValueFactory (if the key was present). /// The key to be added or whose value should be updated /// The value to be added for an absent key /// The function used to generate a new value for an existing key based on the key's existing value /// /// is a null reference (Nothing in Visual Basic).-or- is a null reference (Nothing in Visual Basic). /// The dictionary already contains the maximum number of elements, . [__DynamicallyInvokable] public TValue AddOrUpdate(TKey key, TValue addValue, Func updateValueFactory) { if (key == null) { throw new ArgumentNullException("key"); } if (updateValueFactory == null) { throw new ArgumentNullException("updateValueFactory"); } TValue tValue2; while (true) { TValue tValue; if (this.TryGetValue(key, out tValue)) { tValue2 = updateValueFactory(key, tValue); if (this.TryUpdate(key, tValue2, tValue)) { break; } } else { TValue result; if (this.TryAddInternal(key, addValue, false, true, out result)) { return result; } } } return tValue2; } [__DynamicallyInvokable] void IDictionary.Add(TKey key, TValue value) { if (!this.TryAdd(key, value)) { throw new ArgumentException(this.GetResource("ConcurrentDictionary_KeyAlreadyExisted")); } } [__DynamicallyInvokable] bool IDictionary.Remove(TKey key) { TValue tValue; return this.TryRemove(key, out tValue); } [__DynamicallyInvokable] void ICollection>.Add(KeyValuePair keyValuePair) { ((IDictionary)this).Add(keyValuePair.Key, keyValuePair.Value); } [__DynamicallyInvokable] bool ICollection>.Contains(KeyValuePair keyValuePair) { TValue x; return this.TryGetValue(keyValuePair.Key, out x) && EqualityComparer.Default.Equals(x, keyValuePair.Value); } [__DynamicallyInvokable] bool ICollection>.Remove(KeyValuePair keyValuePair) { if (keyValuePair.Key == null) { throw new ArgumentNullException(this.GetResource("ConcurrentDictionary_ItemKeyIsNull")); } TValue tValue; return this.TryRemoveInternal(keyValuePair.Key, out tValue, true, keyValuePair.Value); } /// Returns an enumerator that iterates through the . /// An enumerator for the . [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } /// Adds the specified key and value to the dictionary. /// The object to use as the key. /// The object to use as the value. /// /// is a null reference (Nothing in Visual Basic). /// /// is of a type that is not assignable to the key type of the . -or- is of a type that is not assignable to , the type of values in the . -or- A value with the same key already exists in the . /// The dictionary already contains the maximum number of elements, . [__DynamicallyInvokable] void IDictionary.Add(object key, object value) { if (key == null) { throw new ArgumentNullException("key"); } if (!(key is TKey)) { throw new ArgumentException(this.GetResource("ConcurrentDictionary_TypeOfKeyIncorrect")); } TValue value2; try { value2 = (TValue)((object)value); } catch (InvalidCastException) { throw new ArgumentException(this.GetResource("ConcurrentDictionary_TypeOfValueIncorrect")); } ((IDictionary)this).Add((TKey)((object)key), value2); } /// Gets whether the contains an element with the specified key. /// true if the contains an element with the specified key; otherwise, false. /// The key to locate in the . /// /// is a null reference (Nothing in Visual Basic). [__DynamicallyInvokable] bool IDictionary.Contains(object key) { if (key == null) { throw new ArgumentNullException("key"); } return key is TKey && this.ContainsKey((TKey)((object)key)); } /// Provides an for the . /// An for the . [__DynamicallyInvokable] IDictionaryEnumerator IDictionary.GetEnumerator() { return new ConcurrentDictionary.DictionaryEnumerator(this); } /// Removes the element with the specified key from the . /// The key of the element to remove. /// /// is a null reference (Nothing in Visual Basic). [__DynamicallyInvokable] void IDictionary.Remove(object key) { if (key == null) { throw new ArgumentNullException("key"); } if (key is TKey) { TValue tValue; this.TryRemove((TKey)((object)key), out tValue); } } /// Copies the elements of the to an array, starting at the specified array index. /// The one-dimensional array that is the destination of the elements copied from the . The array must have zero-based indexing. /// The zero-based index in at which copying begins. /// /// is a null reference (Nothing in Visual Basic). /// /// is less than 0. /// /// is equal to or greater than the length of the . -or- The number of elements in the source is greater than the available space from to the end of the destination . [__DynamicallyInvokable] void ICollection.CopyTo(Array array, int index) { if (array == null) { throw new ArgumentNullException("array"); } if (index < 0) { throw new ArgumentOutOfRangeException("index", this.GetResource("ConcurrentDictionary_IndexIsNegative")); } int toExclusive = 0; try { this.AcquireAllLocks(ref toExclusive); ConcurrentDictionary.Tables tables = this.m_tables; int num = 0; int num2 = 0; while (num2 < tables.m_locks.Length && num >= 0) { num += tables.m_countPerLock[num2]; num2++; } if (array.Length - num < index || num < 0) { throw new ArgumentException(this.GetResource("ConcurrentDictionary_ArrayNotLargeEnough")); } KeyValuePair[] array2 = array as KeyValuePair[]; if (array2 != null) { this.CopyToPairs(array2, index); } else { DictionaryEntry[] array3 = array as DictionaryEntry[]; if (array3 != null) { this.CopyToEntries(array3, index); } else { object[] array4 = array as object[]; if (array4 == null) { throw new ArgumentException(this.GetResource("ConcurrentDictionary_ArrayIncorrectType"), "array"); } this.CopyToObjects(array4, index); } } } finally { this.ReleaseLocks(0, toExclusive); } } private void GrowTable(ConcurrentDictionary.Tables tables) { int toExclusive = 0; try { this.AcquireLocks(0, 1, ref toExclusive); if (tables == this.m_tables) { long num = 0L; for (int i = 0; i < tables.m_countPerLock.Length; i++) { num += (long)tables.m_countPerLock[i]; } if (num < (long)(tables.m_buckets.Length / 4)) { this.m_budget = 2 * this.m_budget; if (this.m_budget < 0) { this.m_budget = 2147483647; } } else { int num2 = 0; bool flag = false; object[] array; checked { try { num2 = tables.m_buckets.Length * 2 + 1; while (num2 % 3 == 0 || num2 % 5 == 0 || num2 % 7 == 0) { num2 += 2; } if (num2 > 2146435071) { flag = true; } } catch (OverflowException) { flag = true; } if (flag) { num2 = 2146435071; this.m_budget = 2147483647; } this.AcquireLocks(1, tables.m_locks.Length, ref toExclusive); array = tables.m_locks; } if (this.m_growLockArray && tables.m_locks.Length < 1024) { array = new object[tables.m_locks.Length * 2]; Array.Copy(tables.m_locks, array, tables.m_locks.Length); for (int j = tables.m_locks.Length; j < array.Length; j++) { array[j] = new object(); } } ConcurrentDictionary.Node[] array2 = new ConcurrentDictionary.Node[num2]; int[] array3 = new int[array.Length]; for (int k = 0; k < tables.m_buckets.Length; k++) { checked { ConcurrentDictionary.Node next; for (ConcurrentDictionary.Node node = tables.m_buckets[k]; node != null; node = next) { next = node.m_next; int num3; int num4; this.GetBucketAndLockNo(node.m_hashcode, out num3, out num4, array2.Length, array.Length); array2[num3] = new ConcurrentDictionary.Node(node.m_key, node.m_value, node.m_hashcode, array2[num3]); array3[num4]++; } } } this.m_budget = Math.Max(1, array2.Length / array.Length); this.m_tables = new ConcurrentDictionary.Tables(array2, array, array3); } } } finally { this.ReleaseLocks(0, toExclusive); } } private void GetBucketAndLockNo(int hashcode, out int bucketNo, out int lockNo, int bucketCount, int lockCount) { bucketNo = (hashcode & 2147483647) % bucketCount; lockNo = bucketNo % lockCount; } private void AcquireAllLocks(ref int locksAcquired) { //if (CDSCollectionETWBCLProvider.Log.IsEnabled()) //{ // CDSCollectionETWBCLProvider.Log.ConcurrentDictionary_AcquiringAllLocks(this.m_tables.m_buckets.Length); //} this.AcquireLocks(0, 1, ref locksAcquired); this.AcquireLocks(1, this.m_tables.m_locks.Length, ref locksAcquired); } private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired) { object[] locks = this.m_tables.m_locks; for (int i = fromInclusive; i < toExclusive; i++) { bool flag = false; try { Monitor.Enter(locks[i]); flag = true; } finally { if (flag) { locksAcquired++; } } } } private void ReleaseLocks(int fromInclusive, int toExclusive) { for (int i = fromInclusive; i < toExclusive; i++) { Monitor.Exit(this.m_tables.m_locks[i]); } } private ReadOnlyCollection GetKeys() { int toExclusive = 0; ReadOnlyCollection result; try { this.AcquireAllLocks(ref toExclusive); List list = new List(); for (int i = 0; i < this.m_tables.m_buckets.Length; i++) { for (ConcurrentDictionary.Node node = this.m_tables.m_buckets[i]; node != null; node = node.m_next) { list.Add(node.m_key); } } result = new ReadOnlyCollection(list); } finally { this.ReleaseLocks(0, toExclusive); } return result; } private ReadOnlyCollection GetValues() { int toExclusive = 0; ReadOnlyCollection result; try { this.AcquireAllLocks(ref toExclusive); List list = new List(); for (int i = 0; i < this.m_tables.m_buckets.Length; i++) { for (ConcurrentDictionary.Node node = this.m_tables.m_buckets[i]; node != null; node = node.m_next) { list.Add(node.m_value); } } result = new ReadOnlyCollection(list); } finally { this.ReleaseLocks(0, toExclusive); } return result; } [Conditional("DEBUG")] private void Assert(bool condition) { } private string GetResource(string key) { return key; } [OnSerializing] private void OnSerializing(StreamingContext context) { ConcurrentDictionary.Tables tables = this.m_tables; this.m_serializationArray = this.ToArray(); this.m_serializationConcurrencyLevel = tables.m_locks.Length; this.m_serializationCapacity = tables.m_buckets.Length; } [OnDeserialized] private void OnDeserialized(StreamingContext context) { KeyValuePair[] serializationArray = this.m_serializationArray; ConcurrentDictionary.Node[] buckets = new ConcurrentDictionary.Node[this.m_serializationCapacity]; int[] countPerLock = new int[this.m_serializationConcurrencyLevel]; object[] array = new object[this.m_serializationConcurrencyLevel]; for (int i = 0; i < array.Length; i++) { array[i] = new object(); } this.m_tables = new ConcurrentDictionary.Tables(buckets, array, countPerLock); this.InitializeFromCollection(serializationArray); this.m_serializationArray = null; } } } #endif