2009-08-20 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)\r
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;\r
42                 SerializationInfo serializationInfo;\r
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                 \r
58                 public OrderedDictionary (IEqualityComparer equalityComparer)\r
59                 {\r
60                         list = new ArrayList ();\r
61                         hash = new Hashtable (equalityComparer);\r
62                         comparer = equalityComparer;\r
63                 }\r
64 \r
65                 public OrderedDictionary (int capacity, IEqualityComparer equalityComparer)\r
66                 {\r
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                 }\r
72 \r
73                 protected OrderedDictionary (SerializationInfo info, StreamingContext context)\r
74                 {\r
75                         serializationInfo = info;\r
76                 }\r
77 \r
78                 protected virtual void OnDeserialization (object sender)\r
79                 {\r
80                         ((IDeserializationCallback) this).OnDeserialization (sender);\r
81                 }\r
82 \r
83                 void IDeserializationCallback.OnDeserialization (object sender)\r
84                 {\r
85                         if (serializationInfo == null)\r
86                                 return;\r
87 \r
88                         comparer = (IEqualityComparer) serializationInfo.GetValue ("KeyComparer", typeof (IEqualityComparer));\r
89                         readOnly = serializationInfo.GetBoolean ("ReadOnly");\r
90                         initialCapacity = serializationInfo.GetInt32 ("InitialCapacity");\r
91 \r
92                         if (list == null)\r
93                                 list = new ArrayList ();\r
94                         else\r
95                                 list.Clear ();\r
96 \r
97                         hash = new Hashtable (comparer);\r
98                         object[] array = (object[]) serializationInfo.GetValue ("ArrayList", typeof(object[]));\r
99                         foreach (DictionaryEntry de in array) {\r
100                                 hash.Add (de.Key, de.Value);\r
101                                 list.Add (de);\r
102                         }\r
103                 }\r
104                 \r
105                 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)\r
106                 {\r
107                         if (info == null)\r
108                                 throw new ArgumentNullException ("info");\r
109 \r
110                         info.AddValue ("KeyComparer", comparer, typeof (IEqualityComparer));\r
111                         info.AddValue ("ReadOnly", readOnly);\r
112                         info.AddValue ("InitialCapacity", initialCapacity);\r
113 \r
114                         object[] array = new object [hash.Count];\r
115                         hash.CopyTo (array, 0);\r
116                         info.AddValue ("ArrayList", array);\r
117                 }\r
118 \r
119                 IEnumerator IEnumerable.GetEnumerator()\r
120                 {\r
121                         return list.GetEnumerator ();\r
122                 }\r
123                 \r
124                 public int Count {\r
125                         get {\r
126                                 return list.Count;\r
127                         }\r
128                 }\r
129 \r
130                 bool ICollection.IsSynchronized {\r
131                         get {\r
132                                 return list.IsSynchronized;\r
133                         }\r
134                 }\r
135 \r
136                 object ICollection.SyncRoot {\r
137                         get {\r
138                                 return list.SyncRoot;\r
139                         }\r
140                 }\r
141 \r
142                 public void CopyTo (Array array, int index)\r
143                 {\r
144                         list.CopyTo (array, index);\r
145                 }\r
146 \r
147                 bool IDictionary.IsFixedSize {\r
148                         get {\r
149                                 return false;\r
150                         }\r
151                 }\r
152                 \r
153                 public bool IsReadOnly\r
154                 {\r
155                         get {\r
156                                 return readOnly;\r
157                         }\r
158                 }\r
159                 \r
160                 public object this [object key]\r
161                 {\r
162                         get { return hash [key]; }\r
163                         set {\r
164                                 WriteCheck ();\r
165                                 if (hash.Contains (key)) {\r
166                                         int i = FindListEntry (key);\r
167                                         list [i] = new DictionaryEntry (key, value);\r
168                                 } else\r
169                                         list.Add (new DictionaryEntry (key, value));\r
170                                 \r
171                                 hash [key] = value;\r
172                         }\r
173                 }\r
174                 \r
175                 public object this [int index]\r
176                 {\r
177                         get { return ((DictionaryEntry) list [index]).Value; }\r
178                         set {\r
179                                 WriteCheck ();\r
180                                 DictionaryEntry de = (DictionaryEntry) list [index];\r
181                                 de.Value = value;\r
182                                 // update (even on the list) isn't automatic\r
183                                 list [index] = de;\r
184                                 hash [de.Key] = value;\r
185                         }\r
186                 }\r
187                 \r
188                 public ICollection Keys\r
189                 {\r
190                         get {\r
191                                 return new OrderedCollection (list, true);\r
192                         }\r
193                 }\r
194                 \r
195                 public ICollection Values\r
196                 {\r
197                         get {\r
198                                 return new OrderedCollection (list, false);\r
199                         }\r
200                 }\r
201 \r
202                 public void Add (object key, object value)\r
203                 {\r
204                         WriteCheck ();\r
205                         hash.Add (key, value);\r
206                         list.Add (new DictionaryEntry (key, value));\r
207                 }\r
208                 \r
209                 public void Clear()\r
210                 {\r
211                         WriteCheck ();\r
212                         hash.Clear ();\r
213                         list.Clear ();\r
214                 }\r
215                 \r
216                 public bool Contains (object key)\r
217                 {\r
218                         return hash.Contains (key);\r
219                 }\r
220                 \r
221                 public virtual IDictionaryEnumerator GetEnumerator()\r
222                 {\r
223                         return new OrderedEntryCollectionEnumerator (list.GetEnumerator ());\r
224                 }\r
225                 \r
226                 public void Remove (object key)\r
227                 {\r
228                         WriteCheck ();\r
229 \r
230                         if (hash.Contains (key)) {\r
231                                 hash.Remove (key);\r
232                                 int i = FindListEntry (key);\r
233                                 list.RemoveAt (i);\r
234                         }\r
235                 }\r
236                 \r
237                 int FindListEntry (object key)\r
238                 {\r
239                         for (int n=0; n<list.Count; n++) {\r
240                                 DictionaryEntry de = (DictionaryEntry) list [n];\r
241                                 if (comparer != null ? comparer.Equals(de.Key, key) : de.Key.Equals(key))\r
242                                         return n;\r
243                         }\r
244                         return -1;\r
245                 }\r
246                 \r
247                 void WriteCheck ()\r
248                 {\r
249                         if (readOnly)\r
250                                 throw new NotSupportedException ("Collection is read only");\r
251                 }\r
252                 \r
253                 public OrderedDictionary AsReadOnly ()\r
254                 {\r
255                         OrderedDictionary od = new OrderedDictionary ();\r
256                         od.list = list;\r
257                         od.hash = hash;\r
258                         od.comparer = comparer;\r
259                         od.readOnly = true;\r
260                         return od;\r
261                 }\r
262                 \r
263                 public void Insert (int index, object key, object value)\r
264                 {\r
265                         WriteCheck ();\r
266                         hash.Add (key, value);\r
267                         list.Insert (index, new DictionaryEntry (key, value));\r
268                 }\r
269                 \r
270                 public void RemoveAt (int index)\r
271                 {\r
272                         WriteCheck ();\r
273                         DictionaryEntry entry = (DictionaryEntry) list [index];\r
274                         list.RemoveAt (index);\r
275                         hash.Remove (entry.Key);\r
276                 }\r
277                 \r
278                 private class OrderedEntryCollectionEnumerator : IEnumerator, IDictionaryEnumerator\r
279                 {\r
280                         IEnumerator listEnumerator;\r
281                         \r
282                         public OrderedEntryCollectionEnumerator (IEnumerator listEnumerator)\r
283                         {\r
284                                 this.listEnumerator = listEnumerator;\r
285                         }\r
286 \r
287                         public bool MoveNext()\r
288                         {\r
289                                 return listEnumerator.MoveNext ();\r
290                         }\r
291                         \r
292                         public void Reset()\r
293                         {\r
294                                 listEnumerator.Reset ();\r
295                         }\r
296                         \r
297                         public object Current\r
298                         {\r
299                                 get { return listEnumerator.Current; }\r
300                         }\r
301                         \r
302                         public DictionaryEntry Entry\r
303                         {\r
304                                 get { return (DictionaryEntry) listEnumerator.Current; }\r
305                         }\r
306                         \r
307                         public object Key\r
308                         {\r
309                                 get { return Entry.Key; }\r
310                         }\r
311                         \r
312                         public object Value\r
313                         {\r
314                                 get { return Entry.Value; }\r
315                         }\r
316                 }\r
317                 \r
318                 private class OrderedCollection : ICollection\r
319                 {\r
320                         private ArrayList list;\r
321                         private bool isKeyList;\r
322                                 \r
323                         public OrderedCollection (ArrayList list, bool isKeyList)\r
324                         {\r
325                                 this.list = list;\r
326                                 this.isKeyList = isKeyList;\r
327                         }\r
328 \r
329                         public int Count {\r
330                                 get {\r
331                                         return list.Count;\r
332                                 }\r
333                         }\r
334                         \r
335                         public bool IsSynchronized\r
336                         {\r
337                                 get {\r
338                                         return false;\r
339                                 }\r
340                         }\r
341                         \r
342                         public object SyncRoot\r
343                         {\r
344                                 get {\r
345                                         return list.SyncRoot;\r
346                                 }\r
347                         }\r
348 \r
349                         public void CopyTo (Array array, int index)\r
350                         {\r
351                                 for (int n=0; n<list.Count; n++) {\r
352                                         DictionaryEntry de = (DictionaryEntry) list [n];\r
353                                         if (isKeyList) array.SetValue (de.Key, index + n);\r
354                                         else array.SetValue (de.Value, index + n);\r
355                                 }\r
356                         }\r
357                         \r
358                         public IEnumerator GetEnumerator()\r
359                         {\r
360                                 return new OrderedCollectionEnumerator (list.GetEnumerator (), isKeyList);\r
361                         }\r
362                         \r
363                         private class OrderedCollectionEnumerator : IEnumerator\r
364                         {\r
365                                 private bool isKeyList;\r
366                                 IEnumerator listEnumerator;\r
367                                         \r
368                                 public OrderedCollectionEnumerator (IEnumerator listEnumerator, bool isKeyList)\r
369                                 {\r
370                                         this.listEnumerator = listEnumerator;\r
371                                         this.isKeyList = isKeyList;\r
372                                 }\r
373 \r
374                                 public object Current\r
375                                 {\r
376                                         get {\r
377                                                 DictionaryEntry entry = (DictionaryEntry) listEnumerator.Current;\r
378                                                 return isKeyList ? entry.Key : entry.Value;\r
379                                         }\r
380                                 }\r
381                                 \r
382                                 public bool MoveNext()\r
383                                 {\r
384                                         return listEnumerator.MoveNext ();\r
385                                 }\r
386                                 \r
387                                 public void Reset()\r
388                                 {\r
389                                         listEnumerator.Reset ();\r
390                                 }\r
391                         }\r
392                 }\r
393         }\r
394 }\r
395 \r
396 #endif\r