* corlib.dll.sources: IEqualityComparer, etc
[mono.git] / mcs / class / corlib / System.Collections.Generic / Dictionary.cs
1 //
2 // System.Collections.Generic.Dictionary
3 //
4 // Authors:
5 //      Sureshkumar T (tsureshkumar@novell.com)
6 //      Marek Safar (marek.safar@seznam.cz) (stubs)
7 //      Ankit Jain (radical@corewars.org)
8 //
9 //
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 #if NET_2_0
34
35 using System;
36 using System.Collections;
37 using System.Collections.Generic;
38 using System.Runtime.Serialization;
39
40
41 namespace System.Collections.Generic {
42
43         [Serializable]
44         public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>,
45                 IDictionary,
46                 ICollection,
47                 IEnumerable,
48                 ISerializable,
49                 IDeserializationCallback
50         {
51                 const int INITIAL_SIZE = 10;
52                 const float DEFAULT_LOAD_FACTOR = (90f / 100);
53
54                 [Serializable]
55                 internal class Slot {
56                         public TKey Key;
57                         public TValue Value;
58                         public Slot next;
59                         public Slot (TKey Key, TValue Value, Slot next)
60                         {
61                                 this.Key = Key;
62                                 this.Value = Value;
63                                 this.next = next;
64                         }
65                 }
66         
67                 Slot [] _table;
68         
69                 int _usedSlots;
70                 float _loadFactor = DEFAULT_LOAD_FACTOR;
71         
72                 IEqualityComparer<TKey> _hcp;
73         
74                 uint _threshold;
75         
76                 public int Count {
77                         get { return _usedSlots; }
78                 }
79
80                 public TValue this [TKey key] {
81                         get {
82                                 int index = GetSlot (key);
83                                 if (index < 0)
84                                         throw new KeyNotFoundException ();
85                                 return _table [index].Value;
86                         }
87                         
88                         set {
89                                 int index = GetSlot (key);
90                                 if (index < 0)
91                                         DoAdd (index, key, value);
92                                 else
93                                         _table [index].Value = value;
94                         }
95                 }
96         
97                 public Dictionary ()
98                 {
99                         Init ();
100                 }
101         
102                 public Dictionary (IEqualityComparer<TKey> comparer)
103                 {
104                         Init (INITIAL_SIZE, comparer, DEFAULT_LOAD_FACTOR);
105                 }
106         
107                 public Dictionary (IDictionary<TKey, TValue> dictionary)
108                         : this (dictionary, null)
109                 {
110                 }
111         
112                 public Dictionary (int capacity)
113                 {
114                         Init (capacity);
115                 }
116         
117                 public Dictionary (float loadFactor)
118                 {
119                         Init (loadFactor);
120                 }
121         
122                 public Dictionary (IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
123                 {
124                         if (dictionary == null)
125                                 throw new ArgumentNullException ("dictionary");
126                         int capacity = dictionary.Count;
127                         Init (capacity, comparer, DEFAULT_LOAD_FACTOR);
128                         foreach (KeyValuePair<TKey, TValue> entry in dictionary) {
129                                 this.Add (entry.Key, entry.Value);
130                         }
131                 }
132         
133                 public Dictionary (int capacity, IEqualityComparer<TKey> comparer)
134                 {
135                         Init (capacity, comparer, DEFAULT_LOAD_FACTOR);
136                 }
137         
138                 protected Dictionary (SerializationInfo info, StreamingContext context)
139                 {
140                         Init ();
141                 }
142         
143                 void Init ()
144                 {
145                         Init (INITIAL_SIZE, null, DEFAULT_LOAD_FACTOR);
146                 }
147         
148                 void Init (int capacity)
149                 {
150                         Init (capacity, null, DEFAULT_LOAD_FACTOR);
151                 }
152         
153                 void Init (float loadFactor)
154                 {
155                         Init (INITIAL_SIZE, null, loadFactor);
156                 }
157                 
158                 protected void Init (int capacity, IEqualityComparer<TKey> hcp, float loadFactor)
159                 {
160                         if (capacity < 0)
161                                 throw new ArgumentOutOfRangeException ("capacity");
162                         this._hcp = hcp;
163                         _table = new Slot [capacity];
164                         _loadFactor = loadFactor;
165                         _threshold = (uint) (capacity * _loadFactor);
166                         if (_threshold == 0 && capacity > 0)
167                                 _threshold = 1;
168                 }
169         
170                 ICollection<TValue> GetValues ()
171                 {
172                         return ((IDictionary<TKey, TValue>) this).Values;
173                 }
174         
175                 ICollection<TKey> GetKeys ()
176                 {
177                         return ((IDictionary<TKey, TValue>) this).Keys;
178                 }
179         
180         
181                 void CopyTo (KeyValuePair<TKey, TValue> [] array, int index)
182                 {
183                         if (array == null)
184                                 throw new ArgumentNullException ("array");
185                         if (index < 0)
186                                 throw new ArgumentOutOfRangeException ("index");
187                         if (index >= array.Length)
188                                 throw new ArgumentException ("index larger than largest valid index of array");
189                         if (array.Length - index < _usedSlots)
190                                 throw new ArgumentException ("Destination array cannot hold the requested elements!");
191                         
192                         foreach (KeyValuePair<TKey, TValue> kv in this)
193                                 array [index++] = kv;
194                 }
195         
196                 protected void Resize ()
197                 {
198                         // From the SDK docs:
199                         //       Hashtable is automatically increased
200                         //       to the smallest prime number that is larger
201                         //       than twice the current number of Hashtable buckets
202                         uint newSize = (uint) ToPrime ((_table.Length << 1) | 1);
203
204                         _threshold = (uint) (newSize * _loadFactor);
205                         if (_threshold == 0 && newSize > 0)
206                                 _threshold = 1;
207                 
208                         Slot nextslot = null;
209                         Slot [] oldTable = _table;
210                         
211                         _table = new Slot [newSize];
212
213                         int index;
214                         for (int i = 0; i < oldTable.Length; i++) {
215                                 for (Slot slot = oldTable [i]; slot != null; slot = nextslot) {
216                                         nextslot = slot.next;
217
218                                         index = DoHash (slot.Key);
219                                         slot.next = _table [index];
220                                         _table [index] = slot;
221                                 }
222                         }
223                 }
224
225                 protected virtual int GetHash (TKey key)
226                 {
227                         //IEqualityComparer<K> hcp = this._hcp;
228                         
229                         return key.GetHashCode ();
230                         /*
231                         return (hcp != null)
232                         ? hcp.GetHashCode (key)
233                         : key.GetHashCode ();
234                         */
235                 }
236         
237                 public void Add (TKey key, TValue value)
238                 {
239                         int index = GetSlot (key);
240                         if (index >= 0)
241                                 throw new ArgumentException ("An element with the same key already exists in the dictionary.");
242
243                         DoAdd (index, key, value);
244                 }
245
246                 void DoAdd (int negated_index, TKey key, TValue value)
247                 {
248                         int index = -negated_index - 1;
249
250                         if (_usedSlots >= _threshold) {
251                                 Resize ();
252                                 index = DoHash (key);
253                         }
254
255                         _table [index] = new Slot (key, value, _table [index]);
256                         ++_usedSlots;
257                 }
258         
259                 protected int DoHash (TKey key)
260                 {
261                         if (key == null)
262                                 throw new ArgumentNullException ("key", "null key");
263         
264                         int size = this._table.Length;
265                         int h = this.GetHash (key) & Int32.MaxValue;
266                         //Console.WriteLine ("Hashvalue for key {0} is {1}", key.ToString (), h);
267                         int spot = (int) ((uint) h % size);
268                         return spot;
269                 }
270
271                 public IEqualityComparer<TKey> Comparer {
272                         get {
273                                 return _hcp;
274                         }
275                 }
276                 
277                 public void Clear ()
278                 {
279                         for (int i = 0; i < _table.Length; i++)
280                                 _table [i] = null;
281                         _usedSlots = 0;
282                 }
283         
284                 public bool ContainsKey (TKey key)
285                 {
286                         return GetSlot (key) >= 0;
287                 }
288         
289                 public bool ContainsValue (TValue value)
290                 {
291                         foreach (TValue v in ((IDictionary) this).Values) {
292                                 if (v.Equals (value))
293                                         return true;
294                         }
295                         return false;
296                 }
297         
298                 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
299                 {
300                         throw new NotImplementedException ();
301                 }
302         
303                 public virtual void OnDeserialization (object sender)
304                 {
305                         throw new NotImplementedException ();
306                 }
307         
308                 public bool Remove (TKey key)
309                 {
310                         int index = GetSlot (key);
311
312                         if (index < 0)
313                                 return false;
314
315                         // If GetSlot returns a valid index, the given key is at the head of the chain.
316                         _table [index] = _table [index].next;
317                         --_usedSlots;
318                         return true;
319                 }
320
321                 //
322                 // Returns the index of the chain containing key.  Also ensures that the found key is the first element of the chain.
323                 // If the key is not found, returns -h-1, where 'h' is the index of the chain that would've contained the key.
324                 // 
325                 internal int GetSlot (TKey key)
326                 {
327                         if (key == null)
328                                 throw new ArgumentNullException ("key");
329                         int index = DoHash (key);
330                         Slot slot = _table [index];
331                         Slot prev = null;
332
333                         while (slot != null && !slot.Key.Equals (key)) {
334                                 prev = slot;
335                                 slot = slot.next;
336                         }
337         
338                         if (slot == null)
339                                 return - index - 1;
340         
341                         if (prev != null) {
342                                 // Move to the head of the list
343                                 prev.next = slot.next;
344                                 slot.next = _table [index];
345                                 _table [index] = slot;
346                         }
347
348                         return index;
349                 }
350         
351                 public bool TryGetValue (TKey key, out TValue value)
352                 {
353                         int index = GetSlot (key);
354                         bool found = index >= 0;
355                         value = found ? _table [index].Value : default (TValue);
356                         return found;
357                 }
358         
359                 ICollection<TKey> IDictionary<TKey, TValue>.Keys {
360                         get {
361                                 return Keys;
362                         }
363                 }
364         
365                 ICollection<TValue> IDictionary<TKey, TValue>.Values {
366                         get {
367                                 return Values;
368                         }
369                 }
370
371                 public KeyCollection Keys {
372                         get {
373                                 return new KeyCollection (this);
374                         }
375                 }
376
377                 public ValueCollection Values {
378                         get {
379                                 return new ValueCollection (this);
380                         }
381                 }
382                 
383                 bool IDictionary.IsFixedSize {
384                         get { return false; }
385                 }
386                 
387                 bool IDictionary.IsReadOnly {
388                         get { return false; }
389                 }
390                 
391                 object IDictionary.this [object key] {
392                         get {
393                                 if (!(key is TKey))
394                                         throw new ArgumentException ("key is of not '" + typeof (TKey).ToString () + "'!");
395                                 return this [(TKey) key];
396                         }
397                         set { this [(TKey) key] = (TValue) value; }
398                 }
399                 ICollection IDictionary.Keys
400                 {
401                         get { return ((IDictionary<TKey, TValue>) this).Keys as ICollection; }
402                 }
403                 ICollection IDictionary.Values
404                 {
405                         get { return ((IDictionary<TKey, TValue>) this).Values as ICollection; }
406                 }
407         
408                 void IDictionary.Add (object key, object value)
409                 {
410                         if (!(key is TKey))
411                                 throw new ArgumentException ("key is of not '" + typeof (TKey).ToString () + "'!");
412                         if (!(value is TValue))
413                                 throw new ArgumentException ("value is of not '" + typeof (TValue).ToString () + "'!");
414                         this.Add ((TKey) key, (TValue) value);
415                 }
416         
417                 bool IDictionary.Contains (object key)
418                 {
419                         return ContainsKey ((TKey) key);
420                 }
421         
422                 void IDictionary.Remove (object key)
423                 {
424                         Remove ((TKey) key);
425                 }
426         
427                 bool ICollection.IsSynchronized {
428                         get { return false; }
429                 }
430                 object ICollection.SyncRoot {
431                         get { return this; }
432                 }
433         
434                 bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
435                         get { return false; }
436                 }
437         
438                 void ICollection<KeyValuePair<TKey, TValue>>.Add (KeyValuePair<TKey, TValue> keyValuePair)
439                 {
440                         Add (keyValuePair.Key, keyValuePair.Value);
441                 }
442         
443                 bool ICollection<KeyValuePair<TKey, TValue>>.Contains (KeyValuePair<TKey, TValue> keyValuePair)
444                 {
445                         return this.ContainsKey (keyValuePair.Key);
446                 }
447         
448                 void ICollection<KeyValuePair<TKey, TValue>>.CopyTo (KeyValuePair<TKey, TValue> [] array, int index)
449                 {
450                         CopyTo (array, index);
451                 }
452         
453                 bool ICollection<KeyValuePair<TKey, TValue>>.Remove (KeyValuePair<TKey, TValue> keyValuePair)
454                 {
455                         return Remove (keyValuePair.Key);
456                 }
457         
458         
459                 void ICollection.CopyTo (Array array, int index)
460                 {
461                         CopyTo ((KeyValuePair<TKey, TValue> []) array, index);
462                 }
463         
464                 IEnumerator IEnumerable.GetEnumerator ()
465                 {
466                         return new Enumerator (this, EnumerationMode.DictionaryEntry);
467                 }
468         
469                 IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator ()
470                 {
471                         return new Enumerator (this);
472                 }
473         
474                 /**
475                  * This is to make the gmcs compiler errror silent
476                  */
477         //                         IEnumerator<TKey> IEnumerable<K>.GetEnumerator ()
478         //                         {
479         //                                         throw new NotImplementedException ();
480         //                         }
481         
482         
483                 IDictionaryEnumerator IDictionary.GetEnumerator ()
484                 {
485                         return new Enumerator (this, EnumerationMode.DictionaryEntry);
486                 }
487         
488                 public Enumerator GetEnumerator ()
489                 {
490                         return new Enumerator (this, EnumerationMode.KeyValuePair);
491                 }
492         
493                 public enum EnumerationMode { Key, Value, DictionaryEntry, KeyValuePair };
494         
495                 [Serializable]
496                 public struct Enumerator : IEnumerator<KeyValuePair<TKey,TValue>>,
497                         IDisposable, IDictionaryEnumerator, IEnumerator
498                 {
499                         Dictionary<TKey, TValue> _dictionary;
500                         Slot _current;
501                         int _index;
502                         int _validNodeVisited;
503                         bool _isValid;
504                         EnumerationMode _navigationMode;
505         
506         
507         
508                         public Enumerator (Dictionary<TKey, TValue> dictionary) : this (dictionary, EnumerationMode.KeyValuePair)
509                         {
510                         }
511         
512                         public Enumerator (Dictionary<TKey, TValue> dictionary, EnumerationMode mode)
513                         {
514                                 _index = 0;
515                                 _current = null;
516                                 _validNodeVisited = 0;
517                                 _dictionary = dictionary;
518                                 _isValid = false;
519                                 _navigationMode = mode;
520                         }
521         
522                         public bool MoveNext ()
523                         {
524                                 if (_validNodeVisited == _dictionary.Count)
525                                         return (_isValid = false);
526         
527                                 while (_index < _dictionary._table.Length) {
528                                         if (_current == null)
529                                                 _current = _dictionary._table [_index++];
530                                         else
531                                                 _current = _current.next;
532         
533                                         if (_current != null) {
534                                                 ++_validNodeVisited;
535                                                 return (_isValid = true);
536                                         }
537                                 }
538         
539                                 return (_isValid = false);
540                         }
541         
542                         public KeyValuePair<TKey, TValue> Current {
543                                 get {
544                                         if (!_isValid) throw new InvalidOperationException ();
545                                         KeyValuePair<TKey, TValue> kv = new KeyValuePair<TKey, TValue> (_current.Key, _current.Value);
546                                         return kv;
547                                 }
548                         }
549         
550                         object IEnumerator.Current {
551                                 get {
552                                         if (!_isValid) throw new InvalidOperationException ();
553                                         switch (_navigationMode) {
554                                         case EnumerationMode.Key:
555                                                 return _current.Key as object;
556                                         case EnumerationMode.Value:
557                                                 return _current.Value as object;
558                                         case EnumerationMode.DictionaryEntry:
559                                                 DictionaryEntry de = new DictionaryEntry (_current.Key, _current.Value);
560                                                 return de as object;
561                                         case EnumerationMode.KeyValuePair:
562                                         default:
563                                                 KeyValuePair<TKey, TValue> kv = new KeyValuePair<TKey, TValue> (_current.Key, _current.Value);
564                                                 return kv as object;
565                                         }
566                                 }
567                         }
568         
569                         DictionaryEntry IDictionaryEnumerator.Entry
570                         {
571                                 get
572                                 {
573                                         if (!_isValid) throw new InvalidOperationException ();
574                                         DictionaryEntry entry = new DictionaryEntry (_current.Key, _current.Value);
575                                         return entry;
576                                 }
577                         }
578         
579                         void IEnumerator.Reset ()
580                         {
581                                 _index = 0;
582                                 _current = null;
583                                 _isValid = false;
584                                 _validNodeVisited = 0;
585                         }
586         
587                         object IDictionaryEnumerator.Key
588                         {
589                                 get
590                                 {
591                                         if (!_isValid) throw new InvalidOperationException ();
592                                         return _current.Key;
593                                 }
594                         }
595                         object IDictionaryEnumerator.Value
596                         {
597                                 get
598                                 {
599                                         if (!_isValid) throw new InvalidOperationException ();
600                                         return _current.Value;
601                                 }
602                         }
603         
604                         public void Dispose ()
605                         {
606         
607                         }
608                 }
609         
610                 // This collection is a read only collection
611                 public class KeyCollection : ICollection<TKey>, ICollection {
612                         Dictionary<TKey, TValue> _dictionary;
613         
614                         public KeyCollection (Dictionary<TKey, TValue> dictionary)
615                         {
616                                 _dictionary = dictionary;
617                         }
618         
619                         void ICollection<TKey>.Add (TKey item)
620                         {
621                                 throw new InvalidOperationException ();
622                         }
623         
624                         void ICollection<TKey>.Clear ()
625                         {
626                                 throw new InvalidOperationException ();
627                         }
628         
629                         bool ICollection<TKey>.Contains (TKey item)
630                         {
631                                 return _dictionary.ContainsKey (item);
632                         }
633         
634                         bool ICollection<TKey>.Remove (TKey item)
635                         {
636                                 throw new InvalidOperationException ();
637                         }
638         
639                         void ICollection.CopyTo (Array array, int index)
640                         {
641                                 CopyTo ((TKey []) array, index);
642                         }
643         
644                         public void CopyTo (TKey [] array, int index)
645                         {
646                                 if (array == null)
647                                         throw new ArgumentNullException ("array");
648                                 if (index < 0)
649                                         throw new ArgumentOutOfRangeException ("index");
650                                 if (index >= array.Length)
651                                         throw new ArgumentException ("index larger than largest valid index of array");
652                                 if (array.Length - index < _dictionary._usedSlots)
653                                         throw new ArgumentException ("Destination array cannot hold the requested elements!");
654
655                                 IEnumerable<TKey> enumerateThis = (IEnumerable<TKey>) this;
656                                 foreach (TKey k in enumerateThis) {
657                                         array [index++] = k;
658                                 }
659                         }
660         
661                         public Enumerator GetEnumerator ()
662                         {
663                                 return new Enumerator (_dictionary);
664                         }
665         
666                         IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator ()
667                         {
668                                 return new KeyEnumerator (_dictionary);
669                         }
670         
671                         IEnumerator IEnumerable.GetEnumerator ()
672                         {
673                                 return new Enumerator (_dictionary, EnumerationMode.Key);
674                         }
675         
676         
677                         bool ICollection<TKey>.IsReadOnly { get { return ((IDictionary) _dictionary).IsReadOnly; } }
678                         public int Count { get { return _dictionary.Count; } }
679                         bool ICollection.IsSynchronized { get { return ((IDictionary) _dictionary).IsSynchronized; } }
680                         object ICollection.SyncRoot { get { return ((IDictionary) _dictionary).SyncRoot; } }
681         
682                         public struct KeyEnumerator : IEnumerator<TKey>, IDisposable, IEnumerator {
683                                 IEnumerator _hostEnumerator;
684                                 internal KeyEnumerator (Dictionary<TKey, TValue> dictionary)
685                                 {
686                                         _hostEnumerator = new Enumerator (dictionary, EnumerationMode.Key);
687                                 }
688                                 
689                                 public void Dispose ()
690                                 {
691                                 }
692                                 
693                                 public bool MoveNext ()
694                                 {
695                                         return _hostEnumerator.MoveNext ();
696                                 }
697                                 
698                                 public TKey Current {
699                                         get {
700                                                 return (TKey) _hostEnumerator.Current;
701                                         }
702                                 }
703                                 
704                                 object IEnumerator.Current {
705                                         get {
706                                                 return _hostEnumerator.Current;
707                                         }
708                                 }
709                                 
710                                 void IEnumerator.Reset ()
711                                 {
712                                         _hostEnumerator.Reset ();
713                                 }
714                         }
715                 }
716         
717                 // This collection is a read only collection
718                 public class ValueCollection : ICollection<TValue>, ICollection {
719                         Dictionary<TKey, TValue> _dictionary;
720         
721                         public ValueCollection (Dictionary<TKey, TValue> dictionary)
722                         {
723                                 _dictionary = dictionary;
724                         }
725         
726                         void ICollection<TValue>.Add (TValue item)
727                         {
728                                 throw new InvalidOperationException ();
729                         }
730         
731                         void ICollection<TValue>.Clear ()
732                         {
733                                 throw new InvalidOperationException ();
734                         }
735         
736                         bool ICollection<TValue>.Contains (TValue item)
737                         {
738                                 return _dictionary.ContainsValue (item);
739                         }
740         
741                         bool ICollection<TValue>.Remove (TValue item)
742                         {
743                                 throw new InvalidOperationException ();
744                         }
745         
746                         void ICollection.CopyTo (Array array, int index)
747                         {
748                                 CopyTo ((TValue []) array, index);
749                         }
750         
751                         public void CopyTo (TValue [] array, int index)
752                         {
753                                 if (array == null)
754                                         throw new ArgumentNullException ("array");
755                                 if (index < 0)
756                                         throw new ArgumentOutOfRangeException ("index");
757                                 if (index >= array.Length)
758                                         throw new ArgumentException ("index larger than largest valid index of array");
759                                 if (array.Length - index < _dictionary._usedSlots)
760                                         throw new ArgumentException ("Destination array cannot hold the requested elements!");
761
762                                 IEnumerable<TValue> enumerateThis = (IEnumerable<TValue>) this;
763                                 foreach (TValue v in enumerateThis) {
764                                         array [index++] = v;
765                                 }
766                         }
767         
768                         public Enumerator GetEnumerator ()
769                         {
770                                 return new Enumerator (_dictionary);
771                         }
772         
773                         IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator ()
774                         {
775                                 return new ValueEnumerator (_dictionary);
776                         }
777         
778                         IEnumerator IEnumerable.GetEnumerator ()
779                         {
780                                 return new Enumerator (_dictionary, EnumerationMode.Value);
781                         }
782         
783         
784                         bool ICollection<TValue>.IsReadOnly { get { return ((IDictionary) _dictionary).IsReadOnly; } }
785                         public int Count { get { return _dictionary.Count; } }
786                         bool ICollection.IsSynchronized { get { return ((IDictionary) _dictionary).IsSynchronized; } }
787                         object ICollection.SyncRoot { get { return ((IDictionary) _dictionary).SyncRoot; } }
788         
789                         public struct ValueEnumerator : IEnumerator<TValue>
790                         {
791                                 IEnumerator _hostEnumerator;
792                                 internal ValueEnumerator (Dictionary<TKey, TValue> dictionary)
793                                 {
794                                         _hostEnumerator = new Enumerator (dictionary, EnumerationMode.Value);
795                                 }
796                                 
797                                 public void Dispose ()
798                                 {
799                                 }
800                                 
801                                 public bool MoveNext ()
802                                 {
803                                         return _hostEnumerator.MoveNext ();
804                                 }
805                                 
806                                 public TValue Current {
807                                         get {
808                                                 return (TValue) _hostEnumerator.Current;
809                                         }
810                                 }
811                                 
812                                 object IEnumerator.Current {
813                                         get {
814                                                 return _hostEnumerator.Current;
815                                         }
816                                 }
817                                 
818                                 void IEnumerator.Reset ()
819                                 {
820                                         _hostEnumerator.Reset ();
821                                 }
822         
823                         }
824                 }
825         
826                 static bool TestPrime (int x)
827                 {
828                         if ((x & 1) != 0) {
829                                 for (int n = 3; n < (int) Math.Sqrt (x); n += 2) {
830                                         if ((x % n) == 0)
831                                                 return false;
832                                 }
833                                 return true;
834                         }
835                         // There is only one even prime - 2.
836                         return (x == 2);
837                 }
838         
839                 static int CalcPrime (int x)
840                 {
841                         for (int i = (x & (~1)) - 1; i < Int32.MaxValue; i += 2) {
842                                 if (TestPrime (i)) return i;
843                         }
844                         return x;
845                 }
846         
847                 static int ToPrime (int x)
848                 {
849                         for (int i = 0; i < primeTbl.Length; i++) {
850                                 if (x <= primeTbl [i])
851                                         return primeTbl [i];
852                         }
853                         return CalcPrime (x);
854                 }
855         
856                 static readonly int [] primeTbl = {
857                         11,
858                         19,
859                         37,
860                         73,
861                         109,
862                         163,
863                         251,
864                         367,
865                         557,
866                         823,
867                         1237,
868                         1861,
869                         2777,
870                         4177,
871                         6247,
872                         9371,
873                         14057,
874                         21089,
875                         31627,
876                         47431,
877                         71143,
878                         106721,
879                         160073,
880                         240101,
881                         360163,
882                         540217,
883                         810343,
884                         1215497,
885                         1823231,
886                         2734867,
887                         4102283,
888                         6153409,
889                         9230113,
890                         13845163
891                 };
892         }
893 }
894 #endif
895