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
25 #if NET_4_0 || BOOTSTRAP_NET_4_0
28 using System.Threading;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Runtime.Serialization;
33 namespace System.Collections.Concurrent
35 public class ConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>,
36 ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>,
37 IDictionary, ICollection, IEnumerable
39 IEqualityComparer<TKey> comparer;
41 SplitOrderedList<KeyValuePair<TKey, TValue>> internalDictionary = new SplitOrderedList<KeyValuePair<TKey, TValue>> ();
43 public ConcurrentDictionary () : this (EqualityComparer<TKey>.Default)
47 public ConcurrentDictionary (IEnumerable<KeyValuePair<TKey, TValue>> values)
48 : this (values, EqualityComparer<TKey>.Default)
50 foreach (KeyValuePair<TKey, TValue> pair in values)
51 Add (pair.Key, pair.Value);
54 public ConcurrentDictionary (IEqualityComparer<TKey> comparer)
56 this.comparer = comparer;
59 public ConcurrentDictionary (IEnumerable<KeyValuePair<TKey, TValue>> values, IEqualityComparer<TKey> comparer)
62 foreach (KeyValuePair<TKey, TValue> pair in values)
63 Add (pair.Key, pair.Value);
67 public ConcurrentDictionary (int concurrencyLevel, int capacity)
68 : this (EqualityComparer<TKey>.Default)
73 public ConcurrentDictionary (int concurrencyLevel,
74 IEnumerable<KeyValuePair<TKey, TValue>> values,
75 IEqualityComparer<TKey> comparer)
76 : this (values, comparer)
82 public ConcurrentDictionary (int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer)
88 void Add (TKey key, TValue value)
90 while (!TryAdd (key, value));
93 void IDictionary<TKey, TValue>.Add (TKey key, TValue value)
98 public bool TryAdd (TKey key, TValue value)
100 return internalDictionary.Insert (Hash (key), Make (key, value));
103 void ICollection<KeyValuePair<TKey,TValue>>.Add (KeyValuePair<TKey, TValue> pair)
105 Add (pair.Key, pair.Value);
108 public TValue AddOrUpdate (TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory)
110 return internalDictionary.InsertOrUpdate (Hash (key),
111 () => Make (key, addValueFactory (key)),
112 (e) => Make (key, updateValueFactory (key, e.Value))).Value;
115 public TValue AddOrUpdate (TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory)
117 return AddOrUpdate (key, (_) => addValue, updateValueFactory);
120 TValue GetValue (TKey key)
123 if (!TryGetValue (key, out temp))
124 // TODO: find a correct Exception
125 throw new ArgumentException ("Not a valid key for this dictionary", "key");
129 public bool TryGetValue (TKey key, out TValue value)
131 KeyValuePair<TKey, TValue> pair;
132 bool result = internalDictionary.Find (Hash (key), out pair);
138 public bool TryUpdate (TKey key, TValue newValue, TValue comparand)
140 return internalDictionary.CompareExchange (Hash (key), Make (key, newValue), (e) => e.Value.Equals (comparand));
143 public TValue this[TKey key] {
145 return GetValue (key);
148 AddOrUpdate (key, (_) => value, (_, __) => value);
152 public TValue GetOrAdd (TKey key, Func<TKey, TValue> valueFactory)
154 return internalDictionary.InsertOrGet (Hash (key), Make (key, default(TValue)), () => Make (key, valueFactory (key))).Value;
157 public TValue GetOrAdd (TKey key, TValue value)
159 return internalDictionary.InsertOrGet (Hash (key), Make (key, value), null).Value;
162 public bool TryRemove (TKey key, out TValue value)
164 KeyValuePair<TKey, TValue> data;
165 bool result = internalDictionary.Delete (Hash (key), out data);
170 bool Remove (TKey key)
174 return TryRemove (key, out dummy);
177 bool IDictionary<TKey, TValue>.Remove (TKey key)
182 bool ICollection<KeyValuePair<TKey,TValue>>.Remove (KeyValuePair<TKey,TValue> pair)
184 return Remove (pair.Key);
187 public bool ContainsKey (TKey key)
189 KeyValuePair<TKey, TValue> dummy;
190 return internalDictionary.Find (Hash (key), out dummy);
193 bool IDictionary.Contains (object key)
198 return ContainsKey ((TKey)key);
201 void IDictionary.Remove (object key)
209 object IDictionary.this [object key]
213 throw new ArgumentException ("key isn't of correct type", "key");
215 return this[(TKey)key];
218 if (!(key is TKey) || !(value is TValue))
219 throw new ArgumentException ("key or value aren't of correct type");
221 this[(TKey)key] = (TValue)value;
225 void IDictionary.Add (object key, object value)
227 if (!(key is TKey) || !(value is TValue))
228 throw new ArgumentException ("key or value aren't of correct type");
230 Add ((TKey)key, (TValue)value);
233 bool ICollection<KeyValuePair<TKey,TValue>>.Contains (KeyValuePair<TKey, TValue> pair)
235 return ContainsKey (pair.Key);
238 public KeyValuePair<TKey,TValue>[] ToArray ()
240 // This is most certainly not optimum but there is
241 // not a lot of possibilities
243 return new List<KeyValuePair<TKey,TValue>> (this).ToArray ();
249 internalDictionary = new SplitOrderedList<KeyValuePair<TKey, TValue>> ();
254 return internalDictionary.Count;
258 public bool IsEmpty {
264 bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
270 bool IDictionary.IsReadOnly {
276 public ICollection<TKey> Keys {
278 return GetPart<TKey> ((kvp) => kvp.Key);
282 public ICollection<TValue> Values {
284 return GetPart<TValue> ((kvp) => kvp.Value);
288 ICollection IDictionary.Keys {
290 return (ICollection)Keys;
294 ICollection IDictionary.Values {
296 return (ICollection)Values;
300 ICollection<T> GetPart<T> (Func<KeyValuePair<TKey, TValue>, T> extractor)
302 List<T> temp = new List<T> ();
304 foreach (KeyValuePair<TKey, TValue> kvp in this)
305 temp.Add (extractor (kvp));
307 return temp.AsReadOnly ();
310 void ICollection.CopyTo (Array array, int startIndex)
312 KeyValuePair<TKey, TValue>[] arr = array as KeyValuePair<TKey, TValue>[];
316 CopyTo (arr, startIndex, Count);
319 void CopyTo (KeyValuePair<TKey, TValue>[] array, int startIndex)
321 CopyTo (array, startIndex, Count);
324 void ICollection<KeyValuePair<TKey, TValue>>.CopyTo (KeyValuePair<TKey, TValue>[] array, int startIndex)
326 CopyTo (array, startIndex);
329 void CopyTo (KeyValuePair<TKey, TValue>[] array, int startIndex, int num)
331 foreach (var kvp in this) {
332 array [startIndex++] = kvp;
339 public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator ()
341 return GetEnumeratorInternal ();
344 IEnumerator IEnumerable.GetEnumerator ()
346 return (IEnumerator)GetEnumeratorInternal ();
349 IEnumerator<KeyValuePair<TKey, TValue>> GetEnumeratorInternal ()
351 return internalDictionary.GetEnumerator ();
354 IDictionaryEnumerator IDictionary.GetEnumerator ()
356 return new ConcurrentDictionaryEnumerator (GetEnumeratorInternal ());
359 class ConcurrentDictionaryEnumerator : IDictionaryEnumerator
361 IEnumerator<KeyValuePair<TKey, TValue>> internalEnum;
363 public ConcurrentDictionaryEnumerator (IEnumerator<KeyValuePair<TKey, TValue>> internalEnum)
365 this.internalEnum = internalEnum;
368 public bool MoveNext ()
370 return internalEnum.MoveNext ();
375 internalEnum.Reset ();
378 public object Current {
384 public DictionaryEntry Entry {
386 KeyValuePair<TKey, TValue> current = internalEnum.Current;
387 return new DictionaryEntry (current.Key, current.Value);
393 return internalEnum.Current.Key;
397 public object Value {
399 return internalEnum.Current.Value;
404 object ICollection.SyncRoot {
410 bool IDictionary.IsFixedSize {
416 bool ICollection.IsSynchronized {
420 static KeyValuePair<U, V> Make<U, V> (U key, V value)
422 return new KeyValuePair<U, V> (key, value);
427 return (uint)comparer.GetHashCode (key);