2 // System.Collections.Generic.SortedDictionary
5 // Raja R Harinath <rharinath@novell.com>
7 // Authors of previous (superseded) version:
8 // Kazuki Oikawa (kazuki@panicode.com)
9 // Atsushi Enomoto (atsushi@ximian.com)
13 // Copyright (C) 2007, Novell, Inc.
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.Diagnostics;
38 using System.Runtime.Serialization;
39 using System.Security.Permissions;
41 namespace System.Collections.Generic
44 [DebuggerDisplay ("Count={Count}")]
45 [DebuggerTypeProxy (typeof (CollectionDebuggerView<,>))]
46 public class SortedDictionary<TKey,TValue> : IDictionary<TKey,TValue>, ICollection<KeyValuePair<TKey,TValue>>, IEnumerable<KeyValuePair<TKey,TValue>>, IDictionary, ICollection, IEnumerable, ISerializable
48 class Node : RBTree.Node {
52 public Node (TKey key)
57 public Node (TKey key, TValue value)
63 public override void SwapValue (RBTree.Node other)
65 Node o = (Node) other;
66 TKey k = key; key = o.key; o.key = k;
67 TValue v = value; value = o.value; o.value = v;
70 public KeyValuePair<TKey, TValue> AsKV ()
72 return new KeyValuePair<TKey, TValue> (key, value);
75 public DictionaryEntry AsDE ()
77 return new DictionaryEntry (key, value);
82 class NodeHelper : RBTree.INodeHelper<TKey> {
83 public IComparer<TKey> cmp;
85 public int Compare (TKey key, RBTree.Node node)
87 return cmp.Compare (key, ((Node) node).key);
90 public RBTree.Node CreateNode (TKey key)
92 return new Node (key);
95 private NodeHelper (IComparer<TKey> cmp)
99 static NodeHelper Default = new NodeHelper (Comparer<TKey>.Default);
100 public static NodeHelper GetHelper (IComparer<TKey> cmp)
102 if (cmp == null || cmp == Comparer<TKey>.Default)
104 return new NodeHelper (cmp);
112 public SortedDictionary () : this ((IComparer<TKey>) null)
116 public SortedDictionary (IComparer<TKey> comparer)
118 hlp = NodeHelper.GetHelper (comparer);
119 tree = new RBTree (hlp);
122 public SortedDictionary (IDictionary<TKey,TValue> dictionary) : this (dictionary, null)
126 public SortedDictionary (IDictionary<TKey,TValue> dictionary, IComparer<TKey> comparer) : this (comparer)
128 if (dictionary == null)
129 throw new ArgumentNullException ("dictionary");
131 foreach (KeyValuePair<TKey, TValue> entry in dictionary)
132 Add (entry.Key, entry.Value);
135 protected SortedDictionary (SerializationInfo info, StreamingContext context)
137 hlp = (NodeHelper)info.GetValue("Helper", typeof(NodeHelper));
138 tree = new RBTree (hlp);
140 KeyValuePair<TKey, TValue> [] data = (KeyValuePair<TKey, TValue>[])info.GetValue("KeyValuePairs", typeof(KeyValuePair<TKey, TValue>[]));
141 foreach (KeyValuePair<TKey, TValue> entry in data)
142 Add(entry.Key, entry.Value);
147 #region PublicProperty
149 public IComparer<TKey> Comparer {
150 get { return hlp.cmp; }
154 get { return (int) tree.Count; }
157 public TValue this [TKey key] {
159 Node n = (Node) tree.Lookup (key);
161 throw new KeyNotFoundException ();
166 throw new ArgumentNullException ("key");
167 Node n = (Node) tree.Intern (key, null);
172 public KeyCollection Keys {
173 get { return new KeyCollection (this); }
176 public ValueCollection Values {
177 get { return new ValueCollection (this); }
183 public void Add (TKey key, TValue value)
186 throw new ArgumentNullException ("key");
188 RBTree.Node n = new Node (key, value);
189 if (tree.Intern (key, n) != n)
190 throw new ArgumentException ("key already present in dictionary", "key");
198 public bool ContainsKey (TKey key)
200 return tree.Lookup (key) != null;
203 public bool ContainsValue (TValue value)
205 IEqualityComparer<TValue> vcmp = EqualityComparer<TValue>.Default;
206 foreach (Node n in tree)
207 if (vcmp.Equals (value, n.value))
212 public void CopyTo (KeyValuePair<TKey,TValue>[] array, int index)
217 throw new ArgumentNullException ();
218 if (index < 0 || array.Length <= index)
219 throw new ArgumentOutOfRangeException ();
220 if (array.Length - index < Count)
221 throw new ArgumentException ();
223 foreach (Node n in tree)
224 array [index ++] = n.AsKV ();
227 public Enumerator GetEnumerator ()
229 return new Enumerator (this);
232 public bool Remove (TKey key)
234 return tree.Remove (key) != null;
237 public bool TryGetValue (TKey key, out TValue value)
239 Node n = (Node) tree.Lookup (key);
240 value = n == null ? default (TValue) : n.value;
244 [SecurityPermission (SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
245 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
248 throw new ArgumentNullException ("info");
250 KeyValuePair<TKey, TValue> [] data = new KeyValuePair<TKey,TValue> [Count];
252 info.AddValue ("KeyValuePairs", data);
253 info.AddValue ("Helper", hlp);
258 #region PrivateMethod
259 TKey ToKey (object key)
262 throw new ArgumentNullException ("key");
264 throw new ArgumentException (String.Format ("Key \"{0}\" cannot be converted to the key type {1}.", key, typeof (TKey)));
268 TValue ToValue (object value)
270 if (!(value is TValue) && (value != null || typeof (TValue).IsValueType))
271 throw new ArgumentException (String.Format ("Value \"{0}\" cannot be converted to the value type {1}.", value, typeof (TValue)));
272 return (TValue) value;
276 #region IDictionary<TKey,TValue> Member
278 ICollection<TKey> IDictionary<TKey,TValue>.Keys {
279 get { return new KeyCollection (this); }
282 ICollection<TValue> IDictionary<TKey,TValue>.Values {
283 get { return new ValueCollection (this); }
288 #region ICollection<KeyValuePair<TKey,TValue>> Member
290 void ICollection<KeyValuePair<TKey,TValue>>.Add (KeyValuePair<TKey,TValue> item)
292 Add (item.Key, item.Value);
295 bool ICollection<KeyValuePair<TKey,TValue>>.Contains (KeyValuePair<TKey,TValue> item)
298 return TryGetValue (item.Key, out value) &&
299 EqualityComparer<TValue>.Default.Equals (item.Value, value);
302 bool ICollection<KeyValuePair<TKey,TValue>>.IsReadOnly {
303 get { return false; }
306 bool ICollection<KeyValuePair<TKey,TValue>>.Remove (KeyValuePair<TKey,TValue> item)
309 return TryGetValue (item.Key, out value) &&
310 EqualityComparer<TValue>.Default.Equals (item.Value, value) &&
316 #region IDictionary Member
318 void IDictionary.Add (object key, object value)
320 Add (ToKey (key), ToValue (value));
323 bool IDictionary.Contains (object key)
325 return ContainsKey (ToKey (key));
328 IDictionaryEnumerator IDictionary.GetEnumerator ()
330 return new Enumerator (this);
333 bool IDictionary.IsFixedSize {
334 get { return false; }
337 bool IDictionary.IsReadOnly {
338 get { return false; }
341 ICollection IDictionary.Keys {
342 get { return new KeyCollection (this); }
345 void IDictionary.Remove (object key)
347 Remove (ToKey (key));
350 ICollection IDictionary.Values {
351 get { return new ValueCollection (this); }
354 object IDictionary.this [object key] {
355 get { return this [ToKey (key)]; }
356 set { this [ToKey (key)] = ToValue (value); }
361 #region ICollection Member
363 void ICollection.CopyTo (Array array, int index)
368 throw new ArgumentNullException ();
369 if (index < 0 || array.Length <= index)
370 throw new ArgumentOutOfRangeException ();
371 if (array.Length - index < Count)
372 throw new ArgumentException ();
374 foreach (Node n in tree)
375 array.SetValue (n.AsDE (), index++);
378 bool ICollection.IsSynchronized {
379 get { return false; }
382 // TODO:Is this correct? If this is wrong,please fix.
383 object ICollection.SyncRoot {
389 #region IEnumerable Member
391 IEnumerator IEnumerable.GetEnumerator ()
393 return new Enumerator (this);
398 #region IEnumerable<TKey> Member
400 IEnumerator<KeyValuePair<TKey,TValue>> IEnumerable<KeyValuePair<TKey,TValue>>.GetEnumerator ()
402 return new Enumerator (this);
408 [DebuggerDisplay ("Count={Count}")]
409 [DebuggerTypeProxy (typeof (CollectionDebuggerView<,>))]
410 public sealed class ValueCollection : ICollection<TValue>,
411 IEnumerable<TValue>, ICollection, IEnumerable
413 SortedDictionary<TKey,TValue> _dic;
415 public ValueCollection (SortedDictionary<TKey,TValue> dictionary)
417 if (dictionary == null)
418 throw new ArgumentNullException ("dictionary");
423 void ICollection<TValue>.Add (TValue item)
425 throw new NotSupportedException ();
428 void ICollection<TValue>.Clear ()
430 throw new NotSupportedException ();
433 bool ICollection<TValue>.Contains (TValue item)
435 return _dic.ContainsValue (item);
438 public void CopyTo (TValue [] array, int index)
443 throw new ArgumentNullException ();
444 if (index < 0 || array.Length <= index)
445 throw new ArgumentOutOfRangeException ();
446 if (array.Length - index < Count)
447 throw new ArgumentException ();
448 foreach (Node n in _dic.tree)
449 array [index++] = n.value;
453 get { return _dic.Count; }
456 bool ICollection<TValue>.IsReadOnly {
460 bool ICollection<TValue>.Remove (TValue item)
462 throw new NotSupportedException ();
465 IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator ()
467 return GetEnumerator ();
470 public Enumerator GetEnumerator ()
472 return new Enumerator (_dic);
475 void ICollection.CopyTo (Array array, int index)
480 throw new ArgumentNullException ();
481 if (index < 0 || array.Length <= index)
482 throw new ArgumentOutOfRangeException ();
483 if (array.Length - index < Count)
484 throw new ArgumentException ();
485 foreach (Node n in _dic.tree)
486 array.SetValue (n.value, index++);
489 bool ICollection.IsSynchronized {
490 get { return false; }
493 object ICollection.SyncRoot {
497 IEnumerator IEnumerable.GetEnumerator ()
499 return new Enumerator (_dic);
502 public struct Enumerator : IEnumerator<TValue>,IEnumerator, IDisposable
504 RBTree.NodeEnumerator host;
508 internal Enumerator (SortedDictionary<TKey,TValue> dictionary)
511 host = dictionary.tree.GetEnumerator ();
514 public TValue Current {
515 get { return current; }
518 public bool MoveNext ()
520 if (!host.MoveNext ())
522 current = ((Node) host.Current).value;
526 public void Dispose ()
531 object IEnumerator.Current {
533 host.check_current ();
538 void IEnumerator.Reset ()
546 [DebuggerDisplay ("Count={Count}")]
547 [DebuggerTypeProxy (typeof (CollectionDebuggerView<,>))]
548 public sealed class KeyCollection : ICollection<TKey>,
549 IEnumerable<TKey>, ICollection, IEnumerable
551 SortedDictionary<TKey,TValue> _dic;
553 public KeyCollection (SortedDictionary<TKey,TValue> dictionary)
558 void ICollection<TKey>.Add (TKey item)
560 throw new NotSupportedException ();
563 void ICollection<TKey>.Clear ()
565 throw new NotSupportedException ();
568 bool ICollection<TKey>.Contains (TKey item)
570 return _dic.ContainsKey (item);
573 IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator ()
575 return GetEnumerator ();
578 public void CopyTo (TKey [] array, int index)
583 throw new ArgumentNullException ();
584 if (index < 0 || array.Length <= index)
585 throw new ArgumentOutOfRangeException ();
586 if (array.Length - index < Count)
587 throw new ArgumentException ();
588 foreach (Node n in _dic.tree)
589 array [index++] = n.key;
593 get { return _dic.Count; }
596 bool ICollection<TKey>.IsReadOnly {
600 bool ICollection<TKey>.Remove (TKey item)
602 throw new NotSupportedException ();
605 public Enumerator GetEnumerator ()
607 return new Enumerator (_dic);
610 void ICollection.CopyTo (Array array, int index)
615 throw new ArgumentNullException ();
616 if (index < 0 || array.Length <= index)
617 throw new ArgumentOutOfRangeException ();
618 if (array.Length - index < Count)
619 throw new ArgumentException ();
620 foreach (Node n in _dic.tree)
621 array.SetValue (n.key, index++);
624 bool ICollection.IsSynchronized {
625 get { return false; }
628 object ICollection.SyncRoot {
632 IEnumerator IEnumerable.GetEnumerator ()
634 return new Enumerator (_dic);
637 public struct Enumerator : IEnumerator<TKey>, IEnumerator, IDisposable
639 RBTree.NodeEnumerator host;
643 internal Enumerator (SortedDictionary<TKey,TValue> dic)
646 host = dic.tree.GetEnumerator ();
649 public TKey Current {
650 get { return current; }
653 public bool MoveNext ()
655 if (!host.MoveNext ())
657 current = ((Node) host.Current).key;
661 public void Dispose ()
666 object IEnumerator.Current {
668 host.check_current ();
673 void IEnumerator.Reset ()
680 public struct Enumerator : IEnumerator<KeyValuePair<TKey,TValue>>, IDisposable, IDictionaryEnumerator, IEnumerator
682 RBTree.NodeEnumerator host;
684 KeyValuePair<TKey, TValue> current;
686 internal Enumerator (SortedDictionary<TKey,TValue> dic)
689 host = dic.tree.GetEnumerator ();
692 public KeyValuePair<TKey,TValue> Current {
693 get { return current; }
696 public bool MoveNext ()
698 if (!host.MoveNext ())
700 current = ((Node) host.Current).AsKV ();
704 public void Dispose ()
711 host.check_current ();
712 return (Node) host.Current;
716 DictionaryEntry IDictionaryEnumerator.Entry {
717 get { return CurrentNode.AsDE (); }
720 object IDictionaryEnumerator.Key {
721 get { return CurrentNode.key; }
724 object IDictionaryEnumerator.Value {
725 get { return CurrentNode.value; }
728 object IEnumerator.Current {
729 get { return CurrentNode.AsDE (); }
732 void IEnumerator.Reset ()