2 // System.Collections.Generic.Dictionary
5 // Sureshkumar T (tsureshkumar@novell.com)
6 // Marek Safar (marek.safar@seznam.cz) (stubs)
7 // Ankit Jain (radical@corewars.org)
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
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.
36 using System.Collections;
37 using System.Collections.Generic;
38 using System.Runtime.Serialization;
41 namespace System.Collections.Generic {
44 public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>,
49 IDeserializationCallback
51 const int INITIAL_SIZE = 10;
52 const float DEFAULT_LOAD_FACTOR = (90f / 100);
59 public Slot (TKey Key, TValue Value, Slot next)
70 float _loadFactor = DEFAULT_LOAD_FACTOR;
72 IEqualityComparer<TKey> _hcp;
77 get { return _usedSlots; }
80 public TValue this [TKey key] {
82 int index = GetSlot (key);
84 throw new KeyNotFoundException ();
85 return _table [index].Value;
89 int index = GetSlot (key);
91 DoAdd (index, key, value);
93 _table [index].Value = value;
102 public Dictionary (IEqualityComparer<TKey> comparer)
104 Init (INITIAL_SIZE, comparer, DEFAULT_LOAD_FACTOR);
107 public Dictionary (IDictionary<TKey, TValue> dictionary)
108 : this (dictionary, null)
112 public Dictionary (int capacity)
117 public Dictionary (float loadFactor)
122 public Dictionary (IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
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);
133 public Dictionary (int capacity, IEqualityComparer<TKey> comparer)
135 Init (capacity, comparer, DEFAULT_LOAD_FACTOR);
138 protected Dictionary (SerializationInfo info, StreamingContext context)
145 Init (INITIAL_SIZE, null, DEFAULT_LOAD_FACTOR);
148 void Init (int capacity)
150 Init (capacity, null, DEFAULT_LOAD_FACTOR);
153 void Init (float loadFactor)
155 Init (INITIAL_SIZE, null, loadFactor);
158 protected void Init (int capacity, IEqualityComparer<TKey> hcp, float loadFactor)
161 throw new ArgumentOutOfRangeException ("capacity");
163 _table = new Slot [capacity];
164 _loadFactor = loadFactor;
165 _threshold = (uint) (capacity * _loadFactor);
166 if (_threshold == 0 && capacity > 0)
170 ICollection<TValue> GetValues ()
172 return ((IDictionary<TKey, TValue>) this).Values;
175 ICollection<TKey> GetKeys ()
177 return ((IDictionary<TKey, TValue>) this).Keys;
181 void CopyTo (KeyValuePair<TKey, TValue> [] array, int index)
184 throw new ArgumentNullException ("array");
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!");
192 foreach (KeyValuePair<TKey, TValue> kv in this)
193 array [index++] = kv;
196 protected void Resize ()
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);
204 _threshold = (uint) (newSize * _loadFactor);
205 if (_threshold == 0 && newSize > 0)
208 Slot nextslot = null;
209 Slot [] oldTable = _table;
211 _table = new Slot [newSize];
214 for (int i = 0; i < oldTable.Length; i++) {
215 for (Slot slot = oldTable [i]; slot != null; slot = nextslot) {
216 nextslot = slot.next;
218 index = DoHash (slot.Key);
219 slot.next = _table [index];
220 _table [index] = slot;
225 protected virtual int GetHash (TKey key)
227 //IEqualityComparer<K> hcp = this._hcp;
229 return key.GetHashCode ();
232 ? hcp.GetHashCode (key)
233 : key.GetHashCode ();
237 public void Add (TKey key, TValue value)
239 int index = GetSlot (key);
241 throw new ArgumentException ("An element with the same key already exists in the dictionary.");
243 DoAdd (index, key, value);
246 void DoAdd (int negated_index, TKey key, TValue value)
248 int index = -negated_index - 1;
250 if (_usedSlots >= _threshold) {
252 index = DoHash (key);
255 _table [index] = new Slot (key, value, _table [index]);
259 protected int DoHash (TKey key)
262 throw new ArgumentNullException ("key", "null key");
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);
271 public IEqualityComparer<TKey> Comparer {
279 for (int i = 0; i < _table.Length; i++)
284 public bool ContainsKey (TKey key)
286 return GetSlot (key) >= 0;
289 public bool ContainsValue (TValue value)
291 foreach (TValue v in ((IDictionary) this).Values) {
292 if (v.Equals (value))
298 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
300 throw new NotImplementedException ();
303 public virtual void OnDeserialization (object sender)
305 throw new NotImplementedException ();
308 public bool Remove (TKey key)
310 int index = GetSlot (key);
315 // If GetSlot returns a valid index, the given key is at the head of the chain.
316 _table [index] = _table [index].next;
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.
325 internal int GetSlot (TKey key)
328 throw new ArgumentNullException ("key");
329 int index = DoHash (key);
330 Slot slot = _table [index];
333 while (slot != null && !slot.Key.Equals (key)) {
342 // Move to the head of the list
343 prev.next = slot.next;
344 slot.next = _table [index];
345 _table [index] = slot;
351 public bool TryGetValue (TKey key, out TValue value)
353 int index = GetSlot (key);
354 bool found = index >= 0;
355 value = found ? _table [index].Value : default (TValue);
359 ICollection<TKey> IDictionary<TKey, TValue>.Keys {
365 ICollection<TValue> IDictionary<TKey, TValue>.Values {
371 public KeyCollection Keys {
373 return new KeyCollection (this);
377 public ValueCollection Values {
379 return new ValueCollection (this);
383 bool IDictionary.IsFixedSize {
384 get { return false; }
387 bool IDictionary.IsReadOnly {
388 get { return false; }
391 object IDictionary.this [object key] {
394 throw new ArgumentException ("key is of not '" + typeof (TKey).ToString () + "'!");
395 return this [(TKey) key];
397 set { this [(TKey) key] = (TValue) value; }
399 ICollection IDictionary.Keys
401 get { return ((IDictionary<TKey, TValue>) this).Keys as ICollection; }
403 ICollection IDictionary.Values
405 get { return ((IDictionary<TKey, TValue>) this).Values as ICollection; }
408 void IDictionary.Add (object key, object value)
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);
417 bool IDictionary.Contains (object key)
419 return ContainsKey ((TKey) key);
422 void IDictionary.Remove (object key)
427 bool ICollection.IsSynchronized {
428 get { return false; }
430 object ICollection.SyncRoot {
434 bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
435 get { return false; }
438 void ICollection<KeyValuePair<TKey, TValue>>.Add (KeyValuePair<TKey, TValue> keyValuePair)
440 Add (keyValuePair.Key, keyValuePair.Value);
443 bool ICollection<KeyValuePair<TKey, TValue>>.Contains (KeyValuePair<TKey, TValue> keyValuePair)
445 return this.ContainsKey (keyValuePair.Key);
448 void ICollection<KeyValuePair<TKey, TValue>>.CopyTo (KeyValuePair<TKey, TValue> [] array, int index)
450 CopyTo (array, index);
453 bool ICollection<KeyValuePair<TKey, TValue>>.Remove (KeyValuePair<TKey, TValue> keyValuePair)
455 return Remove (keyValuePair.Key);
459 void ICollection.CopyTo (Array array, int index)
461 CopyTo ((KeyValuePair<TKey, TValue> []) array, index);
464 IEnumerator IEnumerable.GetEnumerator ()
466 return new Enumerator (this, EnumerationMode.DictionaryEntry);
469 IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator ()
471 return new Enumerator (this);
475 * This is to make the gmcs compiler errror silent
477 // IEnumerator<TKey> IEnumerable<K>.GetEnumerator ()
479 // throw new NotImplementedException ();
483 IDictionaryEnumerator IDictionary.GetEnumerator ()
485 return new Enumerator (this, EnumerationMode.DictionaryEntry);
488 public Enumerator GetEnumerator ()
490 return new Enumerator (this, EnumerationMode.KeyValuePair);
493 public enum EnumerationMode { Key, Value, DictionaryEntry, KeyValuePair };
496 public struct Enumerator : IEnumerator<KeyValuePair<TKey,TValue>>,
497 IDisposable, IDictionaryEnumerator, IEnumerator
499 Dictionary<TKey, TValue> _dictionary;
502 int _validNodeVisited;
504 EnumerationMode _navigationMode;
508 public Enumerator (Dictionary<TKey, TValue> dictionary) : this (dictionary, EnumerationMode.KeyValuePair)
512 public Enumerator (Dictionary<TKey, TValue> dictionary, EnumerationMode mode)
516 _validNodeVisited = 0;
517 _dictionary = dictionary;
519 _navigationMode = mode;
522 public bool MoveNext ()
524 if (_validNodeVisited == _dictionary.Count)
525 return (_isValid = false);
527 while (_index < _dictionary._table.Length) {
528 if (_current == null)
529 _current = _dictionary._table [_index++];
531 _current = _current.next;
533 if (_current != null) {
535 return (_isValid = true);
539 return (_isValid = false);
542 public KeyValuePair<TKey, TValue> Current {
544 if (!_isValid) throw new InvalidOperationException ();
545 KeyValuePair<TKey, TValue> kv = new KeyValuePair<TKey, TValue> (_current.Key, _current.Value);
550 object IEnumerator.Current {
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);
561 case EnumerationMode.KeyValuePair:
563 KeyValuePair<TKey, TValue> kv = new KeyValuePair<TKey, TValue> (_current.Key, _current.Value);
569 DictionaryEntry IDictionaryEnumerator.Entry
573 if (!_isValid) throw new InvalidOperationException ();
574 DictionaryEntry entry = new DictionaryEntry (_current.Key, _current.Value);
579 void IEnumerator.Reset ()
584 _validNodeVisited = 0;
587 object IDictionaryEnumerator.Key
591 if (!_isValid) throw new InvalidOperationException ();
595 object IDictionaryEnumerator.Value
599 if (!_isValid) throw new InvalidOperationException ();
600 return _current.Value;
604 public void Dispose ()
610 // This collection is a read only collection
611 public class KeyCollection : ICollection<TKey>, ICollection {
612 Dictionary<TKey, TValue> _dictionary;
614 public KeyCollection (Dictionary<TKey, TValue> dictionary)
616 _dictionary = dictionary;
619 void ICollection<TKey>.Add (TKey item)
621 throw new InvalidOperationException ();
624 void ICollection<TKey>.Clear ()
626 throw new InvalidOperationException ();
629 bool ICollection<TKey>.Contains (TKey item)
631 return _dictionary.ContainsKey (item);
634 bool ICollection<TKey>.Remove (TKey item)
636 throw new InvalidOperationException ();
639 void ICollection.CopyTo (Array array, int index)
641 CopyTo ((TKey []) array, index);
644 public void CopyTo (TKey [] array, int index)
647 throw new ArgumentNullException ("array");
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!");
655 IEnumerable<TKey> enumerateThis = (IEnumerable<TKey>) this;
656 foreach (TKey k in enumerateThis) {
661 public Enumerator GetEnumerator ()
663 return new Enumerator (_dictionary);
666 IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator ()
668 return new KeyEnumerator (_dictionary);
671 IEnumerator IEnumerable.GetEnumerator ()
673 return new Enumerator (_dictionary, EnumerationMode.Key);
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; } }
682 public struct KeyEnumerator : IEnumerator<TKey>, IDisposable, IEnumerator {
683 IEnumerator _hostEnumerator;
684 internal KeyEnumerator (Dictionary<TKey, TValue> dictionary)
686 _hostEnumerator = new Enumerator (dictionary, EnumerationMode.Key);
689 public void Dispose ()
693 public bool MoveNext ()
695 return _hostEnumerator.MoveNext ();
698 public TKey Current {
700 return (TKey) _hostEnumerator.Current;
704 object IEnumerator.Current {
706 return _hostEnumerator.Current;
710 void IEnumerator.Reset ()
712 _hostEnumerator.Reset ();
717 // This collection is a read only collection
718 public class ValueCollection : ICollection<TValue>, ICollection {
719 Dictionary<TKey, TValue> _dictionary;
721 public ValueCollection (Dictionary<TKey, TValue> dictionary)
723 _dictionary = dictionary;
726 void ICollection<TValue>.Add (TValue item)
728 throw new InvalidOperationException ();
731 void ICollection<TValue>.Clear ()
733 throw new InvalidOperationException ();
736 bool ICollection<TValue>.Contains (TValue item)
738 return _dictionary.ContainsValue (item);
741 bool ICollection<TValue>.Remove (TValue item)
743 throw new InvalidOperationException ();
746 void ICollection.CopyTo (Array array, int index)
748 CopyTo ((TValue []) array, index);
751 public void CopyTo (TValue [] array, int index)
754 throw new ArgumentNullException ("array");
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!");
762 IEnumerable<TValue> enumerateThis = (IEnumerable<TValue>) this;
763 foreach (TValue v in enumerateThis) {
768 public Enumerator GetEnumerator ()
770 return new Enumerator (_dictionary);
773 IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator ()
775 return new ValueEnumerator (_dictionary);
778 IEnumerator IEnumerable.GetEnumerator ()
780 return new Enumerator (_dictionary, EnumerationMode.Value);
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; } }
789 public struct ValueEnumerator : IEnumerator<TValue>
791 IEnumerator _hostEnumerator;
792 internal ValueEnumerator (Dictionary<TKey, TValue> dictionary)
794 _hostEnumerator = new Enumerator (dictionary, EnumerationMode.Value);
797 public void Dispose ()
801 public bool MoveNext ()
803 return _hostEnumerator.MoveNext ();
806 public TValue Current {
808 return (TValue) _hostEnumerator.Current;
812 object IEnumerator.Current {
814 return _hostEnumerator.Current;
818 void IEnumerator.Reset ()
820 _hostEnumerator.Reset ();
826 static bool TestPrime (int x)
829 for (int n = 3; n < (int) Math.Sqrt (x); n += 2) {
835 // There is only one even prime - 2.
839 static int CalcPrime (int x)
841 for (int i = (x & (~1)) - 1; i < Int32.MaxValue; i += 2) {
842 if (TestPrime (i)) return i;
847 static int ToPrime (int x)
849 for (int i = 0; i < primeTbl.Length; i++) {
850 if (x <= primeTbl [i])
853 return CalcPrime (x);
856 static readonly int [] primeTbl = {