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