2005-06-05 Peter Bartok <pbartok@novell.com>
[mono.git] / mcs / class / Microsoft.VisualBasic / Microsoft.VisualBasic / Collection.cs
1 //
2 // Collection.cs
3 //
4 // Author:
5 //   Chris J Breisch (cjbreisch@altavista.net) 
6 //
7 // (C) 2002 Chris J Breisch
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32 using System;
33 using System.Runtime.InteropServices;
34 using System.Collections;
35 using System.ComponentModel;
36 using Microsoft.VisualBasic.CompilerServices;
37
38
39 namespace Microsoft.VisualBasic {
40         sealed public class Collection : ICollection, IList {
41         //
42         // <summary>
43         //              Collection : The BASIC Collection Object
44         //      </summary>
45         //
46         //      <remarks>
47         //      </remarks>
48                 // Declarations
49                 private Hashtable m_Hashtable = new Hashtable();
50                 private ArrayList m_HashIndexers = new ArrayList();
51                 internal bool Modified = false;
52
53                 private class ColEnumerator: IEnumerator 
54                 //
55                 // <summary>
56                 //              ColEnumerator : This internal class is used
57                 //              for enumerating through our Collection
58                 //      </summary>
59                 //
60                 //      <remarks>
61                 //      </remarks>
62                 {
63                         private int Index;
64                         private Collection Col;
65                         private object Item;
66
67                         public ColEnumerator(Collection coll) 
68                         {
69                                 Col = coll;
70                                 Index = 0;
71                                 Col.Modified = false;
72                         }
73
74                         public void Reset() 
75                         {
76                                 if (Col.Modified) 
77                                 {
78                                         // FIXME : spec says throw exception, MS doesn't
79                                         // throw new InvalidOperationException();
80                                 }
81                                 Index = 0;
82                         }
83
84                         public bool MoveNext() 
85                         {
86                                 if (Col.Modified) 
87                                 {
88                                         // FIXME : spec says throw exception, MS doesn't
89                                         // throw new InvalidOperationException();
90                                 }
91                                 Index++;
92                                 try {
93                                         Item = Col[Index];
94                                 }
95                                 catch {
96                                         // do nothing
97                                 }
98
99                                 return Index <= Col.Count;
100                         }
101
102                         public object Current {
103                                 get {
104                                         if (Index == 0) {
105                                                 // FIXME : spec says throw InvalidOperation, 
106                                                 // but MS throws IndexOutOfRange
107                                                 throw new IndexOutOfRangeException();
108                                                 // throw new InvalidOperationException();
109                                         }
110                                         else {
111                                                 return Item;
112                                         }
113                                 }
114                         }
115
116                         // The current property on the IEnumerator interface:
117                         object IEnumerator.Current {
118                                 get {
119                                         return(Current);
120                                 }
121                         }
122                 }
123                 // Constructors
124                 // Properties
125                 System.Boolean IList.IsReadOnly {
126                         get {return false;}
127                 }
128
129                 System.Boolean ICollection.IsSynchronized {
130                         get {return m_Hashtable.IsSynchronized;}
131                 }
132
133                 System.Object ICollection.SyncRoot {
134                         get {return m_Hashtable.SyncRoot;}
135                 }
136
137                 System.Boolean IList.IsFixedSize { 
138                         get {return false;} 
139                 }
140
141                 public System.Int32 Count {
142                         get {return m_HashIndexers.Count;} 
143                 }
144
145                 [ReadOnly(true)]
146                 [System.Runtime.CompilerServices.IndexerName("Item")] 
147                 public System.Object this [System.Int32 Index] {
148                         get {
149                                 try {
150                                         // Collections are 1-based
151                                         return m_Hashtable[m_HashIndexers[Index-1]];
152                                 }
153                                 catch {
154                                         throw new IndexOutOfRangeException();
155                                 }
156                         }
157                         set {throw new NotImplementedException();} 
158                 }
159
160                 [System.Runtime.CompilerServices.IndexerName("Item")] 
161                 public System.Object this [System.Object Index] 
162                 {
163                         get     {
164                                 if (Index is string) {
165                                         if (m_HashIndexers.IndexOf(Index) < 0) {
166                                                 //      throw new IndexOutOfRangeException();
167                                                 // FIXME : Spec Says IndexOutOfRange...MS throws Argument
168                                                 throw new ArgumentException();
169                                         }
170                                         return m_Hashtable[Index];
171                                 } 
172                                 else {
173                                         throw new ArgumentException();
174                                 }
175                         }
176                 }
177
178                 // Methods
179                 System.Int32 IList.IndexOf (System.Object value) 
180                 { 
181                         int LastPos = 0;
182                         bool Found = false;
183
184                         while (!Found) {
185                                 LastPos = m_HashIndexers.IndexOf(value.GetHashCode(), LastPos);
186                                 if (LastPos == -1) {
187                                         Found = true;
188                                 } else if (m_Hashtable[m_HashIndexers[LastPos]] == value) {
189                                         Found = true;
190                                 }
191                         }
192                         return LastPos;
193                 }
194
195                 System.Boolean IList.Contains (System.Object value) 
196                 { 
197                         return m_Hashtable.ContainsValue(value);
198                 }
199
200                 void IList.Clear () 
201                 {
202                         m_Hashtable.Clear();
203                         m_HashIndexers.Clear();
204                 }
205
206                 public void Remove (System.String Key) 
207                 { 
208                         int Index;
209                         
210                         if (Key == null) {
211                                 throw new ArgumentNullException();
212                         }
213                         try {
214                                 Index = m_HashIndexers.IndexOf(Key) + 1;
215                                 Remove(Index);
216                         }
217                         catch {
218                                 throw new ArgumentException();
219                         }
220                 }
221
222                 public void Remove (System.Int32 Index)
223                 { 
224                         try {
225                                 // Collections are 1-based
226                                 m_Hashtable.Remove(m_HashIndexers[Index-1]);
227                                 m_HashIndexers.RemoveAt(Index-1);
228                                 Modified = true;
229                         } 
230                         catch {
231                                 throw new IndexOutOfRangeException();
232                         }
233                 }
234
235                 void IList.Remove (System.Object value) 
236                 {
237                         if (value == null) {
238                                 throw new ArgumentNullException();
239                         }
240                         if (!(value is string)) {
241                                 throw new ArgumentException();
242                         }
243                         Remove((string)value);
244                 }
245
246                 void IList.RemoveAt (System.Int32 index) 
247                 {
248                         Remove(index);
249                 }
250
251                 void IList.Insert (System.Int32 index, System.Object value) 
252                 {
253                         Insert(index, value, value.GetHashCode().ToString());
254                 }
255
256                 void Insert(System.Int32 index, System.Object value, string Key)
257                 {
258                         m_HashIndexers.Insert(index -1, Key);
259                         m_Hashtable.Add(Key, value);
260                         Modified = true;
261                 }
262
263                 System.Int32 IList.Add (System.Object Item) 
264                 {
265                         return Add(Item, Item.GetHashCode().ToString());
266                 }
267
268                 System.Int32 Add(System.Object Item, string Key)
269                 {
270                         m_Hashtable.Add(Key, Item);
271                         Modified = true;
272
273                         return m_HashIndexers.Add(Key);
274                 }
275
276                 private int GetIndexPosition(System.Object Item) 
277                 {
278                         int Position = int.MinValue;
279
280                         if (Item is string) {
281                                 Position = m_HashIndexers.IndexOf(Item) + 1;
282                         } 
283                         else if (Item is int) {
284                                 Position = Convert.ToInt32(Item);
285                         }
286                         else {
287                                 throw new InvalidCastException();
288                         }
289                         if (Position < 0) {
290                                 throw new ArgumentException();
291                         }
292
293                         //Position must be from 1 to value of collections Count 
294                         if (Position > m_HashIndexers.Count) {
295                                 throw new ArgumentOutOfRangeException();
296                         }
297  
298                         return Position;
299                 }
300
301                 public void Add (System.Object Item, 
302                         [Optional, __DefaultArgumentValue(null)] String Key, 
303                         [Optional, __DefaultArgumentValue(null)] System.Object Before, 
304                         [Optional, __DefaultArgumentValue(null)] System.Object After)
305                 {
306                         int Position = int.MinValue;
307                         
308                         // check for valid args
309                         if (Before != null && After != null) {
310                                 throw new ArgumentException();
311                         }
312                         if (Key != null && m_HashIndexers.IndexOf(Key) != -1) {
313                                 throw new ArgumentException();
314                         }
315                         if (Before != null) {
316                                 // Looks like its an implementation bug in .NET
317                                 // Not very satisfied with the fix, but did it
318                                 // just to bring the similar behaviour on mono
319                                 // as well.
320                                 if (Before is int) {
321                                         Position = Convert.ToInt32(Before);
322                                         if (Position !=  (m_HashIndexers.Count + 1)) 
323                                                 Position = GetIndexPosition(Before);                            
324                                 }
325                                 else
326                                         Position = GetIndexPosition(Before);
327                         }
328                         if (After != null) {
329                                 Position = GetIndexPosition(After) + 1;
330                         }
331                         if (Key == null) {
332                                 Key = (Item.GetHashCode() + m_HashIndexers.Count).ToString();
333                         }
334
335                         if (Position > (m_HashIndexers.Count+1) || Position == int.MinValue) {
336                                 Add(Item, Key);
337                         } 
338                         else {
339                                 Insert(Position, Item, Key);
340                         }
341                 }
342
343                 void ICollection.CopyTo (System.Array array, System.Int32 index) 
344                 {
345                         System.Array NewArray = 
346                                 Array.CreateInstance(typeof(System.Object), 
347                                         m_HashIndexers.Count - index);
348                         
349                         // Collections are 1-based
350                         for (int i = index -1; i < m_HashIndexers.Count; i++) {
351                                 NewArray.SetValue(m_Hashtable[m_HashIndexers[i]], i - index);
352                         }
353                 }
354                 
355                 public IEnumerator GetEnumerator () 
356                 {
357                         return new ColEnumerator(this);
358                 }
359         }
360 }