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)
420 void ICollection<TValue>.Add (TValue item)
422 throw new NotSupportedException ();
425 void ICollection<TValue>.Clear ()
427 throw new NotSupportedException ();
430 bool ICollection<TValue>.Contains (TValue item)
432 return _dic.ContainsValue (item);
435 public void CopyTo (TValue [] array, int index)
440 throw new ArgumentNullException ();
441 if (index < 0 || array.Length <= index)
442 throw new ArgumentOutOfRangeException ();
443 if (array.Length - index < Count)
444 throw new ArgumentException ();
445 foreach (Node n in _dic.tree)
446 array [index++] = n.value;
450 get { return _dic.Count; }
453 bool ICollection<TValue>.IsReadOnly {
457 bool ICollection<TValue>.Remove (TValue item)
459 throw new NotSupportedException ();
462 IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator ()
464 return GetEnumerator ();
467 public Enumerator GetEnumerator ()
469 return new Enumerator (_dic);
472 void ICollection.CopyTo (Array array, int index)
477 throw new ArgumentNullException ();
478 if (index < 0 || array.Length <= index)
479 throw new ArgumentOutOfRangeException ();
480 if (array.Length - index < Count)
481 throw new ArgumentException ();
482 foreach (Node n in _dic.tree)
483 array.SetValue (n.value, index++);
486 bool ICollection.IsSynchronized {
487 get { return false; }
490 object ICollection.SyncRoot {
494 IEnumerator IEnumerable.GetEnumerator ()
496 return new Enumerator (_dic);
499 public struct Enumerator : IEnumerator<TValue>,IEnumerator, IDisposable
501 RBTree.NodeEnumerator host;
505 internal Enumerator (SortedDictionary<TKey,TValue> dictionary)
508 host = dictionary.tree.GetEnumerator ();
511 public TValue Current {
512 get { return current; }
515 public bool MoveNext ()
517 if (!host.MoveNext ())
519 current = ((Node) host.Current).value;
523 public void Dispose ()
528 object IEnumerator.Current {
530 host.check_current ();
535 void IEnumerator.Reset ()
543 [DebuggerDisplay ("Count={Count}")]
544 [DebuggerTypeProxy (typeof (CollectionDebuggerView<,>))]
545 public sealed class KeyCollection : ICollection<TKey>,
546 IEnumerable<TKey>, ICollection, IEnumerable
548 SortedDictionary<TKey,TValue> _dic;
550 public KeyCollection (SortedDictionary<TKey,TValue> dictionary)
555 void ICollection<TKey>.Add (TKey item)
557 throw new NotSupportedException ();
560 void ICollection<TKey>.Clear ()
562 throw new NotSupportedException ();
565 bool ICollection<TKey>.Contains (TKey item)
567 return _dic.ContainsKey (item);
570 IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator ()
572 return GetEnumerator ();
575 public void CopyTo (TKey [] array, int index)
580 throw new ArgumentNullException ();
581 if (index < 0 || array.Length <= index)
582 throw new ArgumentOutOfRangeException ();
583 if (array.Length - index < Count)
584 throw new ArgumentException ();
585 foreach (Node n in _dic.tree)
586 array [index++] = n.key;
590 get { return _dic.Count; }
593 bool ICollection<TKey>.IsReadOnly {
597 bool ICollection<TKey>.Remove (TKey item)
599 throw new NotSupportedException ();
602 public Enumerator GetEnumerator ()
604 return new Enumerator (_dic);
607 void ICollection.CopyTo (Array array, int index)
612 throw new ArgumentNullException ();
613 if (index < 0 || array.Length <= index)
614 throw new ArgumentOutOfRangeException ();
615 if (array.Length - index < Count)
616 throw new ArgumentException ();
617 foreach (Node n in _dic.tree)
618 array.SetValue (n.key, index++);
621 bool ICollection.IsSynchronized {
622 get { return false; }
625 object ICollection.SyncRoot {
629 IEnumerator IEnumerable.GetEnumerator ()
631 return new Enumerator (_dic);
634 public struct Enumerator : IEnumerator<TKey>, IEnumerator, IDisposable
636 RBTree.NodeEnumerator host;
640 internal Enumerator (SortedDictionary<TKey,TValue> dic)
643 host = dic.tree.GetEnumerator ();
646 public TKey Current {
647 get { return current; }
650 public bool MoveNext ()
652 if (!host.MoveNext ())
654 current = ((Node) host.Current).key;
658 public void Dispose ()
663 object IEnumerator.Current {
665 host.check_current ();
670 void IEnumerator.Reset ()
677 public struct Enumerator : IEnumerator<KeyValuePair<TKey,TValue>>, IDisposable, IDictionaryEnumerator, IEnumerator
679 RBTree.NodeEnumerator host;
681 KeyValuePair<TKey, TValue> current;
683 internal Enumerator (SortedDictionary<TKey,TValue> dic)
686 host = dic.tree.GetEnumerator ();
689 public KeyValuePair<TKey,TValue> Current {
690 get { return current; }
693 public bool MoveNext ()
695 if (!host.MoveNext ())
697 current = ((Node) host.Current).AsKV ();
701 public void Dispose ()
708 host.check_current ();
709 return (Node) host.Current;
713 DictionaryEntry IDictionaryEnumerator.Entry {
714 get { return CurrentNode.AsDE (); }
717 object IDictionaryEnumerator.Key {
718 get { return CurrentNode.key; }
721 object IDictionaryEnumerator.Value {
722 get { return CurrentNode.value; }
725 object IEnumerator.Current {
726 get { return CurrentNode.AsDE (); }
729 void IEnumerator.Reset ()