2006-12-01 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System / System.Collections.Specialized / ListDictionary.cs
index af1f56cec28e04a6507d297c807ca917137dc5bb..ed47e0db6a5d8a5f3e6b2c9d33228583e294da11 100644 (file)
@@ -1,3 +1,8 @@
+//
+// System.Collections.Specialized.ListDictionary.cs
+//
+// Copyright (C) 2004, 2005 Novell (http://www.novell.com)
+//
 
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // 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
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-namespace System.Collections.Specialized\r
-{\r
-       [Serializable]\r
-       public class ListDictionary : IDictionary, ICollection, IEnumerable\r
-       {\r
-               private int count;\r
-               private int modCount;\r
-               private ListEntry root;\r
-               private IComparer comparer;\r
-               \r
-               \r
-               public ListDictionary()\r
-               {\r
-                       count = 0;\r
-                       modCount = 0;\r
-                       comparer = null;\r
-                       root = null;\r
-               }\r
-               \r
-               public ListDictionary(IComparer comparer) : this()\r
-               {\r
-                       this.comparer = comparer;\r
-               }\r
-               \r
-               private bool AreEqual(object obj1, object obj2)\r
-               {\r
-                       if (comparer != null) {\r
-                               if (comparer.Compare(obj1, obj2) == 0) {\r
-                                       return true;\r
-                               }\r
-                       } else {\r
-                               if (obj1.Equals(obj2)) {\r
-                                       return true;\r
-                               }\r
-                       }\r
-                       \r
-                       return false;\r
-               }\r
-               \r
-               private ListEntry FindEntry(object key)\r
-               {\r
-                       if (key == null) {\r
-                               throw new ArgumentNullException("Attempted lookup for a null key.");\r
-                       }\r
-                       \r
-                       if (root == null) {\r
-                               return null;\r
-                       } else {\r
-                               ListEntry entry = root;\r
-                               \r
-                               while (entry != null) {\r
-                                       if (AreEqual(key, entry.key)) {\r
-                                               return entry;\r
-                                       }\r
-                                       \r
-                                       entry = entry.next;\r
-                               }\r
-                       }\r
-                       \r
-                       return null;\r
-               }\r
-\r
-               private void AddImpl(object key, object value)\r
-               {\r
-                       if (key == null) {\r
-                               throw new ArgumentNullException("Attempted add with a null key.");\r
-                       }\r
-                       \r
-                       if (root == null) {\r
-                               root = new ListEntry();\r
-                               root.key = key;\r
-                               root.value = value;\r
-                       } else {\r
-                               ListEntry entry = root;\r
-                               \r
-                               while (entry != null) {\r
-                                       if (AreEqual(key, entry.key)) {\r
-                                               throw new ArgumentException("Duplicate key in add.");\r
-                                       }\r
-                                       \r
-                                       if (entry.next == null) {\r
-                                               break;\r
-                                       }\r
-                                       \r
-                                       entry = entry.next;\r
-                               }\r
-                               \r
-                               entry.next = new ListEntry();\r
-                               entry.next.key = key;\r
-                               entry.next.value = value;\r
-                       }\r
-                       \r
-                       count++;\r
-                       modCount++;\r
-               }\r
-               \r
-               // IEnumerable Interface\r
-               IEnumerator IEnumerable.GetEnumerator()\r
-               {\r
-                       return new ListEntryEnumerator(this);\r
-               }\r
-               \r
-               // ICollection Interface\r
-               public int Count {\r
-                       get {\r
-                               return count;\r
-                       }\r
-               }\r
-               \r
-               public bool IsSynchronized {\r
-                       get {\r
-                               return false;\r
-                       }\r
-               }\r
-               \r
-               public object SyncRoot {\r
-                       get {\r
-                               return this;\r
-                       }\r
-               }\r
-\r
-               public void CopyTo(Array array, int index)\r
-               {\r
-                       if (array == null)\r
-                               throw new ArgumentNullException(\r
-                                       "array",\r
-                                       "Array cannot be null.");\r
-\r
-                       if (index < 0)\r
-                               throw new ArgumentOutOfRangeException("index", "index is less than 0");\r
-\r
-                       int i = index;\r
-                       foreach ( DictionaryEntry entry in this )\r
-                               array.SetValue( entry, i++ );\r
-               }\r
-               \r
-               // IDictionary Interface\r
-               public bool IsFixedSize\r
-               {\r
-                       get {\r
-                               return false;\r
-                       }\r
-               }\r
-               \r
-               public bool IsReadOnly\r
-               {\r
-                       get {\r
-                               return false;\r
-                       }\r
-               }\r
-               \r
-               // Indexer\r
-               public object this[object key]\r
-               {\r
-                       get {\r
-                               ListEntry entry = FindEntry(key);\r
-                               return entry == null ? entry : entry.value;\r
-                       }\r
-                       \r
-                       set {\r
-                               ListEntry entry = FindEntry(key);\r
-                               if (entry != null)\r
-                                       entry.value = value;\r
-                               else\r
-                                       AddImpl(key, value);\r
-                       }\r
-               }\r
-               \r
-               public ICollection Keys\r
-               {\r
-                       get {\r
-                               return new ListEntryCollection(this, true);\r
-                       }\r
-               }\r
-               \r
-               public ICollection Values\r
-               {\r
-                       get {\r
-                               return new ListEntryCollection(this, false);\r
-                       }\r
-               }\r
-               \r
-               public void Add(object key, object value)\r
-               {\r
-                       AddImpl(key, value);\r
-               }\r
-               \r
-               public void Clear()\r
-               {\r
-                       root = null;\r
-                       count = 0;\r
-                       modCount++;\r
-               }\r
-               \r
-               public bool Contains(object key)\r
-               {\r
-                       return FindEntry(key) != null ? true : false;\r
-               }\r
-               \r
-               public IDictionaryEnumerator GetEnumerator()\r
-               {\r
-                       return new ListEntryEnumerator(this);\r
-               }\r
-               \r
-               public void Remove(object key)\r
-               {\r
-                       if (key == null)\r
-                               throw new ArgumentNullException(\r
-                                       "key",\r
-                                       "Key cannot be null.");\r
-\r
-                       \r
-                       ListEntry entry = root;\r
-                       \r
-                       for (ListEntry prev = null; entry != null; prev = entry, entry = entry.next) {\r
-                               if (AreEqual(key, entry.key)) {\r
-                                       if (prev != null) {\r
-                                               prev.next = entry.next;\r
-                                       } else {\r
-                                               root = entry.next;\r
-                                       }\r
-                                       \r
-                                       entry.value = null;\r
-                                       count--;\r
-                                       modCount++;\r
-                               }\r
-                       }\r
-               }\r
-               \r
-\r
-               [Serializable]\r
-               private class ListEntry\r
-               {\r
-                       public object key = null;\r
-                       public object value = null;\r
-                       public ListEntry next = null;\r
-               }\r
-\r
-\r
-               private class ListEntryEnumerator : IEnumerator, IDictionaryEnumerator\r
-               {\r
-                       private ListDictionary dict;\r
-                       private bool isAtStart;\r
-                       private ListEntry current;\r
-                       private int version;\r
-                       \r
-                       public ListEntryEnumerator(ListDictionary dict)\r
-                       {\r
-                               this.dict = dict;\r
-                               version = dict.modCount;\r
-                               Reset();\r
-                       }\r
-\r
-                       private void FailFast()\r
-                       {\r
-                               if (version != dict.modCount) {\r
-                                       throw new InvalidOperationException(\r
-                                               "The ListDictionary's contents changed after this enumerator was instantiated.");\r
-                               }\r
-                       }\r
-                               \r
-                       public bool MoveNext()\r
-                       {\r
-                               FailFast();\r
-                               \r
-                               if (isAtStart) {\r
-                                       current = dict.root;\r
-                                       isAtStart = false;\r
-                               } else {\r
-                                       current = current.next;\r
-                               }\r
-                               \r
-                               return current != null ? true : false;  \r
-                       }\r
-                       \r
-                       public void Reset()\r
-                       {\r
-                               FailFast();\r
-\r
-                               isAtStart = true;\r
-                               current = null;\r
-                       }\r
-                       \r
-                       public object Current\r
-                       {\r
-                               get {\r
-                                       FailFast();\r
-                                       \r
-                                       if (isAtStart || current == null) {\r
-                                               throw new InvalidOperationException(\r
-                                                       "Enumerator is positioned before the collection's first element or after the last element.");\r
-                                       }\r
-                                       \r
-                                       return new DictionaryEntry(current.key, current.value);\r
-                               }\r
-                       }\r
-                       \r
-                       // IDictionaryEnumerator\r
-                       public DictionaryEntry Entry\r
-                       {\r
-                               get {\r
-                                       FailFast();\r
-                                       return (DictionaryEntry) Current;\r
-                               }\r
-                       }\r
-                       \r
-                       public object Key\r
-                       {\r
-                               get {\r
-                                       FailFast();\r
-                                       \r
-                                       if (isAtStart || current == null) {\r
-                                               throw new InvalidOperationException(\r
-                                                       "Enumerator is positioned before the collection's first element or after the last element.");\r
-                                       }\r
-                                       \r
-                                       return current.key;\r
-                               }\r
-                       }\r
-                       \r
-                       public object Value\r
-                       {\r
-                               get {\r
-                                       FailFast();\r
-                                       \r
-                                       if (isAtStart || current == null) {\r
-                                               throw new InvalidOperationException(\r
-                                                       "Enumerator is positioned before the collection's first element or after the last element.");\r
-                                       }\r
-                                       \r
-                                       return current.value;\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               private class ListEntryCollection : ICollection\r
-               {\r
-                       private ListDictionary dict;\r
-                       private bool isKeyList;\r
-                               \r
-                       public ListEntryCollection(ListDictionary dict, bool isKeyList)\r
-                       {\r
-                               this.dict = dict;\r
-                               this.isKeyList = isKeyList;\r
-                       }\r
-                       \r
-                       // ICollection Interface\r
-                       public int Count {\r
-                               get {\r
-                                       return dict.Count;\r
-                               }\r
-                       }\r
-                       \r
-                       public bool IsSynchronized\r
-                       {\r
-                               get {\r
-                                       return false;\r
-                               }\r
-                       }\r
-                       \r
-                       public object SyncRoot\r
-                       {\r
-                               get {\r
-                                       return dict.SyncRoot;\r
-                               }\r
-                       }\r
-\r
-                       public void CopyTo(Array array, int index)\r
-                       {\r
-                               int i = index;\r
-                               foreach ( object obj in this )\r
-                                       array.SetValue( obj, i++ );\r
-                       }\r
-                       \r
-                       // IEnumerable Interface\r
-                       public IEnumerator GetEnumerator()\r
-                       {\r
-                               return new ListEntryCollectionEnumerator(dict, isKeyList);\r
-                       }\r
-                       \r
-                       private class ListEntryCollectionEnumerator : IEnumerator\r
-                       {\r
-                               private ListDictionary dict;\r
-                               private bool isKeyList;\r
-                               private bool isAtStart;\r
-                               private int version;\r
-                               private ListEntry current;\r
-                                       \r
-                               public ListEntryCollectionEnumerator(ListDictionary dict, bool isKeyList)\r
-                               {\r
-                                       this.dict = dict;\r
-                                       this.isKeyList = isKeyList;\r
-                                       isAtStart = true;\r
-                                       version = dict.modCount;\r
-                               }\r
-\r
-                               private void FailFast()\r
-                               {\r
-                                       if (version != dict.modCount) {\r
-                                               throw new InvalidOperationException(\r
-                                                       "The Collection's contents changed after this " +\r
-                                                       "enumerator was instantiated.");\r
-                                       }\r
-                               }\r
-                               \r
-                               public object Current\r
-                               {\r
-                                       get {\r
-                                               FailFast();\r
-                                               \r
-                                               if (isAtStart || current == null) {\r
-                                                       throw new InvalidOperationException(\r
-                                                               "Enumerator is positioned before the collection's " +\r
-                                                               "first element or after the last element.");\r
-                                               }\r
-                                               \r
-                                               return isKeyList ? current.key : current.value;\r
-                                       }\r
-                               }\r
-                               \r
-                               public bool MoveNext()\r
-                               {\r
-                                       FailFast();\r
-                                       \r
-                                       if (isAtStart) {\r
-                                               current = dict.root;\r
-                                               isAtStart = false;\r
-                                       } else {\r
-                                               current = current.next;\r
-                                       }\r
-                                       \r
-                                       return current != null ? true : false;\r
-                               }\r
-                               \r
-                               public void Reset()\r
-                               {\r
-                                       FailFast();\r
-                                       isAtStart = true;\r
-                                       current = null;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-}\r
+using System;
+using System.Runtime.Serialization;
+
+namespace System.Collections.Specialized
+{
+       [Serializable]
+       public class ListDictionary : IDictionary, ICollection, IEnumerable {
+               private int count;
+               private int version;
+               private DictionaryNode head;
+               private IComparer comparer;
+
+               public ListDictionary ()
+               {
+                       count = 0;
+                       version = 0;
+                       comparer = null;
+                       head = null;
+               }
+
+               public ListDictionary (IComparer comparer) : this ()
+               {
+                       this.comparer = comparer;
+               }
+
+               private DictionaryNode FindEntry (object key)
+               {
+                       if (key == null)
+                               throw new ArgumentNullException ("key", "Attempted lookup for a null key.");
+
+                       DictionaryNode entry = head;
+                       DictionaryNode prev = null;
+                       if (comparer == null) {
+                               while (entry != null) {
+                                       if (key.Equals (entry.key))
+                                               break;
+                                       prev = entry;
+                                       entry = entry.next;
+                               }
+                       } else {
+                               while (entry != null) {
+                                       if (comparer.Compare (key, entry.key) == 0)
+                                               break;
+                                       prev = entry;
+                                       entry = entry.next;
+                               }
+                       }
+                       return entry;
+               }
+               private DictionaryNode FindEntry (object key, out DictionaryNode prev)
+               {
+                       if (key == null)
+                               throw new ArgumentNullException ("key", "Attempted lookup for a null key.");
+
+                       DictionaryNode entry = head;
+                       prev = null;
+                       if (comparer == null) {
+                               while (entry != null) {
+                                       if (key.Equals (entry.key))
+                                               break;
+                                       prev = entry;
+                                       entry = entry.next;
+                               }
+                       } else {
+                               while (entry != null) {
+                                       if (comparer.Compare (key, entry.key) == 0)
+                                               break;
+                                       prev = entry;
+                                       entry = entry.next;
+                               }
+                       }
+                       return entry;
+               }
+
+               private void AddImpl (object key, object value, DictionaryNode prev)
+               {
+                       //
+                       // Code in the MCS compiler (doc.cs) appears to depend on the new entry being
+                       // added at the end, even though we don't promise any such thing.
+                       // Preferably, this code would just have been:
+                       //
+                       //   head = new DictionaryNode (key, value, head);
+                       //
+                       if (prev == null)
+                               head = new DictionaryNode (key, value, head);
+                       else
+                               prev.next = new DictionaryNode (key, value, prev.next);
+                       ++count;
+                       ++version;
+               }
+
+               // IEnumerable Interface
+               IEnumerator IEnumerable.GetEnumerator ()
+               {
+                       return new DictionaryNodeEnumerator (this);
+               }
+
+               // ICollection Interface
+               public int Count {
+                       get { return count; }
+               }
+
+               public bool IsSynchronized {
+                       get { return false; }
+               }
+
+               public object SyncRoot {
+                       get { return this; }
+               }
+
+               public void CopyTo (Array array, int index)
+               {
+                       if (array == null)
+                               throw new ArgumentNullException ("array", "Array cannot be null.");
+                       if (index < 0)
+                               throw new ArgumentOutOfRangeException ("index", "index is less than 0");
+                       if (index > array.Length)
+                               throw new IndexOutOfRangeException ("index is too large");
+                       if (Count > array.Length - index)
+                               throw new ArgumentException ("Not enough room in the array");
+
+                       foreach (DictionaryEntry entry in this)
+                               array.SetValue (entry, index++);
+               }
+
+               // IDictionary Interface
+               public bool IsFixedSize {
+                       get { return false; }
+               }
+
+               public bool IsReadOnly {
+                       get { return false; }
+               }
+
+               // Indexer
+               public object this [object key] {
+                       get {
+                               DictionaryNode entry = FindEntry (key);
+                               return entry == null ? null : entry.value;
+                       }
+
+                       set {
+                               DictionaryNode prev;
+                               DictionaryNode entry = FindEntry (key, out prev);
+                               if (entry != null)
+                                       entry.value = value;
+                               else
+                                       AddImpl (key, value, prev);
+                       }
+               }
+
+               public ICollection Keys {
+                       get { return new DictionaryNodeCollection (this, true); }
+               }
+
+               public ICollection Values {
+                       get { return new DictionaryNodeCollection (this, false); }
+               }
+
+               public void Add (object key, object value)
+               {
+                       DictionaryNode prev;
+                       DictionaryNode entry = FindEntry (key, out prev);
+                       if (entry != null)
+                               throw new ArgumentException ("key", "Duplicate key in add.");
+
+                       AddImpl (key, value, prev);
+               }
+
+               public void Clear ()
+               {
+                       head = null;
+                       count = 0;
+                       version++;
+               }
+
+               public bool Contains (object key)
+               {
+                       return FindEntry (key) != null;
+               }
+
+               public IDictionaryEnumerator GetEnumerator ()
+               {
+                       return new DictionaryNodeEnumerator (this);
+               }
+
+               public void Remove (object key)
+               {
+                       DictionaryNode prev;
+                       DictionaryNode entry = FindEntry (key, out prev);
+                       if (entry == null)
+                               return;
+                       if (prev == null)
+                               head = entry.next;
+                       else
+                               prev.next = entry.next;
+                       entry.value = null;
+                       count--;
+                       version++;
+               }
+
+
+               [Serializable]
+               private class DictionaryNode {
+                       public object key;
+                       public object value;
+                       public DictionaryNode next;
+                       public DictionaryNode (object key, object value, DictionaryNode next)
+                       {
+                               this.key = key;
+                               this.value = value;
+                               this.next = next;
+                       }
+               }
+
+               private class DictionaryNodeEnumerator : IEnumerator, IDictionaryEnumerator {
+                       private ListDictionary dict;
+                       private bool isAtStart;
+                       private DictionaryNode current;
+                       private int version;
+
+                       public DictionaryNodeEnumerator (ListDictionary dict)
+                       {
+                               this.dict = dict;
+                               version = dict.version;
+                               Reset();
+                       }
+
+                       private void FailFast()
+                       {
+                               if (version != dict.version) {
+                                       throw new InvalidOperationException (
+                                               "The ListDictionary's contents changed after this enumerator was instantiated.");
+                               }
+                       }
+
+                       public bool MoveNext ()
+                       {
+                               FailFast ();
+                               if (current == null && !isAtStart)
+                                       return false;
+                               current = isAtStart ? dict.head : current.next;
+                               isAtStart = false;
+                               return current != null;
+                       }
+
+                       public void Reset ()
+                       {
+                               FailFast ();
+                               isAtStart = true;
+                               current = null;
+                       }
+
+                       public object Current {
+                               get { return Entry; }
+                       }
+
+                       private DictionaryNode DictionaryNode {
+                               get {
+                                       FailFast ();
+                                       if (current == null)
+                                               throw new InvalidOperationException (
+                                                       "Enumerator is positioned before the collection's first element or after the last element.");
+                                       return current;
+                               }
+                       }
+
+                       // IDictionaryEnumerator
+                       public DictionaryEntry Entry {
+                               get {
+                                       object key = DictionaryNode.key;
+                                       return new DictionaryEntry (key, current.value);
+                               }
+                       }
+
+                       public object Key {
+                               get { return DictionaryNode.key; }
+                       }
+
+                       public object Value {
+                               get { return DictionaryNode.value; }
+                       }
+               }
+
+               private class DictionaryNodeCollection : ICollection {
+                       private ListDictionary dict;
+                       private bool isKeyList;
+
+                       public DictionaryNodeCollection (ListDictionary dict, bool isKeyList)
+                       {
+                               this.dict = dict;
+                               this.isKeyList = isKeyList;
+                       }
+
+                       // ICollection Interface
+                       public int Count {
+                               get { return dict.Count; }
+                       }
+
+                       public bool IsSynchronized {
+                               get { return false; }
+                       }
+
+                       public object SyncRoot {
+                               get { return dict.SyncRoot; }
+                       }
+
+                       public void CopyTo (Array array, int index)
+                       {
+                               if (array == null)
+                                       throw new ArgumentNullException ("array", "Array cannot be null.");
+                               if (index < 0)
+                                       throw new ArgumentOutOfRangeException ("index", "index is less than 0");
+                               if (index > array.Length)
+                                       throw new IndexOutOfRangeException ("index is too large");
+                               if (Count > array.Length - index)
+                                       throw new ArgumentException ("Not enough room in the array");
+
+                               foreach (object obj in this)
+                                       array.SetValue (obj, index++);
+                       }
+
+                       // IEnumerable Interface
+                       public IEnumerator GetEnumerator()
+                       {
+                               return new DictionaryNodeCollectionEnumerator (dict.GetEnumerator (), isKeyList);
+                       }
+
+                       private class DictionaryNodeCollectionEnumerator : IEnumerator {
+                               private IDictionaryEnumerator inner;
+                               private bool isKeyList;
+
+                               public DictionaryNodeCollectionEnumerator (IDictionaryEnumerator inner, bool isKeyList)
+                               {
+                                       this.inner = inner;
+                                       this.isKeyList = isKeyList;
+                               }
+
+                               public object Current {
+                                       get { return isKeyList ? inner.Key : inner.Value; }
+                               }
+
+                               public bool MoveNext ()
+                               {
+                                       return inner.MoveNext ();
+                               }
+
+                               public void Reset ()
+                               {
+                                       inner.Reset ();
+                               }
+                       }
+               }
+       }
+}