// // System.Collections.Generic.SortedDictionary // // Author: // Raja R Harinath // // Authors of previous (superseded) version: // Kazuki Oikawa (kazuki@panicode.com) // Atsushi Enomoto (atsushi@ximian.com) // // // Copyright (C) 2007, Novell, Inc. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections; using System.Diagnostics; using System.Runtime.Serialization; using System.Security.Permissions; namespace System.Collections.Generic { [Serializable] [DebuggerDisplay ("Count={Count}")] [DebuggerTypeProxy (typeof (CollectionDebuggerView<,>))] public class SortedDictionary : IDictionary, ICollection>, IEnumerable>, IDictionary, ICollection, IEnumerable, ISerializable { class Node : RBTree.Node { public TKey key; public TValue value; public Node (TKey key) { this.key = key; } public Node (TKey key, TValue value) { this.key = key; this.value = value; } public override void SwapValue (RBTree.Node other) { Node o = (Node) other; TKey k = key; key = o.key; o.key = k; TValue v = value; value = o.value; o.value = v; } public KeyValuePair AsKV () { return new KeyValuePair (key, value); } public DictionaryEntry AsDE () { return new DictionaryEntry (key, value); } } [Serializable] class NodeHelper : RBTree.INodeHelper { public IComparer cmp; public int Compare (TKey key, RBTree.Node node) { return cmp.Compare (key, ((Node) node).key); } public RBTree.Node CreateNode (TKey key) { return new Node (key); } private NodeHelper (IComparer cmp) { this.cmp = cmp; } static NodeHelper Default = new NodeHelper (Comparer.Default); public static NodeHelper GetHelper (IComparer cmp) { if (cmp == null || cmp == Comparer.Default) return Default; return new NodeHelper (cmp); } } RBTree tree; NodeHelper hlp; #region Constructor public SortedDictionary () : this ((IComparer) null) { } public SortedDictionary (IComparer comparer) { hlp = NodeHelper.GetHelper (comparer); tree = new RBTree (hlp); } public SortedDictionary (IDictionary dictionary) : this (dictionary, null) { } public SortedDictionary (IDictionary dictionary, IComparer comparer) : this (comparer) { if (dictionary == null) throw new ArgumentNullException ("dictionary"); foreach (KeyValuePair entry in dictionary) Add (entry.Key, entry.Value); } protected SortedDictionary (SerializationInfo info, StreamingContext context) { hlp = (NodeHelper)info.GetValue("Helper", typeof(NodeHelper)); tree = new RBTree (hlp); KeyValuePair [] data = (KeyValuePair[])info.GetValue("KeyValuePairs", typeof(KeyValuePair[])); foreach (KeyValuePair entry in data) Add(entry.Key, entry.Value); } #endregion #region PublicProperty public IComparer Comparer { get { return hlp.cmp; } } public int Count { get { return (int) tree.Count; } } public TValue this [TKey key] { get { Node n = (Node) tree.Lookup (key); if (n == null) throw new KeyNotFoundException (); return n.value; } set { if (key == null) throw new ArgumentNullException ("key"); Node n = (Node) tree.Intern (key, null); n.value = value; } } public KeyCollection Keys { get { return new KeyCollection (this); } } public ValueCollection Values { get { return new ValueCollection (this); } } #endregion #region PublicMethod public void Add (TKey key, TValue value) { if (key == null) throw new ArgumentNullException ("key"); RBTree.Node n = new Node (key, value); if (tree.Intern (key, n) != n) throw new ArgumentException ("key already present in dictionary", "key"); } public void Clear () { tree.Clear (); } public bool ContainsKey (TKey key) { return tree.Lookup (key) != null; } public bool ContainsValue (TValue value) { IEqualityComparer vcmp = EqualityComparer.Default; foreach (Node n in tree) if (vcmp.Equals (value, n.value)) return true; return false; } public void CopyTo (KeyValuePair[] array, int index) { if (Count == 0) return; if (array == null) throw new ArgumentNullException (); if (index < 0 || array.Length <= index) throw new ArgumentOutOfRangeException (); if (array.Length - index < Count) throw new ArgumentException (); foreach (Node n in tree) array [index ++] = n.AsKV (); } public Enumerator GetEnumerator () { return new Enumerator (this); } public bool Remove (TKey key) { return tree.Remove (key) != null; } public bool TryGetValue (TKey key, out TValue value) { Node n = (Node) tree.Lookup (key); value = n == null ? default (TValue) : n.value; return n != null; } [SecurityPermission (SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)] public virtual void GetObjectData (SerializationInfo info, StreamingContext context) { if (info == null) throw new ArgumentNullException ("info"); KeyValuePair [] data = new KeyValuePair [Count]; CopyTo (data, 0); info.AddValue ("KeyValuePairs", data); info.AddValue ("Helper", hlp); } #endregion #region PrivateMethod TKey ToKey (object key) { if (key == null) throw new ArgumentNullException ("key"); if (!(key is TKey)) throw new ArgumentException (String.Format ("Key \"{0}\" cannot be converted to the key type {1}.", key, typeof (TKey))); return (TKey) key; } TValue ToValue (object value) { if (!(value is TValue) && (value != null || typeof (TValue).IsValueType)) throw new ArgumentException (String.Format ("Value \"{0}\" cannot be converted to the value type {1}.", value, typeof (TValue))); return (TValue) value; } #endregion #region IDictionary Member ICollection IDictionary.Keys { get { return new KeyCollection (this); } } ICollection IDictionary.Values { get { return new ValueCollection (this); } } #endregion #region ICollection> Member void ICollection>.Add (KeyValuePair item) { Add (item.Key, item.Value); } bool ICollection>.Contains (KeyValuePair item) { TValue value; return TryGetValue (item.Key, out value) && EqualityComparer.Default.Equals (item.Value, value); } bool ICollection>.IsReadOnly { get { return false; } } bool ICollection>.Remove (KeyValuePair item) { TValue value; return TryGetValue (item.Key, out value) && EqualityComparer.Default.Equals (item.Value, value) && Remove (item.Key); } #endregion #region IDictionary Member void IDictionary.Add (object key, object value) { Add (ToKey (key), ToValue (value)); } bool IDictionary.Contains (object key) { return ContainsKey (ToKey (key)); } IDictionaryEnumerator IDictionary.GetEnumerator () { return new Enumerator (this); } bool IDictionary.IsFixedSize { get { return false; } } bool IDictionary.IsReadOnly { get { return false; } } ICollection IDictionary.Keys { get { return new KeyCollection (this); } } void IDictionary.Remove (object key) { Remove (ToKey (key)); } ICollection IDictionary.Values { get { return new ValueCollection (this); } } object IDictionary.this [object key] { get { return this [ToKey (key)]; } set { this [ToKey (key)] = ToValue (value); } } #endregion #region ICollection Member void ICollection.CopyTo (Array array, int index) { if (Count == 0) return; if (array == null) throw new ArgumentNullException (); if (index < 0 || array.Length <= index) throw new ArgumentOutOfRangeException (); if (array.Length - index < Count) throw new ArgumentException (); foreach (Node n in tree) array.SetValue (n.AsDE (), index++); } bool ICollection.IsSynchronized { get { return false; } } // TODO:Is this correct? If this is wrong,please fix. object ICollection.SyncRoot { get { return this; } } #endregion #region IEnumerable Member IEnumerator IEnumerable.GetEnumerator () { return new Enumerator (this); } #endregion #region IEnumerable Member IEnumerator> IEnumerable>.GetEnumerator () { return new Enumerator (this); } #endregion [Serializable] [DebuggerDisplay ("Count={Count}")] [DebuggerTypeProxy (typeof (CollectionDebuggerView<,>))] public sealed class ValueCollection : ICollection, IEnumerable, ICollection, IEnumerable { SortedDictionary _dic; public ValueCollection (SortedDictionary dictionary) { _dic = dictionary; } void ICollection.Add (TValue item) { throw new NotSupportedException (); } void ICollection.Clear () { throw new NotSupportedException (); } bool ICollection.Contains (TValue item) { return _dic.ContainsValue (item); } public void CopyTo (TValue [] array, int index) { if (Count == 0) return; if (array == null) throw new ArgumentNullException (); if (index < 0 || array.Length <= index) throw new ArgumentOutOfRangeException (); if (array.Length - index < Count) throw new ArgumentException (); foreach (Node n in _dic.tree) array [index++] = n.value; } public int Count { get { return _dic.Count; } } bool ICollection.IsReadOnly { get { return true; } } bool ICollection.Remove (TValue item) { throw new NotSupportedException (); } IEnumerator IEnumerable.GetEnumerator () { return GetEnumerator (); } public Enumerator GetEnumerator () { return new Enumerator (_dic); } void ICollection.CopyTo (Array array, int index) { if (Count == 0) return; if (array == null) throw new ArgumentNullException (); if (index < 0 || array.Length <= index) throw new ArgumentOutOfRangeException (); if (array.Length - index < Count) throw new ArgumentException (); foreach (Node n in _dic.tree) array.SetValue (n.value, index++); } bool ICollection.IsSynchronized { get { return false; } } object ICollection.SyncRoot { get { return _dic; } } IEnumerator IEnumerable.GetEnumerator () { return new Enumerator (_dic); } public struct Enumerator : IEnumerator,IEnumerator, IDisposable { RBTree.NodeEnumerator host; TValue current; internal Enumerator (SortedDictionary dictionary) : this () { host = dictionary.tree.GetEnumerator (); } public TValue Current { get { return current; } } public bool MoveNext () { if (!host.MoveNext ()) return false; current = ((Node) host.Current).value; return true; } public void Dispose () { host.Dispose (); } object IEnumerator.Current { get { host.check_current (); return current; } } void IEnumerator.Reset () { host.Reset (); } } } [Serializable] [DebuggerDisplay ("Count={Count}")] [DebuggerTypeProxy (typeof (CollectionDebuggerView<,>))] public sealed class KeyCollection : ICollection, IEnumerable, ICollection, IEnumerable { SortedDictionary _dic; public KeyCollection (SortedDictionary dictionary) { _dic = dictionary; } void ICollection.Add (TKey item) { throw new NotSupportedException (); } void ICollection.Clear () { throw new NotSupportedException (); } bool ICollection.Contains (TKey item) { return _dic.ContainsKey (item); } IEnumerator IEnumerable.GetEnumerator () { return GetEnumerator (); } public void CopyTo (TKey [] array, int index) { if (Count == 0) return; if (array == null) throw new ArgumentNullException (); if (index < 0 || array.Length <= index) throw new ArgumentOutOfRangeException (); if (array.Length - index < Count) throw new ArgumentException (); foreach (Node n in _dic.tree) array [index++] = n.key; } public int Count { get { return _dic.Count; } } bool ICollection.IsReadOnly { get { return true; } } bool ICollection.Remove (TKey item) { throw new NotSupportedException (); } public Enumerator GetEnumerator () { return new Enumerator (_dic); } void ICollection.CopyTo (Array array, int index) { if (Count == 0) return; if (array == null) throw new ArgumentNullException (); if (index < 0 || array.Length <= index) throw new ArgumentOutOfRangeException (); if (array.Length - index < Count) throw new ArgumentException (); foreach (Node n in _dic.tree) array.SetValue (n.key, index++); } bool ICollection.IsSynchronized { get { return false; } } object ICollection.SyncRoot { get { return _dic; } } IEnumerator IEnumerable.GetEnumerator () { return new Enumerator (_dic); } public struct Enumerator : IEnumerator, IEnumerator, IDisposable { RBTree.NodeEnumerator host; TKey current; internal Enumerator (SortedDictionary dic) : this () { host = dic.tree.GetEnumerator (); } public TKey Current { get { return current; } } public bool MoveNext () { if (!host.MoveNext ()) return false; current = ((Node) host.Current).key; return true; } public void Dispose () { host.Dispose (); } object IEnumerator.Current { get { host.check_current (); return current; } } void IEnumerator.Reset () { host.Reset (); } } } public struct Enumerator : IEnumerator>, IDisposable, IDictionaryEnumerator, IEnumerator { RBTree.NodeEnumerator host; KeyValuePair current; internal Enumerator (SortedDictionary dic) : this () { host = dic.tree.GetEnumerator (); } public KeyValuePair Current { get { return current; } } public bool MoveNext () { if (!host.MoveNext ()) return false; current = ((Node) host.Current).AsKV (); return true; } public void Dispose () { host.Dispose (); } Node CurrentNode { get { host.check_current (); return (Node) host.Current; } } DictionaryEntry IDictionaryEnumerator.Entry { get { return CurrentNode.AsDE (); } } object IDictionaryEnumerator.Key { get { return CurrentNode.key; } } object IDictionaryEnumerator.Value { get { return CurrentNode.value; } } object IEnumerator.Current { get { return CurrentNode.AsDE (); } } void IEnumerator.Reset () { host.Reset (); } } } }