1 // ConcurrentDictionary.cs
3 // Copyright (c) 2009 Jérémie "Garuma" Laval
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 using System.Threading;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Runtime.Serialization;
32 using System.Diagnostics;
34 namespace System.Collections.Concurrent
36 [DebuggerDisplay ("Count={Count}")]
37 [DebuggerTypeProxy (typeof (CollectionDebuggerView<,>))]
39 public class ConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>,
40 ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>,
41 IDictionary, ICollection, IEnumerable
43 IEqualityComparer<TKey> comparer;
45 SplitOrderedList<TKey, KeyValuePair<TKey, TValue>> internalDictionary;
47 public ConcurrentDictionary () : this (EqualityComparer<TKey>.Default)
51 public ConcurrentDictionary (IEnumerable<KeyValuePair<TKey, TValue>> collection)
52 : this (collection, EqualityComparer<TKey>.Default)
56 public ConcurrentDictionary (IEqualityComparer<TKey> comparer)
58 this.comparer = comparer;
59 this.internalDictionary = new SplitOrderedList<TKey, KeyValuePair<TKey, TValue>> (comparer);
62 public ConcurrentDictionary (IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer)
65 foreach (KeyValuePair<TKey, TValue> pair in collection)
66 Add (pair.Key, pair.Value);
70 public ConcurrentDictionary (int concurrencyLevel, int capacity)
71 : this (EqualityComparer<TKey>.Default)
76 public ConcurrentDictionary (int concurrencyLevel,
77 IEnumerable<KeyValuePair<TKey, TValue>> collection,
78 IEqualityComparer<TKey> comparer)
79 : this (collection, comparer)
85 public ConcurrentDictionary (int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer)
91 void CheckKey (TKey key)
94 throw new ArgumentNullException ("key");
97 void Add (TKey key, TValue value)
99 while (!TryAdd (key, value));
102 void IDictionary<TKey, TValue>.Add (TKey key, TValue value)
107 public bool TryAdd (TKey key, TValue value)
110 return internalDictionary.Insert (Hash (key), key, Make (key, value));
113 void ICollection<KeyValuePair<TKey,TValue>>.Add (KeyValuePair<TKey, TValue> pair)
115 Add (pair.Key, pair.Value);
118 public TValue AddOrUpdate (TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory)
121 if (addValueFactory == null)
122 throw new ArgumentNullException ("addValueFactory");
123 if (updateValueFactory == null)
124 throw new ArgumentNullException ("updateValueFactory");
125 return internalDictionary.InsertOrUpdate (Hash (key),
127 () => Make (key, addValueFactory (key)),
128 (e) => Make (key, updateValueFactory (key, e.Value))).Value;
131 public TValue AddOrUpdate (TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory)
133 return AddOrUpdate (key, (_) => addValue, updateValueFactory);
136 TValue AddOrUpdate (TKey key, TValue addValue, TValue updateValue)
139 return internalDictionary.InsertOrUpdate (Hash (key),
141 Make (key, addValue),
142 Make (key, updateValue)).Value;
145 TValue GetValue (TKey key)
148 if (!TryGetValue (key, out temp))
149 throw new KeyNotFoundException (key.ToString ());
153 public bool TryGetValue (TKey key, out TValue value)
156 KeyValuePair<TKey, TValue> pair;
157 bool result = internalDictionary.Find (Hash (key), key, out pair);
163 public bool TryUpdate (TKey key, TValue newValue, TValue comparisonValue)
166 return internalDictionary.CompareExchange (Hash (key), key, Make (key, newValue), (e) => e.Value.Equals (comparisonValue));
169 public TValue this[TKey key] {
171 return GetValue (key);
174 AddOrUpdate (key, value, value);
178 public TValue GetOrAdd (TKey key, Func<TKey, TValue> valueFactory)
181 return internalDictionary.InsertOrGet (Hash (key), key, Make (key, default(TValue)), () => Make (key, valueFactory (key))).Value;
184 public TValue GetOrAdd (TKey key, TValue value)
187 return internalDictionary.InsertOrGet (Hash (key), key, Make (key, value), null).Value;
190 public bool TryRemove (TKey key, out TValue value)
193 KeyValuePair<TKey, TValue> data;
194 bool result = internalDictionary.Delete (Hash (key), key, out data);
199 bool Remove (TKey key)
203 return TryRemove (key, out dummy);
206 bool IDictionary<TKey, TValue>.Remove (TKey key)
211 bool ICollection<KeyValuePair<TKey,TValue>>.Remove (KeyValuePair<TKey,TValue> pair)
213 return Remove (pair.Key);
216 public bool ContainsKey (TKey key)
219 KeyValuePair<TKey, TValue> dummy;
220 return internalDictionary.Find (Hash (key), key, out dummy);
223 bool IDictionary.Contains (object key)
228 return ContainsKey ((TKey)key);
231 void IDictionary.Remove (object key)
239 object IDictionary.this [object key]
243 throw new ArgumentException ("key isn't of correct type", "key");
245 return this[(TKey)key];
248 if (!(key is TKey) || !(value is TValue))
249 throw new ArgumentException ("key or value aren't of correct type");
251 this[(TKey)key] = (TValue)value;
255 void IDictionary.Add (object key, object value)
257 if (!(key is TKey) || !(value is TValue))
258 throw new ArgumentException ("key or value aren't of correct type");
260 Add ((TKey)key, (TValue)value);
263 bool ICollection<KeyValuePair<TKey,TValue>>.Contains (KeyValuePair<TKey, TValue> pair)
265 return ContainsKey (pair.Key);
268 public KeyValuePair<TKey,TValue>[] ToArray ()
270 // This is most certainly not optimum but there is
271 // not a lot of possibilities
273 return new List<KeyValuePair<TKey,TValue>> (this).ToArray ();
279 internalDictionary = new SplitOrderedList<TKey, KeyValuePair<TKey, TValue>> (comparer);
284 return internalDictionary.Count;
288 public bool IsEmpty {
294 bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
300 bool IDictionary.IsReadOnly {
306 public ICollection<TKey> Keys {
308 return GetPart<TKey> ((kvp) => kvp.Key);
312 public ICollection<TValue> Values {
314 return GetPart<TValue> ((kvp) => kvp.Value);
318 ICollection IDictionary.Keys {
320 return (ICollection)Keys;
324 ICollection IDictionary.Values {
326 return (ICollection)Values;
330 ICollection<T> GetPart<T> (Func<KeyValuePair<TKey, TValue>, T> extractor)
332 List<T> temp = new List<T> ();
334 foreach (KeyValuePair<TKey, TValue> kvp in this)
335 temp.Add (extractor (kvp));
337 return temp.AsReadOnly ();
340 void ICollection.CopyTo (Array array, int startIndex)
342 KeyValuePair<TKey, TValue>[] arr = array as KeyValuePair<TKey, TValue>[];
346 CopyTo (arr, startIndex, Count);
349 void CopyTo (KeyValuePair<TKey, TValue>[] array, int startIndex)
351 CopyTo (array, startIndex, Count);
354 void ICollection<KeyValuePair<TKey, TValue>>.CopyTo (KeyValuePair<TKey, TValue>[] array, int startIndex)
356 CopyTo (array, startIndex);
359 void CopyTo (KeyValuePair<TKey, TValue>[] array, int startIndex, int num)
361 foreach (var kvp in this) {
362 array [startIndex++] = kvp;
369 public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator ()
371 return GetEnumeratorInternal ();
374 IEnumerator IEnumerable.GetEnumerator ()
376 return (IEnumerator)GetEnumeratorInternal ();
379 IEnumerator<KeyValuePair<TKey, TValue>> GetEnumeratorInternal ()
381 return internalDictionary.GetEnumerator ();
384 IDictionaryEnumerator IDictionary.GetEnumerator ()
386 return new ConcurrentDictionaryEnumerator (GetEnumeratorInternal ());
389 class ConcurrentDictionaryEnumerator : IDictionaryEnumerator
391 IEnumerator<KeyValuePair<TKey, TValue>> internalEnum;
393 public ConcurrentDictionaryEnumerator (IEnumerator<KeyValuePair<TKey, TValue>> internalEnum)
395 this.internalEnum = internalEnum;
398 public bool MoveNext ()
400 return internalEnum.MoveNext ();
405 internalEnum.Reset ();
408 public object Current {
414 public DictionaryEntry Entry {
416 KeyValuePair<TKey, TValue> current = internalEnum.Current;
417 return new DictionaryEntry (current.Key, current.Value);
423 return internalEnum.Current.Key;
427 public object Value {
429 return internalEnum.Current.Value;
434 object ICollection.SyncRoot {
440 bool IDictionary.IsFixedSize {
446 bool ICollection.IsSynchronized {
450 static KeyValuePair<U, V> Make<U, V> (U key, V value)
452 return new KeyValuePair<U, V> (key, value);
457 return (uint)comparer.GetHashCode (key);