2005-11-30 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System / System.Collections.Specialized / OrderedDictionary.cs
1 //\r
2 // System.Web.UI.WebControls.OrderedDictionary.cs\r
3 //\r
4 // Authors:\r
5 //      Lluis Sanchez Gual (lluis@novell.com)\r
6 //\r
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
8 //\r
9 // Permission is hereby granted, free of charge, to any person obtaining\r
10 // a copy of this software and associated documentation files (the\r
11 // "Software"), to deal in the Software without restriction, including\r
12 // without limitation the rights to use, copy, modify, merge, publish,\r
13 // distribute, sublicense, and/or sell copies of the Software, and to\r
14 // permit persons to whom the Software is furnished to do so, subject to\r
15 // the following conditions:\r
16 // \r
17 // The above copyright notice and this permission notice shall be\r
18 // included in all copies or substantial portions of the Software.\r
19 // \r
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
27 //\r
28 \r
29 #if NET_2_0\r
30 \r
31 using System.Runtime.Serialization;\r
32 \r
33 namespace System.Collections.Specialized\r
34 {\r
35         [Serializable]\r
36         public class OrderedDictionary : IOrderedDictionary, IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback\r
37         {\r
38                 ArrayList list;\r
39                 Hashtable hash;\r
40                 bool readOnly;\r
41                 int initialCapacity;
42                 SerializationInfo serializationInfo;
43                 IEqualityComparer comparer;\r
44                 \r
45                 public OrderedDictionary ()\r
46                 {\r
47                         list = new ArrayList ();\r
48                         hash = new Hashtable ();\r
49                 }\r
50                 \r
51                 public OrderedDictionary (int capacity)\r
52                 {\r
53                         initialCapacity = (capacity < 0) ? 0 : capacity;\r
54                         list = new ArrayList (initialCapacity);\r
55                         hash = new Hashtable (initialCapacity);\r
56                 }\r
57                 
58                 public OrderedDictionary (IEqualityComparer equalityComparer)
59                 {
60                         list = new ArrayList ();\r
61                         hash = new Hashtable (equalityComparer);
62                         comparer = equalityComparer;\r
63                 }
64
65                 public OrderedDictionary (int capacity, IEqualityComparer equalityComparer)
66                 {
67                         initialCapacity = (capacity < 0) ? 0 : capacity;\r
68                         list = new ArrayList (initialCapacity);\r
69                         hash = new Hashtable (initialCapacity, equalityComparer);\r
70                         comparer = equalityComparer;\r
71                 }
72 \r
73                 protected OrderedDictionary (SerializationInfo info, StreamingContext context)\r
74                 {
75                         serializationInfo = info;\r
76                 }\r
77
78                 protected virtual void OnDeserialization (object sender)
79                 {
80                         if (serializationInfo == null)
81                                 return;
82
83                         comparer = (IEqualityComparer) serializationInfo.GetValue ("KeyComparer", typeof (IEqualityComparer));
84                         readOnly = serializationInfo.GetBoolean ("ReadOnly");\r
85                         initialCapacity = serializationInfo.GetInt32 ("InitialCapacity");
86
87                         if (list == null)\r
88                                 list = new ArrayList ();
89                         else
90                                 list.Clear ();
91
92                         hash = new Hashtable (comparer);
93                         object[] array = (object[]) serializationInfo.GetValue ("ArrayList", typeof(object[]));
94                         foreach (DictionaryEntry de in array) {
95                                 hash.Add (de.Key, de.Value);\r
96                                 list.Add (de);\r
97                         }\r
98                 }\r
99                 \r
100                 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)\r
101                 {
102                         if (info == null)
103                                 throw new ArgumentNullException ("info");
104
105                         info.AddValue ("KeyComparer", comparer, typeof (IEqualityComparer));
106                         info.AddValue ("ReadOnly", readOnly);\r
107                         info.AddValue ("InitialCapacity", initialCapacity);\r
108
109                         object[] array = new object [hash.Count];
110                         hash.CopyTo (array, 0);\r
111                         info.AddValue ("ArrayList", array);\r
112                 }
113
114                 IEnumerator IEnumerable.GetEnumerator()\r
115                 {\r
116                         return list.GetEnumerator ();\r
117                 }\r
118                 \r
119                 public int Count {\r
120                         get {\r
121                                 return list.Count;\r
122                         }\r
123                 }\r
124
125                 bool ICollection.IsSynchronized {
126                         get {
127                                 return list.IsSynchronized;
128                         }
129                 }
130
131                 object ICollection.SyncRoot {
132                         get {
133                                 return list.SyncRoot;
134                         }
135                 }
136 \r
137                 public void CopyTo (Array array, int index)\r
138                 {\r
139                         list.CopyTo (array, index);\r
140                 }\r
141
142                 bool IDictionary.IsFixedSize {
143                         get {
144                                 return false;
145                         }
146                 }
147                 \r
148                 public virtual bool IsReadOnly\r
149                 {\r
150                         get {\r
151                                 return readOnly;\r
152                         }\r
153                 }\r
154                 \r
155                 public virtual object this [object key]\r
156                 {\r
157                         get { return hash [key]; }\r
158                         set {\r
159                                 WriteCheck ();\r
160                                 if (hash.Contains (key)) {\r
161                                         int i = FindListEntry (key);\r
162                                         list [i] = new DictionaryEntry (key, value);\r
163                                 } else\r
164                                         list.Add (new DictionaryEntry (key, value));\r
165                                 \r
166                                 hash [key] = value;\r
167                         }\r
168                 }\r
169                 \r
170                 public virtual object this [int index]\r
171                 {\r
172                         get { return ((DictionaryEntry) list [index]).Value; }\r
173                         set {\r
174                                 WriteCheck ();\r
175                                 DictionaryEntry de = (DictionaryEntry) list [index];\r
176                                 de.Value = value;
177                                 // update (even on the list) isn't automatic
178                                 list [index] = de;
179                                 hash [de.Key] = value;\r
180                         }\r
181                 }\r
182                 \r
183                 public virtual ICollection Keys\r
184                 {\r
185                         get {\r
186                                 return new OrderedCollection (list, true);\r
187                         }\r
188                 }\r
189                 \r
190                 public virtual ICollection Values\r
191                 {\r
192                         get {\r
193                                 return new OrderedCollection (list, false);\r
194                         }\r
195                 }\r
196 \r
197                 public void Add (object key, object value)\r
198                 {\r
199                         WriteCheck ();\r
200                         hash.Add (key, value);\r
201                         list.Add (new DictionaryEntry (key, value));\r
202                 }\r
203                 \r
204                 public void Clear()\r
205                 {\r
206                         WriteCheck ();\r
207                         hash.Clear ();\r
208                         list.Clear ();\r
209                 }\r
210                 \r
211                 public bool Contains (object key)\r
212                 {\r
213                         return hash.Contains (key);\r
214                 }\r
215                 \r
216                 public virtual IDictionaryEnumerator GetEnumerator()\r
217                 {\r
218                         return new OrderedEntryCollectionEnumerator (list.GetEnumerator ());\r
219                 }\r
220                 \r
221                 public void Remove (object key)\r
222                 {\r
223                         WriteCheck ();\r
224 \r
225                         if (hash.Contains (key)) {\r
226                                 hash.Remove (key);\r
227                                 int i = FindListEntry (key);\r
228                                 list.RemoveAt (i);\r
229                         }\r
230                 }\r
231                 \r
232                 int FindListEntry (object key)\r
233                 {\r
234                         for (int n=0; n<list.Count; n++) {\r
235                                 DictionaryEntry de = (DictionaryEntry) list [n];\r
236                                 if (de.Key.Equals (key))\r
237                                         return n;\r
238                         }\r
239                         return -1;\r
240                 }\r
241                 \r
242                 void WriteCheck ()\r
243                 {\r
244                         if (readOnly)\r
245                                 throw new NotSupportedException ("Collection is read only");\r
246                 }\r
247                 \r
248                 public OrderedDictionary AsReadOnly ()\r
249                 {\r
250                         OrderedDictionary od = new OrderedDictionary ();\r
251                         od.list = list;\r
252                         od.hash = hash;\r
253                         od.comparer = comparer;\r
254                         od.readOnly = true;
255                         return od;\r
256                 }\r
257                 \r
258                 public void Insert (int index, object key, object value)\r
259                 {\r
260                         WriteCheck ();\r
261                         hash.Add (key, value);\r
262                         list.Insert (index, new DictionaryEntry (key, value));\r
263                 }\r
264                 \r
265                 public void RemoveAt (int index)\r
266                 {\r
267                         WriteCheck ();\r
268                         DictionaryEntry entry = (DictionaryEntry) list [index];\r
269                         list.RemoveAt (index);\r
270                         hash.Remove (entry.Key);\r
271                 }\r
272                 \r
273                 private class OrderedEntryCollectionEnumerator : IEnumerator, IDictionaryEnumerator\r
274                 {\r
275                         IEnumerator listEnumerator;\r
276                         \r
277                         public OrderedEntryCollectionEnumerator (IEnumerator listEnumerator)\r
278                         {\r
279                                 this.listEnumerator = listEnumerator;\r
280                         }\r
281 \r
282                         public bool MoveNext()\r
283                         {\r
284                                 return listEnumerator.MoveNext ();\r
285                         }\r
286                         \r
287                         public void Reset()\r
288                         {\r
289                                 listEnumerator.Reset ();\r
290                         }\r
291                         \r
292                         public object Current\r
293                         {\r
294                                 get { return listEnumerator.Current; }\r
295                         }\r
296                         \r
297                         public DictionaryEntry Entry\r
298                         {\r
299                                 get { return (DictionaryEntry) listEnumerator.Current; }\r
300                         }\r
301                         \r
302                         public object Key\r
303                         {\r
304                                 get { return Entry.Key; }\r
305                         }\r
306                         \r
307                         public object Value\r
308                         {\r
309                                 get { return Entry.Value; }\r
310                         }\r
311                 }\r
312                 \r
313                 private class OrderedCollection : ICollection\r
314                 {\r
315                         private ArrayList list;\r
316                         private bool isKeyList;\r
317                                 \r
318                         public OrderedCollection (ArrayList list, bool isKeyList)\r
319                         {\r
320                                 this.list = list;\r
321                                 this.isKeyList = isKeyList;\r
322                         }\r
323 \r
324                         public int Count {\r
325                                 get {\r
326                                         return list.Count;\r
327                                 }\r
328                         }\r
329                         \r
330                         public bool IsSynchronized\r
331                         {\r
332                                 get {\r
333                                         return false;\r
334                                 }\r
335                         }\r
336                         \r
337                         public object SyncRoot\r
338                         {\r
339                                 get {\r
340                                         return list.SyncRoot;\r
341                                 }\r
342                         }\r
343 \r
344                         public void CopyTo (Array array, int index)\r
345                         {\r
346                                 for (int n=0; n<list.Count; n++) {\r
347                                         DictionaryEntry de = (DictionaryEntry) list [n];\r
348                                         if (isKeyList) array.SetValue (de.Key, index + n);\r
349                                         else array.SetValue (de.Value, index + n);\r
350                                 }\r
351                         }\r
352                         \r
353                         public IEnumerator GetEnumerator()\r
354                         {\r
355                                 return new OrderedCollectionEnumerator (list.GetEnumerator (), isKeyList);\r
356                         }\r
357                         \r
358                         private class OrderedCollectionEnumerator : IEnumerator\r
359                         {\r
360                                 private bool isKeyList;\r
361                                 IEnumerator listEnumerator;\r
362                                         \r
363                                 public OrderedCollectionEnumerator (IEnumerator listEnumerator, bool isKeyList)\r
364                                 {\r
365                                         this.listEnumerator = listEnumerator;\r
366                                         this.isKeyList = isKeyList;\r
367                                 }\r
368 \r
369                                 public object Current\r
370                                 {\r
371                                         get {\r
372                                                 DictionaryEntry entry = (DictionaryEntry) listEnumerator.Current;\r
373                                                 return isKeyList ? entry.Key : entry.Value;\r
374                                         }\r
375                                 }\r
376                                 \r
377                                 public bool MoveNext()\r
378                                 {\r
379                                         return listEnumerator.MoveNext ();\r
380                                 }\r
381                                 \r
382                                 public void Reset()\r
383                                 {\r
384                                         listEnumerator.Reset ();\r
385                                 }\r
386                         }\r
387                 }\r
388         }\r
389 }\r
390 \r
391 #endif\r