1 namespace System.Collections.Generic {
3 using System.Diagnostics;
4 using System.Diagnostics.CodeAnalysis;
5 using System.Runtime.Serialization;
10 [DebuggerTypeProxy(typeof(System_DictionaryDebugView<,>))]
11 [DebuggerDisplay("Count = {Count}")]
12 public class SortedDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary {
16 private KeyCollection keys;
21 private ValueCollection values;
23 private TreeSet<KeyValuePair<TKey, TValue>> _set;
25 public SortedDictionary() : this((IComparer<TKey>)null) {
28 public SortedDictionary(IDictionary<TKey,TValue> dictionary) : this( dictionary, null) {
31 public SortedDictionary(IDictionary<TKey,TValue> dictionary, IComparer<TKey> comparer) {
32 if( dictionary == null) {
33 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
36 _set = new TreeSet<KeyValuePair<TKey, TValue>>(new KeyValuePairComparer(comparer));
38 foreach(KeyValuePair<TKey, TValue> pair in dictionary) {
43 public SortedDictionary(IComparer<TKey> comparer) {
44 _set = new TreeSet<KeyValuePair<TKey, TValue>>(new KeyValuePairComparer(comparer));
47 void ICollection<KeyValuePair<TKey,TValue>>.Add(KeyValuePair<TKey,TValue> keyValuePair) {
48 _set.Add(keyValuePair);
51 bool ICollection<KeyValuePair<TKey,TValue>>.Contains(KeyValuePair<TKey,TValue> keyValuePair) {
52 TreeSet<KeyValuePair<TKey, TValue>>.Node node = _set.FindNode(keyValuePair);
57 if( keyValuePair.Value == null) {
58 return node.Item.Value == null;
61 return EqualityComparer<TValue>.Default.Equals(node.Item.Value, keyValuePair.Value);
65 bool ICollection<KeyValuePair<TKey,TValue>>.Remove(KeyValuePair<TKey,TValue> keyValuePair) {
66 TreeSet<KeyValuePair<TKey, TValue>>.Node node = _set.FindNode(keyValuePair);
71 if( EqualityComparer<TValue>.Default.Equals(node.Item.Value, keyValuePair.Value)) {
72 _set.Remove(keyValuePair);
78 bool ICollection<KeyValuePair<TKey,TValue>>.IsReadOnly {
84 public TValue this[TKey key] {
87 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
90 TreeSet<KeyValuePair<TKey, TValue>>.Node node = _set.FindNode(new KeyValuePair<TKey, TValue>(key, default(TValue)));
92 ThrowHelper.ThrowKeyNotFoundException();
95 return node.Item.Value;
99 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
102 TreeSet<KeyValuePair<TKey, TValue>>.Node node = _set.FindNode(new KeyValuePair<TKey, TValue>(key, default(TValue)));
104 _set.Add(new KeyValuePair<TKey, TValue>(key, value));
106 node.Item = new KeyValuePair<TKey, TValue>( node.Item.Key, value);
107 _set.UpdateVersion();
118 public IComparer<TKey> Comparer {
120 return ((KeyValuePairComparer)_set.Comparer).keyComparer;
124 public KeyCollection Keys {
126 if (keys == null) keys = new KeyCollection(this);
131 ICollection<TKey> IDictionary<TKey, TValue>.Keys {
137 public ValueCollection Values {
139 if (values == null) values = new ValueCollection(this);
144 ICollection<TValue> IDictionary<TKey, TValue>.Values {
150 public void Add(TKey key, TValue value) {
152 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
154 _set.Add(new KeyValuePair<TKey, TValue>(key, value));
157 public void Clear() {
161 public bool ContainsKey(TKey key) {
163 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
166 return _set.Contains(new KeyValuePair<TKey, TValue>(key, default(TValue)));
169 public bool ContainsValue(TValue value) {
172 _set.InOrderTreeWalk( delegate(TreeSet<KeyValuePair<TKey, TValue>>.Node node) {
173 if(node.Item.Value == null) {
175 return false; // stop the walk
182 EqualityComparer<TValue> valueComparer = EqualityComparer<TValue>.Default;
183 _set.InOrderTreeWalk( delegate(TreeSet<KeyValuePair<TKey, TValue>>.Node node) {
184 if(valueComparer.Equals(node.Item.Value, value)) {
186 return false; // stop the walk
194 public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index) {
195 _set.CopyTo(array, index);
198 public Enumerator GetEnumerator() {
199 return new Enumerator(this, Enumerator.KeyValuePair);
202 IEnumerator<KeyValuePair<TKey,TValue>> IEnumerable<KeyValuePair<TKey,TValue>>.GetEnumerator() {
203 return new Enumerator(this, Enumerator.KeyValuePair);
206 public bool Remove(TKey key) {
208 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
211 return _set.Remove(new KeyValuePair<TKey, TValue>(key, default(TValue)));
214 public bool TryGetValue( TKey key, out TValue value) {
216 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
219 TreeSet<KeyValuePair<TKey, TValue>>.Node node = _set.FindNode(new KeyValuePair<TKey, TValue>(key, default(TValue)));
221 value = default(TValue);
224 value = node.Item.Value;
228 void ICollection.CopyTo(Array array, int index) {
229 ((ICollection)_set).CopyTo(array, index);
232 bool IDictionary.IsFixedSize {
233 get { return false; }
236 bool IDictionary.IsReadOnly {
237 get { return false; }
240 ICollection IDictionary.Keys {
241 get { return (ICollection)Keys; }
244 ICollection IDictionary.Values {
245 get { return (ICollection)Values; }
248 object IDictionary.this[object key] {
250 if( IsCompatibleKey(key)) {
252 if( TryGetValue((TKey)key, out value)) {
262 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
265 ThrowHelper.IfNullAndNullsAreIllegalThenThrow<TValue>(value, ExceptionArgument.value);
268 TKey tempKey = (TKey)key;
270 this[tempKey] = (TValue)value;
272 catch (InvalidCastException) {
273 ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(TValue));
276 catch (InvalidCastException) {
277 ThrowHelper.ThrowWrongKeyTypeArgumentException(key, typeof(TKey));
282 void IDictionary.Add(object key, object value) {
285 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
288 ThrowHelper.IfNullAndNullsAreIllegalThenThrow<TValue>(value, ExceptionArgument.value);
291 TKey tempKey = (TKey)key;
294 Add(tempKey, (TValue)value);
296 catch (InvalidCastException) {
297 ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(TValue));
300 catch (InvalidCastException) {
301 ThrowHelper.ThrowWrongKeyTypeArgumentException(key, typeof(TKey));
305 bool IDictionary.Contains(object key) {
306 if(IsCompatibleKey(key)) {
307 return ContainsKey((TKey)key);
312 private static bool IsCompatibleKey(object key) {
314 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
317 return (key is TKey);
320 IDictionaryEnumerator IDictionary.GetEnumerator() {
321 return new Enumerator(this, Enumerator.DictEntry);
324 void IDictionary.Remove(object key) {
325 if(IsCompatibleKey(key))
331 bool ICollection.IsSynchronized {
332 get { return false; }
335 object ICollection.SyncRoot {
336 get { return ((ICollection)_set).SyncRoot; }
339 IEnumerator IEnumerable.GetEnumerator() {
340 return new Enumerator(this, Enumerator.KeyValuePair);
343 [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "not an expected scenario")]
344 public struct Enumerator : IEnumerator<KeyValuePair<TKey,TValue>>, IDictionaryEnumerator {
345 private TreeSet<KeyValuePair<TKey, TValue>>.Enumerator treeEnum;
346 private int getEnumeratorRetType; // What should Enumerator.Current return?
348 internal const int KeyValuePair = 1;
349 internal const int DictEntry = 2;
351 internal Enumerator(SortedDictionary<TKey, TValue> dictionary, int getEnumeratorRetType) {
352 treeEnum = dictionary._set.GetEnumerator();
353 this.getEnumeratorRetType = getEnumeratorRetType;
356 public bool MoveNext() {
357 return treeEnum.MoveNext();
360 public void Dispose() {
364 public KeyValuePair<TKey, TValue> Current {
366 return treeEnum.Current;
370 internal bool NotStartedOrEnded {
372 return treeEnum.NotStartedOrEnded;
376 internal void Reset() {
381 void IEnumerator.Reset() {
385 object IEnumerator.Current {
387 if( NotStartedOrEnded) {
388 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
391 if (getEnumeratorRetType == DictEntry) {
392 return new DictionaryEntry(Current.Key, Current.Value);
394 return new KeyValuePair<TKey, TValue>(Current.Key, Current.Value);
400 object IDictionaryEnumerator.Key {
402 if(NotStartedOrEnded) {
403 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
410 object IDictionaryEnumerator.Value {
412 if(NotStartedOrEnded) {
413 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
416 return Current.Value;
420 DictionaryEntry IDictionaryEnumerator.Entry {
422 if(NotStartedOrEnded) {
423 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
426 return new DictionaryEntry(Current.Key, Current.Value);
431 [DebuggerTypeProxy(typeof(System_DictionaryKeyCollectionDebugView<,>))]
432 [DebuggerDisplay("Count = {Count}")]
436 public sealed class KeyCollection: ICollection<TKey>, ICollection {
437 private SortedDictionary<TKey,TValue> dictionary;
439 public KeyCollection(SortedDictionary<TKey,TValue> dictionary) {
440 if (dictionary == null) {
441 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
443 this.dictionary = dictionary;
446 public Enumerator GetEnumerator() {
447 return new Enumerator(dictionary);
450 IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator() {
451 return new Enumerator(dictionary);
454 IEnumerator IEnumerable.GetEnumerator() {
455 return new Enumerator(dictionary);
458 public void CopyTo(TKey[] array, int index) {
460 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
464 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
467 if (array.Length - index < Count) {
468 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
471 dictionary._set.InOrderTreeWalk( delegate(TreeSet<KeyValuePair<TKey, TValue>>.Node node){ array[index++] = node.Item.Key; return true;});
474 void ICollection.CopyTo(Array array, int index) {
476 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
479 if (array.Rank != 1) {
480 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
483 if( array.GetLowerBound(0) != 0 ) {
484 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
488 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
491 if (array.Length - index < dictionary.Count) {
492 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
495 TKey[] keys = array as TKey[];
500 object[] objects = (object[])array;
501 if (objects == null) {
502 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
506 dictionary._set.InOrderTreeWalk( delegate(TreeSet<KeyValuePair<TKey, TValue>>.Node node){ objects[index++] = node.Item.Key; return true;});
508 catch(ArrayTypeMismatchException) {
509 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
515 get { return dictionary.Count;}
518 bool ICollection<TKey>.IsReadOnly {
522 void ICollection<TKey>.Add(TKey item){
523 ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
526 void ICollection<TKey>.Clear(){
527 ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
530 bool ICollection<TKey>.Contains(TKey item){
531 return dictionary.ContainsKey(item);
534 bool ICollection<TKey>.Remove(TKey item){
535 ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
539 bool ICollection.IsSynchronized {
540 get { return false; }
543 Object ICollection.SyncRoot {
544 get { return ((ICollection)dictionary).SyncRoot; }
547 [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "not an expected scenario")]
548 public struct Enumerator : IEnumerator<TKey>, IEnumerator {
549 private SortedDictionary<TKey, TValue>.Enumerator dictEnum;
551 internal Enumerator(SortedDictionary<TKey, TValue> dictionary) {
552 dictEnum = dictionary.GetEnumerator();
555 public void Dispose() {
559 public bool MoveNext() {
560 return dictEnum.MoveNext();
563 public TKey Current {
565 return dictEnum.Current.Key;
569 object IEnumerator.Current {
571 if( dictEnum.NotStartedOrEnded) {
572 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
579 void IEnumerator.Reset() {
586 [DebuggerTypeProxy(typeof(System_DictionaryValueCollectionDebugView<,>))]
587 [DebuggerDisplay("Count = {Count}")]
591 public sealed class ValueCollection: ICollection<TValue>, ICollection {
592 private SortedDictionary<TKey,TValue> dictionary;
594 public ValueCollection(SortedDictionary<TKey,TValue> dictionary) {
595 if (dictionary == null) {
596 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
598 this.dictionary = dictionary;
601 public Enumerator GetEnumerator() {
602 return new Enumerator(dictionary);
605 IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator() {
606 return new Enumerator(dictionary);
609 IEnumerator IEnumerable.GetEnumerator() {
610 return new Enumerator(dictionary);
613 public void CopyTo(TValue[] array, int index) {
615 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
619 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
622 if (array.Length - index < Count) {
623 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
626 dictionary._set.InOrderTreeWalk( delegate(TreeSet<KeyValuePair<TKey, TValue>>.Node node){ array[index++] = node.Item.Value; return true;});
629 void ICollection.CopyTo(Array array, int index) {
631 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
634 if (array.Rank != 1) {
635 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
638 if( array.GetLowerBound(0) != 0 ) {
639 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
643 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
646 if (array.Length - index < dictionary.Count) {
647 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
650 TValue[] values = array as TValue[];
651 if (values != null) {
652 CopyTo(values, index);
655 object[] objects = (object[])array;
656 if (objects == null) {
657 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
661 dictionary._set.InOrderTreeWalk( delegate(TreeSet<KeyValuePair<TKey, TValue>>.Node node){ objects[index++] = node.Item.Value; return true;});
663 catch(ArrayTypeMismatchException) {
664 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
670 get { return dictionary.Count;}
673 bool ICollection<TValue>.IsReadOnly {
677 void ICollection<TValue>.Add(TValue item){
678 ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
681 void ICollection<TValue>.Clear(){
682 ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
685 bool ICollection<TValue>.Contains(TValue item){
686 return dictionary.ContainsValue(item);
689 bool ICollection<TValue>.Remove(TValue item){
690 ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
694 bool ICollection.IsSynchronized {
695 get { return false; }
698 Object ICollection.SyncRoot {
699 get { return ((ICollection)dictionary).SyncRoot; }
702 [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "not an expected scenario")]
703 public struct Enumerator : IEnumerator<TValue>, IEnumerator {
704 private SortedDictionary<TKey, TValue>.Enumerator dictEnum;
706 internal Enumerator(SortedDictionary<TKey, TValue> dictionary) {
707 dictEnum = dictionary.GetEnumerator();
710 public void Dispose() {
714 public bool MoveNext() {
715 return dictEnum.MoveNext();
718 public TValue Current {
720 return dictEnum.Current.Value;
724 object IEnumerator.Current {
726 if( dictEnum.NotStartedOrEnded) {
727 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
734 void IEnumerator.Reset() {
743 internal class KeyValuePairComparer : Comparer<KeyValuePair<TKey, TValue>> {
744 internal IComparer<TKey> keyComparer;
746 public KeyValuePairComparer(IComparer<TKey> keyComparer) {
747 if ( keyComparer == null) {
748 this.keyComparer = Comparer<TKey>.Default;
750 this.keyComparer = keyComparer;
754 public override int Compare( KeyValuePair<TKey, TValue> x, KeyValuePair<TKey, TValue> y) {
755 return keyComparer.Compare(x.Key, y.Key);
763 /// This class is intended as a helper for backwards compatibility with existing SortedDictionaries.
764 /// TreeSet has been converted into SortedSet<T>, which will be exposed publicly. SortedDictionaries
765 /// have the problem where they have already been serialized to disk as having a backing class named
766 /// TreeSet. To ensure that we can read back anything that has already been written to disk, we need to
767 /// make sure that we have a class named TreeSet that does everything the way it used to.
769 /// The only thing that makes it different from SortedSet is that it throws on duplicates
771 /// <typeparam name="T"></typeparam>
775 internal class TreeSet<T> : SortedSet<T> {
780 public TreeSet(IComparer<T> comparer) : base(comparer) { }
782 public TreeSet(ICollection<T> collection) : base(collection) { }
784 public TreeSet(ICollection<T> collection, IComparer<T> comparer) : base(collection, comparer) { }
787 public TreeSet(SerializationInfo siInfo, StreamingContext context) : base(siInfo, context) { }
790 internal override bool AddIfNotPresent(T item) {
791 bool ret = base.AddIfNotPresent(item);
793 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);