2 // System.Collections.Generic.SortedDictionary
5 // Kazuki Oikawa (kazuki@panicode.com)
6 // Atsushi Enomoto (atsushi@ximian.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
34 namespace System.Collections.Generic
37 public class SortedDictionary<TKey,TValue> : IDictionary<TKey,TValue>, ICollection<KeyValuePair<TKey,TValue>>, IEnumerable<KeyValuePair<TKey,TValue>>, IDictionary, ICollection, IEnumerable
41 IComparer<TKey> _comparer;
44 const int DefaultCapacitySize = 4;
46 KeyCollection _keyList;
47 ValueCollection _valueList;
50 public SortedDictionary () : this (0, null)
54 public SortedDictionary (IComparer<TKey> comparer) : this (0, comparer)
58 public SortedDictionary (IDictionary<TKey,TValue> dic) : this (dic, null)
62 // it disappeared in 2.0 RTM
63 SortedDictionary (int capacity) : this (capacity, null)
68 public SortedDictionary (IDictionary<TKey,TValue> dic, IComparer<TKey> comparer) : this (dic == null ? 0 : dic.Count, comparer)
71 throw new ArgumentNullException ();
73 dic.Keys.CopyTo (_keys, 0);
74 dic.Values.CopyTo (_values, 0);
75 Array.Sort<TKey,TValue> (_keys, _values);
79 // it disappeared in 2.0 RTM
80 SortedDictionary (int capacity, IComparer<TKey> comparer)
83 throw new ArgumentOutOfRangeException ();
85 _keys = new TKey [capacity];
86 _values = new TValue [capacity];
90 _comparer = Comparer<TKey>.Default;
96 #region PublicProperty
98 public IComparer<TKey> Comparer {
99 get { return _comparer; }
102 // It disappeared in 2.0 RTM.
104 get { return _keys.Length; }
107 throw new ArgumentOutOfRangeException ();
109 Array.Resize<TKey> (ref _keys, value);
110 Array.Resize<TValue> (ref _values, value);
115 get { return _size; }
118 public TValue this [TKey key] {
120 int index = IndexOfKey (key);
122 return _values [index];
124 throw new KeyNotFoundException ();
128 throw new ArgumentNullException ();
130 int index = IndexOfKey (key);
134 _values [index] = value;
138 public KeyCollection Keys {
139 get { return GetKeyCollection (); }
142 public ValueCollection Values {
143 get { return GetValueCollection (); }
149 public void Add (TKey key, TValue value)
152 throw new ArgumentNullException ();
154 int index = Array.BinarySearch<TKey> (_keys, 0, _size, key, _comparer);
156 throw new ArgumentException ();
160 if (_size == _keys.Length)
161 Capacity += Capacity > 0 ? Capacity : DefaultCapacitySize;
164 Array.Copy (_keys, index, _keys, index + 1, _size - index);
165 Array.Copy (_values, index, _values, index + 1, _size - index);
169 _values [index] = value;
176 Array.Clear (_keys, 0, _size);
177 Array.Clear (_values, 0, _size);
182 public bool ContainsKey (TKey key)
184 return IndexOfKey (key) >= 0;
187 public bool ContainsValue (TValue value)
189 return IndexOfValue (value) >= 0;
192 public void CopyTo (KeyValuePair<TKey,TValue>[] array, int arrayIndex)
195 throw new ArgumentNullException ();
196 if (arrayIndex < 0 || array.Length <= arrayIndex)
197 throw new ArgumentOutOfRangeException ();
198 if (array.Length - arrayIndex < _size)
199 throw new ArgumentException ();
201 for (int i = 0; i < _size; i ++) {
202 array [arrayIndex + i] = new KeyValuePair<TKey,TValue> (_keys [i], _values [i]);
206 public Enumerator GetEnumerator ()
208 return new Enumerator (this);
211 int IndexOfKey (TKey key)
214 throw new ArgumentNullException ();
216 return Array.BinarySearch<TKey> (_keys, 0, _size, key, _comparer);
219 int IndexOfValue (TValue value)
221 return Array.IndexOf<TValue> (_values, value, 0, _size);
224 public bool Remove (TKey key)
226 int index = IndexOfKey (key);
234 void RemoveAt (int index)
236 if (index < 0 || _size <= index)
237 throw new ArgumentOutOfRangeException ();
241 Array.Copy (_keys, index + 1, _keys, index, _size - index);
242 Array.Copy (_values, index + 1, _values, index, _size - index);
245 _keys[_size] = default (TKey) ;
246 _values[_size] = default (TValue) ;
250 public bool TryGetValue (TKey key, out TValue value)
252 int index = IndexOfKey (key);
254 value = _values [index];
258 value = default (TValue) ;
264 #region PrivateMethod
265 private KeyCollection GetKeyCollection ()
267 if (_keyList == null)
268 _keyList = new KeyCollection (this);
271 private ValueCollection GetValueCollection ()
273 if (_valueList == null)
274 _valueList = new ValueCollection (this);
278 TKey ToKey (object key)
281 throw new ArgumentNullException ("key");
283 throw new ArgumentException (String.Format ("Key \"{0}\" cannot be converted to the key type {1}.", key, typeof (TKey)));
287 TValue ToValue (object value)
289 if (!(value is TValue) && (value != null || typeof (TValue).IsValueType))
290 throw new ArgumentException (String.Format ("Value \"{0}\" cannot be converted to the value type {1}.", value, typeof (TValue)));
291 return (TValue) value;
295 #region IDictionary<TKey,TValue> Member
297 ICollection<TKey> IDictionary<TKey,TValue>.Keys {
298 get { return GetKeyCollection (); }
301 ICollection<TValue> IDictionary<TKey,TValue>.Values {
302 get { return GetValueCollection (); }
307 #region ICollection<KeyValuePair<TKey,TValue>> Member
309 void ICollection<KeyValuePair<TKey,TValue>>.Add (KeyValuePair<TKey,TValue> item)
311 Add (item.Key, item.Value);
314 bool ICollection<KeyValuePair<TKey,TValue>>.Contains (KeyValuePair<TKey,TValue> item)
316 int index = IndexOfKey (item.Key);
317 return index >= 0 && Comparer<TValue>.Default.Compare (_values [index], item.Value) == 0;
320 bool ICollection<KeyValuePair<TKey,TValue>>.IsReadOnly {
321 get { return false; }
324 bool ICollection<KeyValuePair<TKey,TValue>>.Remove (KeyValuePair<TKey,TValue> item)
326 int index = IndexOfKey (item.Key);
327 if (index >= 0 && Comparer<TValue>.Default.Compare (_values [index], item.Value) == 0) {
336 #region IDictionary Member
338 void IDictionary.Add (object key, object value)
340 Add (ToKey (key), ToValue (value));
343 bool IDictionary.Contains (object key)
345 return ContainsKey (ToKey (key));
348 IDictionaryEnumerator IDictionary.GetEnumerator ()
350 return new Enumerator (this);
353 bool IDictionary.IsFixedSize {
354 get { return false; }
357 bool IDictionary.IsReadOnly {
358 get { return false; }
361 ICollection IDictionary.Keys {
362 get { return GetKeyCollection (); }
365 void IDictionary.Remove (object key)
367 Remove (ToKey (key));
369 ICollection IDictionary.Values {
370 get { return GetValueCollection (); }
373 object IDictionary.this [object key] {
375 return this [ToKey (key)];
378 if (!(value is TValue))
379 throw new ArgumentException ();
381 this [ToKey (key)] = ToValue (value);
387 #region ICollection Member
389 void ICollection.CopyTo (Array array, int index)
392 throw new ArgumentNullException ();
393 if (index < 0 || array.Length <= index)
394 throw new ArgumentOutOfRangeException ();
395 if (array.Length - index < _size)
396 throw new ArgumentException ();
398 for (int i = 0; i < _size; i ++) {
399 array.SetValue (new KeyValuePair<TKey,TValue> (_keys [i], _values [i]), i);
403 bool ICollection.IsSynchronized {
404 get { return false; }
407 // TODO:Is this correct? If this is wrong,please fix.
408 object ICollection.SyncRoot {
414 #region IEnumerable Member
416 IEnumerator IEnumerable.GetEnumerator ()
418 return new Enumerator (this);
423 #region IEnumerable<TKey> Member
425 IEnumerator<KeyValuePair<TKey,TValue>> IEnumerable<KeyValuePair<TKey,TValue>>.GetEnumerator ()
427 return new Enumerator (this);
433 public sealed class ValueCollection : ICollection<TValue>,
434 IEnumerable<TValue>, ICollection, IEnumerable
436 SortedDictionary<TKey,TValue> _dic;
438 public ValueCollection (SortedDictionary<TKey,TValue> dic)
443 void ICollection<TValue>.Add (TValue item)
445 throw new NotSupportedException ();
448 void ICollection<TValue>.Clear ()
450 throw new NotSupportedException ();
453 bool ICollection<TValue>.Contains (TValue item)
455 return _dic.ContainsValue (item);
458 public void CopyTo (TValue [] array, int arrayIndex)
461 throw new ArgumentNullException ();
462 if (arrayIndex < 0 || array.Length <= arrayIndex)
463 throw new ArgumentOutOfRangeException ();
464 if (array.Length - arrayIndex < _dic._size)
465 throw new ArgumentException ();
466 Array.Copy (_dic._values, 0, array, arrayIndex, _dic._size);
470 get { return _dic._size; }
473 bool ICollection<TValue>.IsReadOnly {
477 bool ICollection<TValue>.Remove (TValue item)
479 throw new NotSupportedException ();
482 IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator ()
484 return GetEnumerator ();
487 public Enumerator GetEnumerator ()
489 return new Enumerator (_dic);
492 void ICollection.CopyTo(Array array, int index)
495 throw new ArgumentNullException ();
496 if (index < 0 || array.Length <= index)
497 throw new ArgumentOutOfRangeException ();
498 if (array.Length - index < _dic._size)
499 throw new ArgumentException ();
500 Array.Copy (_dic._values, 0, array, index, _dic._size);
503 bool ICollection.IsSynchronized {
504 get { return false; }
507 object ICollection.SyncRoot {
511 IEnumerator IEnumerable.GetEnumerator ()
513 return new Enumerator (_dic);
516 public struct Enumerator : IEnumerator<TValue>,IEnumerator, IDisposable
518 SortedDictionary<TKey,TValue> _dic;
523 internal Enumerator (SortedDictionary<TKey,TValue> dic)
526 _version = dic._version;
531 public TValue Current {
533 if (_count <= _index)
534 throw new InvalidOperationException ();
535 return _dic._values [_index];
539 public bool MoveNext ()
541 if (_version != _dic._version)
542 throw new InvalidOperationException ();
544 if (_index + 1 < _count) {
552 public void Dispose ()
557 object IEnumerator.Current {
558 get { return Current; }
561 void IEnumerator.Reset ()
563 if (_version != _dic._version)
564 throw new InvalidOperationException ();
571 public sealed class KeyCollection : ICollection<TKey>,
572 IEnumerable<TKey>, ICollection, IEnumerable
574 SortedDictionary<TKey,TValue> _dic;
576 public KeyCollection (SortedDictionary<TKey,TValue> dic)
581 void ICollection<TKey>.Add (TKey item)
583 throw new NotSupportedException ();
586 void ICollection<TKey>.Clear ()
588 throw new NotSupportedException ();
591 bool ICollection<TKey>.Contains (TKey item)
593 return _dic.ContainsKey (item);
596 IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator ()
598 return GetEnumerator ();
601 public void CopyTo (TKey [] array, int arrayIndex)
603 Array.Copy (_dic._keys, 0, array, arrayIndex, _dic._size);
607 get { return _dic._size; }
610 bool ICollection<TKey>.IsReadOnly {
614 bool ICollection<TKey>.Remove (TKey item)
616 throw new NotSupportedException ();
619 public Enumerator GetEnumerator ()
621 return new Enumerator (_dic);
624 void ICollection.CopyTo (Array array, int index)
627 throw new ArgumentNullException ();
628 if (index < 0 || array.Length <= index)
629 throw new ArgumentOutOfRangeException ();
630 if (array.Length - index < _dic._size)
631 throw new ArgumentException ();
632 Array.Copy (_dic._keys, 0, array, index, _dic._size);
635 bool ICollection.IsSynchronized {
636 get { return false; }
639 object ICollection.SyncRoot {
643 IEnumerator IEnumerable.GetEnumerator ()
645 return new Enumerator (_dic);
648 public struct Enumerator : IEnumerator<TKey>, IEnumerator, IDisposable
650 SortedDictionary<TKey,TValue> _dic;
655 internal Enumerator (SortedDictionary<TKey,TValue> dic)
658 _version = dic._version;
663 public TKey Current {
665 if (_count <= _index)
666 throw new InvalidOperationException ();
667 return _dic._keys [_index];
671 public bool MoveNext ()
673 if (_version != _dic._version)
674 throw new InvalidOperationException ();
676 if (_index + 1 < _count) {
684 public void Dispose ()
689 object IEnumerator.Current {
690 get { return Current; }
693 void IEnumerator.Reset ()
695 if (_version != _dic._version)
696 throw new InvalidOperationException ();
703 public struct Enumerator : IEnumerator<KeyValuePair<TKey,TValue>>, IDisposable , IDictionaryEnumerator, IEnumerator
705 SortedDictionary<TKey,TValue> _dic;
710 internal Enumerator (SortedDictionary<TKey,TValue> dic)
713 _version = dic._version;
718 public KeyValuePair<TKey,TValue> Current {
720 if (_count <= _index)
721 throw new InvalidOperationException ();
722 return new KeyValuePair<TKey,TValue> (_dic._keys [_index], _dic._values [_index]);
726 public bool MoveNext ()
728 if (_version != _dic._version)
729 throw new InvalidOperationException ();
731 if (_index + 1 < _count) {
739 public void Dispose ()
744 DictionaryEntry IDictionaryEnumerator.Entry {
746 if (_count <= _index)
747 throw new InvalidOperationException ();
748 return new DictionaryEntry (_dic._keys [_index], _dic._values [_index]);
752 object IDictionaryEnumerator.Key {
754 if (_count <= _index)
755 throw new InvalidOperationException ();
756 return _dic._keys [_index];
760 object IDictionaryEnumerator.Value {
762 if (_count <= _index)
763 throw new InvalidOperationException ();
764 return _dic._values [_index];
768 object IEnumerator.Current {
770 if (_count <= _index)
771 throw new InvalidOperationException ();
772 return new DictionaryEntry (_dic._keys [_index], _dic._values [_index]);
776 void IEnumerator.Reset ()
778 if (_version != _dic._version)
779 throw new InvalidOperationException ();