Merge branch 'master' of github.com:mono/mono
[mono.git] / mcs / class / corlib / System.Collections.Concurrent / ConcurrentDictionary.cs
1 // ConcurrentDictionary.cs
2 //
3 // Copyright (c) 2009 Jérémie "Garuma" Laval
4 //
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:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
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
21 // THE SOFTWARE.
22 //
23 //
24
25 #if NET_4_0 || BOOTSTRAP_NET_4_0
26
27 using System;
28 using System.Threading;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Runtime.Serialization;
32
33 namespace System.Collections.Concurrent
34 {
35         public class ConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>,
36           ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>,
37           IDictionary, ICollection, IEnumerable
38         {
39                 IEqualityComparer<TKey> comparer;
40
41                 SplitOrderedList<KeyValuePair<TKey, TValue>> internalDictionary = new SplitOrderedList<KeyValuePair<TKey, TValue>> ();
42
43                 public ConcurrentDictionary () : this (EqualityComparer<TKey>.Default)
44                 {
45                 }
46
47                 public ConcurrentDictionary (IEnumerable<KeyValuePair<TKey, TValue>> values)
48                         : this (values, EqualityComparer<TKey>.Default)
49                 {
50                         foreach (KeyValuePair<TKey, TValue> pair in values)
51                                 Add (pair.Key, pair.Value);
52                 }
53
54                 public ConcurrentDictionary (IEqualityComparer<TKey> comparer)
55                 {
56                         this.comparer = comparer;
57                 }
58
59                 public ConcurrentDictionary (IEnumerable<KeyValuePair<TKey, TValue>> values, IEqualityComparer<TKey> comparer)
60                         : this (comparer)
61                 {
62                         foreach (KeyValuePair<TKey, TValue> pair in values)
63                                 Add (pair.Key, pair.Value);
64                 }
65
66                 // Parameters unused
67                 public ConcurrentDictionary (int concurrencyLevel, int capacity)
68                         : this (EqualityComparer<TKey>.Default)
69                 {
70
71                 }
72
73                 public ConcurrentDictionary (int concurrencyLevel,
74                                              IEnumerable<KeyValuePair<TKey, TValue>> values,
75                                              IEqualityComparer<TKey> comparer)
76                         : this (values, comparer)
77                 {
78
79                 }
80
81                 // Parameters unused
82                 public ConcurrentDictionary (int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer)
83                         : this (comparer)
84                 {
85
86                 }
87
88                 void Add (TKey key, TValue value)
89                 {
90                         while (!TryAdd (key, value));
91                 }
92
93                 void IDictionary<TKey, TValue>.Add (TKey key, TValue value)
94                 {
95                         Add (key, value);
96                 }
97
98                 public bool TryAdd (TKey key, TValue value)
99                 {
100                         return internalDictionary.Insert (Hash (key), Make (key, value));
101                 }
102
103                 void ICollection<KeyValuePair<TKey,TValue>>.Add (KeyValuePair<TKey, TValue> pair)
104                 {
105                         Add (pair.Key, pair.Value);
106                 }
107
108                 public TValue AddOrUpdate (TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory)
109                 {
110                         return internalDictionary.InsertOrUpdate (Hash (key),
111                                                                   () => Make (key, addValueFactory (key)),
112                                                                   (e) => Make (key, updateValueFactory (key, e.Value))).Value;
113                 }
114
115                 public TValue AddOrUpdate (TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory)
116                 {
117                         return AddOrUpdate (key, (_) => addValue, updateValueFactory);
118                 }
119
120                 TValue GetValue (TKey key)
121                 {
122                         TValue temp;
123                         if (!TryGetValue (key, out temp))
124                                 // TODO: find a correct Exception
125                                 throw new ArgumentException ("Not a valid key for this dictionary", "key");
126                         return temp;
127                 }
128
129                 public bool TryGetValue (TKey key, out TValue value)
130                 {
131                         KeyValuePair<TKey, TValue> pair;
132                         bool result = internalDictionary.Find (Hash (key), out pair);
133                         value = pair.Value;
134
135                         return result;
136                 }
137
138                 public bool TryUpdate (TKey key, TValue newValue, TValue comparand)
139                 {
140                         return internalDictionary.CompareExchange (Hash (key), Make (key, newValue), (e) => e.Value.Equals (comparand));
141                 }
142
143                 public TValue this[TKey key] {
144                         get {
145                                 return GetValue (key);
146                         }
147                         set {
148                                 AddOrUpdate (key, (_) => value, (_, __) => value);
149                         }
150                 }
151
152                 public TValue GetOrAdd (TKey key, Func<TKey, TValue> valueFactory)
153                 {
154                         return internalDictionary.InsertOrGet (Hash (key), Make (key, default(TValue)), () => Make (key, valueFactory (key))).Value;
155                 }
156
157                 public TValue GetOrAdd (TKey key, TValue value)
158                 {
159                         return internalDictionary.InsertOrGet (Hash (key), Make (key, value), null).Value;
160                 }
161
162                 public bool TryRemove (TKey key, out TValue value)
163                 {
164                         KeyValuePair<TKey, TValue> data;
165                         bool result = internalDictionary.Delete (Hash (key), out data);
166                         value = data.Value;
167                         return result;
168                 }
169
170                 bool Remove (TKey key)
171                 {
172                         TValue dummy;
173
174                         return TryRemove (key, out dummy);
175                 }
176
177                 bool IDictionary<TKey, TValue>.Remove (TKey key)
178                 {
179                         return Remove (key);
180                 }
181
182                 bool ICollection<KeyValuePair<TKey,TValue>>.Remove (KeyValuePair<TKey,TValue> pair)
183                 {
184                         return Remove (pair.Key);
185                 }
186
187                 public bool ContainsKey (TKey key)
188                 {
189                         KeyValuePair<TKey, TValue> dummy;
190                         return internalDictionary.Find (Hash (key), out dummy);
191                 }
192
193                 bool IDictionary.Contains (object key)
194                 {
195                         if (!(key is TKey))
196                                 return false;
197
198                         return ContainsKey ((TKey)key);
199                 }
200
201                 void IDictionary.Remove (object key)
202                 {
203                         if (!(key is TKey))
204                                 return;
205
206                         Remove ((TKey)key);
207                 }
208
209                 object IDictionary.this [object key]
210                 {
211                         get {
212                                 if (!(key is TKey))
213                                         throw new ArgumentException ("key isn't of correct type", "key");
214
215                                 return this[(TKey)key];
216                         }
217                         set {
218                                 if (!(key is TKey) || !(value is TValue))
219                                         throw new ArgumentException ("key or value aren't of correct type");
220
221                                 this[(TKey)key] = (TValue)value;
222                         }
223                 }
224
225                 void IDictionary.Add (object key, object value)
226                 {
227                         if (!(key is TKey) || !(value is TValue))
228                                 throw new ArgumentException ("key or value aren't of correct type");
229
230                         Add ((TKey)key, (TValue)value);
231                 }
232
233                 bool ICollection<KeyValuePair<TKey,TValue>>.Contains (KeyValuePair<TKey, TValue> pair)
234                 {
235                         return ContainsKey (pair.Key);
236                 }
237
238                 public KeyValuePair<TKey,TValue>[] ToArray ()
239                 {
240                         // This is most certainly not optimum but there is
241                         // not a lot of possibilities
242
243                         return new List<KeyValuePair<TKey,TValue>> (this).ToArray ();
244                 }
245
246                 public void Clear()
247                 {
248                         // Pronk
249                         internalDictionary = new SplitOrderedList<KeyValuePair<TKey, TValue>> ();
250                 }
251
252                 public int Count {
253                         get {
254                                 return internalDictionary.Count;
255                         }
256                 }
257
258                 public bool IsEmpty {
259                         get {
260                                 return Count == 0;
261                         }
262                 }
263
264                 bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
265                         get {
266                                 return false;
267                         }
268                 }
269
270                 bool IDictionary.IsReadOnly {
271                         get {
272                                 return false;
273                         }
274                 }
275
276                 public ICollection<TKey> Keys {
277                         get {
278                                 return GetPart<TKey> ((kvp) => kvp.Key);
279                         }
280                 }
281
282                 public ICollection<TValue> Values {
283                         get {
284                                 return GetPart<TValue> ((kvp) => kvp.Value);
285                         }
286                 }
287
288                 ICollection IDictionary.Keys {
289                         get {
290                                 return (ICollection)Keys;
291                         }
292                 }
293
294                 ICollection IDictionary.Values {
295                         get {
296                                 return (ICollection)Values;
297                         }
298                 }
299
300                 ICollection<T> GetPart<T> (Func<KeyValuePair<TKey, TValue>, T> extractor)
301                 {
302                         List<T> temp = new List<T> ();
303
304                         foreach (KeyValuePair<TKey, TValue> kvp in this)
305                                 temp.Add (extractor (kvp));
306
307                         return temp.AsReadOnly ();
308                 }
309
310                 void ICollection.CopyTo (Array array, int startIndex)
311                 {
312                         KeyValuePair<TKey, TValue>[] arr = array as KeyValuePair<TKey, TValue>[];
313                         if (arr == null)
314                                 return;
315
316                         CopyTo (arr, startIndex, Count);
317                 }
318
319                 void CopyTo (KeyValuePair<TKey, TValue>[] array, int startIndex)
320                 {
321                         CopyTo (array, startIndex, Count);
322                 }
323
324                 void ICollection<KeyValuePair<TKey, TValue>>.CopyTo (KeyValuePair<TKey, TValue>[] array, int startIndex)
325                 {
326                         CopyTo (array, startIndex);
327                 }
328
329                 void CopyTo (KeyValuePair<TKey, TValue>[] array, int startIndex, int num)
330                 {
331                         foreach (var kvp in this) {
332                                 array [startIndex++] = kvp;
333
334                                 if (--num <= 0)
335                                         return;
336                         }
337                 }
338
339                 public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator ()
340                 {
341                         return GetEnumeratorInternal ();
342                 }
343
344                 IEnumerator IEnumerable.GetEnumerator ()
345                 {
346                         return (IEnumerator)GetEnumeratorInternal ();
347                 }
348
349                 IEnumerator<KeyValuePair<TKey, TValue>> GetEnumeratorInternal ()
350                 {
351                         return internalDictionary.GetEnumerator ();
352                 }
353
354                 IDictionaryEnumerator IDictionary.GetEnumerator ()
355                 {
356                         return new ConcurrentDictionaryEnumerator (GetEnumeratorInternal ());
357                 }
358
359                 class ConcurrentDictionaryEnumerator : IDictionaryEnumerator
360                 {
361                         IEnumerator<KeyValuePair<TKey, TValue>> internalEnum;
362
363                         public ConcurrentDictionaryEnumerator (IEnumerator<KeyValuePair<TKey, TValue>> internalEnum)
364                         {
365                                 this.internalEnum = internalEnum;
366                         }
367
368                         public bool MoveNext ()
369                         {
370                                 return internalEnum.MoveNext ();
371                         }
372
373                         public void Reset ()
374                         {
375                                 internalEnum.Reset ();
376                         }
377
378                         public object Current {
379                                 get {
380                                         return Entry;
381                                 }
382                         }
383
384                         public DictionaryEntry Entry {
385                                 get {
386                                         KeyValuePair<TKey, TValue> current = internalEnum.Current;
387                                         return new DictionaryEntry (current.Key, current.Value);
388                                 }
389                         }
390
391                         public object Key {
392                                 get {
393                                         return internalEnum.Current.Key;
394                                 }
395                         }
396
397                         public object Value {
398                                 get {
399                                         return internalEnum.Current.Value;
400                                 }
401                         }
402                 }
403
404                 object ICollection.SyncRoot {
405                         get {
406                                 return this;
407                         }
408                 }
409
410                 bool IDictionary.IsFixedSize {
411                         get {
412                                 return false;
413                         }
414                 }
415
416                 bool ICollection.IsSynchronized {
417                         get { return true; }
418                 }
419
420                 static KeyValuePair<U, V> Make<U, V> (U key, V value)
421                 {
422                         return new KeyValuePair<U, V> (key, value);
423                 }
424
425                 uint Hash (TKey key)
426                 {
427                         return (uint)comparer.GetHashCode (key);
428                 }
429         }
430 }
431 #endif