committed patch from Ajay
[mono.git] / mcs / class / corlib / System / Array.cs
1 //
2 // System.Array.cs
3 //
4 // Author:
5 //   Joe Shaw (joe@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.  http://www.ximian.com
8 //
9
10 using System.Collections;
11 using System.Runtime.CompilerServices;
12
13 namespace System
14 {
15
16         [MonoTODO("This should implement IList and IEnumerable too")]
17         public abstract class Array : ICloneable, ICollection
18         {
19                 // Constructor          
20                 protected Array ()
21                 {
22                         /* empty */
23                 }
24                 
25                 // Properties
26                 public int Length 
27                 {
28                         get 
29                         {
30                                 int length = this.GetLength (0);
31
32                                 for (int i = 1; i < this.Rank; i++) {
33                                         length *= this.GetLength (i); 
34                                 }
35                                 
36                                 return length;
37                         }
38                 }
39
40                 public int Rank 
41                 {
42                         get
43                         {
44                                 return this.GetRank ();
45                         }
46                 }
47
48                 // InternalCall Methods
49                 
50                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
51                 public extern int GetRank ();
52
53                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
54                 public extern int GetLength (int dimension);
55
56                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
57                 public extern int GetLowerBound (int dimension);
58
59                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
60                 public extern object GetValue (int[] idxs);
61
62                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
63                 public extern void SetValue (object value, int[] idxs);
64                 
65                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
66                 internal extern static Array CreateInstanceImpl(Type elementType, int[] lengths, int [] bounds);
67
68                 // Properties
69                 public virtual int Count {
70                         get {
71                                 return Length;
72                         }
73                 }
74
75                 [MonoTODO]
76                 public virtual bool IsSynchronized {
77                         get {
78                                 // FIXME?
79                                 return false;
80                         }
81                 }
82
83                 [MonoTODO]
84                 public virtual object SyncRoot {
85                         get {
86                                 // FIXME
87                                 return null;
88                         }
89                 }
90
91                 public virtual bool IsFixedSize 
92                 {
93                         get {
94                                 return true;
95                         }
96                 }
97
98                 public virtual bool IsReadOnly 
99                 {
100                         get{
101                                 return false;
102                         }
103                 }
104
105                 [MonoTODO]
106                 public virtual IEnumerator GetEnumerator ()
107                 {
108                         // FIXME
109                         return null;
110                 }
111
112                 public int GetUpperBound (int dimension)
113                 {
114                         return GetLowerBound (dimension) +
115                                 GetLength (dimension) - 1;
116                 }
117
118                 public object GetValue (int idx)
119                 {
120                         int[] ind = new int [1];
121
122                         ind [0] = idx;
123
124                         return GetValue (ind);
125                 }
126
127                 public object GetValue (int idx1, int idx2)
128                 {
129                         int[] ind = new int [2];
130
131                         ind [0] = idx1;
132                         ind [1] = idx2;
133
134                         return GetValue (ind);
135                 }
136
137                 public object GetValue (int idx1, int idx2, int idx3)
138                 {
139                         int[] ind = new int [3];
140
141                         ind [0] = idx1;
142                         ind [1] = idx2;
143                         ind [2] = idx3;
144
145                         return GetValue (ind);
146                 }
147
148                 public void SetValue (object value, int idx)
149                 {
150                         int[] ind = new int [1];
151
152                         ind [0] = idx;
153
154                         SetValue (value, ind);
155                 }
156                 
157                 public void SetValue (object value, int idx1, int idx2)
158                 {
159                         int[] ind = new int [2];
160
161                         ind [0] = idx1;
162                         ind [1] = idx2;
163
164                         SetValue (value, ind);
165                 }
166
167                 public void SetValue (object value, int idx1, int idx2, int idx3)
168                 {
169                         int[] ind = new int [3];
170
171                         ind [0] = idx1;
172                         ind [1] = idx2;
173                         ind [2] = idx3;
174
175                         SetValue (value, ind);
176                 }
177
178                 public static Array CreateInstance(Type elementType, int length)
179                 {
180                         int[] lengths = new int [1];
181                         int[] bounds = null;
182                         
183                         lengths [0] = length;
184                         
185                         return CreateInstanceImpl (elementType, lengths, bounds);
186                 }
187                 
188                 public static Array CreateInstance(Type elementType, int l1, int l2)
189                 {
190                         int[] lengths = new int [2];
191                         int[] bounds = null;
192                         
193                         lengths [0] = l1;
194                         lengths [1] = l2;
195                         
196                         return CreateInstanceImpl (elementType, lengths, bounds);
197                 }
198
199                 public static Array CreateInstance(Type elementType, int l1, int l2, int l3)
200                 {
201                         int[] lengths = new int [3];
202                         int[] bounds = null;
203                         
204                         lengths [0] = l1;
205                         lengths [1] = l2;
206                         lengths [2] = l3;
207                 
208                         return CreateInstanceImpl (elementType, lengths, bounds);
209                 }
210
211                 public static Array CreateInstance(Type elementType, int[] lengths)
212                 {
213                         int[] bounds = null;
214                         
215                         return CreateInstanceImpl (elementType, lengths, bounds);
216                 }
217
218                 public static Array CreateInstance(Type elementType, int[] lengths, int [] bounds)
219                 {
220                         if(bounds == null)
221                                 throw new ArgumentNullException("bounds");
222
223                         return CreateInstanceImpl (elementType, lengths, bounds);
224                 }
225
226                 
227                 public static int BinarySearch (Array array, object value)
228                 {
229                         return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
230                                              value, null);
231                 }
232
233                 public static int BinarySearch (Array array, object value, IComparer comparer)
234                 {
235                         return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
236                                              value, comparer);
237                 }
238
239                 public static int BinarySearch (Array array, int index, int length, object value)
240                 {
241                         return BinarySearch (array, index, length, value, null);
242                 }
243
244                 public static int BinarySearch (Array array, int index,
245                                                 int length, object value,
246                                                 IComparer comparer)
247                 {
248                         if (array == null)
249                                 throw new ArgumentNullException ();
250
251                         if (array.Rank > 1)
252                                 throw new RankException ();
253
254                         if (index < array.GetLowerBound (0) || length < 0)
255                                 throw new ArgumentOutOfRangeException ();
256
257                         if (index + length > array.GetUpperBound (0) + 1)
258                                 throw new ArgumentException ();
259
260                         if (comparer == null && !(value is IComparable))
261                                 throw new ArgumentException ();
262
263                         // FIXME: Throw an ArgumentException if comparer
264                         // is null and value is not of the same type as the
265                         // elements of array.
266
267                         // FIXME: This is implementing linear search. While it should do a binary one
268                         // FIXME: Should not throw exception when values are null 
269
270                         for (int i = 0; i < length; i++) 
271                         {
272                                 int result;
273
274                                 if (comparer == null && !(array.GetValue(index + i) is IComparable))
275                                         throw new ArgumentException ();
276
277                                 if (comparer == null)
278                                         result = (value as IComparable).CompareTo(array.GetValue(index + i));
279                                 else
280                                         result = comparer.Compare(value, array.GetValue(index + i));
281
282                                 if (result == 0)
283                                         return index + i;
284                                 else if (result < 0)
285                                         return ~(index + i);
286                         }
287
288                         return ~(index + length);
289                 }
290
291                 public static void Clear (Array array, int index, int length)
292                 {
293                         if (array == null)
294                                 throw new ArgumentNullException ();
295
296                         if (array.Rank > 1)
297                                 throw new RankException ();
298
299                         if (index < array.GetLowerBound (0) || length < 0 ||
300                                 index + length > array.GetUpperBound (0) + 1)
301                                 throw new ArgumentOutOfRangeException ();
302
303                         for (int i = 0; i < length; i++) 
304                         {
305                                 array.SetValue(null, index + i);
306                         }
307                 }
308
309                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
310                 public virtual extern object Clone ();
311
312                 public static void Copy (Array source, Array dest, int length)
313                 {
314                         // I don't know how to handle this ?
315                         if (source.Rank > 1 || dest.Rank > 1)
316                                 throw new RankException ();
317
318                         Copy (source, source.GetLowerBound (0), dest, dest.GetLowerBound (0), length);                  
319                 }
320
321                 public static void Copy (Array source, int source_idx, Array dest, int dest_idx, int length)
322                 {
323                         // I don't know how to handle this ?
324                         if (source.Rank > 1 || dest.Rank > 1)
325                                 throw new RankException ();
326
327                         if (length < 0)
328                                 throw new ArgumentOutOfRangeException ();
329
330                         if (source == null || dest == null)
331                                 throw new ArgumentNullException ();
332
333                         if (source_idx < source.GetLowerBound (0) ||
334                             source_idx + length > source.GetUpperBound (0) + 1||
335                             dest_idx < dest.GetLowerBound (0) || dest_idx + length > dest.GetUpperBound (0) + 1)
336                                 throw new ArgumentException ();
337
338                         if (source.Rank != dest.Rank)
339                                 throw new RankException ();
340
341                         for (int i = 0; i < length; i++) 
342                         {
343                                 int index = source.GetLowerBound (0) + i + source_idx;
344
345                                 dest.SetValue(source.GetValue(index), dest_idx + i + dest.GetLowerBound (0));
346                         }
347                         
348                 }
349                 
350                 public static int IndexOf (Array array, object value)
351                 {
352                         return IndexOf (array, value, 0, array.Length);
353                 }
354
355                 public static int IndexOf (Array array, object value, int index)
356                 {
357                         return IndexOf (array, value, index, array.Length - index);
358                 }
359                 
360                 public static int IndexOf (Array array, object value, int index, int length)
361                 {
362                         if (array == null)
363                                 throw new ArgumentNullException ();
364         
365                         if (length < 0 || index < array.GetLowerBound (0) ||
366                             index > array.GetUpperBound (0))
367                                 throw new ArgumentOutOfRangeException ();
368
369                         for (int i = 0; i < length; i++)
370                         {
371                                 if (array.GetValue(index + i).Equals(value))
372                                         return index + i;
373                         }
374
375                         return array.GetLowerBound (0) - 1;
376                 }
377
378                 public static int LastIndexOf (Array array, object value)
379                 {
380                         return LastIndexOf (array, value, 0, array.Length);
381                 }
382
383                 public static int LastIndexOf (Array array, object value, int index)
384                 {
385                         return LastIndexOf (array, value, index, array.Length - index);
386                 }
387                 
388                 public static int LastIndexOf (Array array, object value, int index, int length)
389                 {
390                         if (array == null)
391                                 throw new ArgumentNullException ();
392         
393                         if (length < 0 || index < array.GetLowerBound (0) ||
394                             index > array.GetUpperBound (0))
395                                 throw new ArgumentOutOfRangeException ();
396
397                         for (int i = length - 1; i >= 0; i--)
398                         {
399                                 if (array.GetValue(index + i).Equals(value))
400                                         return index + i;
401                         }
402
403                         return array.GetLowerBound (0) - 1;
404                 }
405
406                 public static void Reverse (Array array)
407                 {
408                         Reverse (array, array.GetLowerBound (0), array.GetLength (0));
409                 }
410
411                 public static void Reverse (Array array, int index, int length)
412                 {
413                         if (array == null)
414                                 throw new ArgumentNullException ();
415
416                         if (array.Rank > 1)
417                                 throw new RankException ();
418
419                         if (index < array.GetLowerBound (0) || length < 0)
420                                 throw new ArgumentOutOfRangeException ();
421
422                         if (index + length > array.GetUpperBound (0) + 1)
423                                 throw new ArgumentException ();
424
425                         for (int i = 0; i < length/2; i++)
426                         {
427                                 object tmp;
428
429                                 tmp = array.GetValue (index + i);
430                                 array.SetValue(array.GetValue (index + length - i - 1), index + i);
431                                 array.SetValue(tmp, index + length - i - 1);
432                         }
433                 }               
434                 
435                 public static void Sort (Array array)
436                 {
437                         Sort (array, null, array.GetLowerBound (0), array.GetLength (0), null);
438                 }
439
440                 public static void Sort (Array keys, Array items)
441                 {
442                         Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), null);
443                 }
444
445                 public static void Sort (Array array, IComparer comparer)
446                 {
447                         Sort (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
448                 }
449
450                 public static void Sort (Array array, int index, int length)
451                 {
452                         Sort (array, null, index, length, null);
453                 }
454
455                 public static void Sort (Array keys, Array items, IComparer comparer)
456                 {
457                         Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
458                 }
459
460                 public static void Sort (Array keys, Array items, int index, int length)
461                 {
462                         Sort (keys, items, index, length, null);
463                 }
464
465                 public static void Sort (Array array, int index, int length, IComparer comparer)
466                 {
467                         Sort (array, null, index, length, comparer);
468                 }
469
470                 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
471                 {
472                         int low0 = index;
473                         int high0 = index + length - 1;
474
475                         qsort (keys, items, index, index + length - 1, comparer);
476                 }
477
478                 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
479                 {
480                         int pivot;
481                         int low = low0;
482                         int high = high0;
483                         
484                         if (keys.Rank > 1 || (items != null && items.Rank > 1))
485                                 throw new RankException ();
486
487                         if (low >= high)
488                                 return;
489
490                         pivot = (low + high) / 2;
491
492                         if (compare (keys.GetValue (low), keys.GetValue (pivot), comparer) > 0)
493                                 swap (keys, items, low, pivot);
494                         
495                         if (compare (keys.GetValue (pivot), keys.GetValue (high), comparer) > 0)
496                                 swap (keys, items, pivot, high);
497
498                         while (low < high)
499                         {
500                                 // Move the walls in
501                                 while (low < high && compare (keys.GetValue (low), keys.GetValue (pivot), comparer) < 0)
502                                         low++;
503                                 while (low < high && compare (keys.GetValue (pivot), keys.GetValue (high), comparer) < 0)
504                                         high--;
505
506                                 if (low < high)
507                                 {
508                                         swap (keys, items, low, high);
509                                         low++;
510                                         high--;
511                                 }
512                         }
513
514                         qsort (keys, items, low0, low - 1, comparer);
515                         qsort (keys, items, high + 1, high0, comparer);
516                 }
517
518                 private static void swap (Array keys, Array items, int i, int j)
519                 {
520                         object tmp;
521
522                         tmp = keys.GetValue (i);
523                         keys.SetValue (keys.GetValue (j), i);
524                         keys.SetValue (tmp, j);
525
526                         if (items != null)
527                         {
528                                 tmp = items.GetValue (i);
529                                 items.SetValue (items.GetValue (j), i);
530                                 items.SetValue (tmp, j);
531                         }
532                 }
533
534                 private static int compare (object value1, object value2, IComparer comparer)
535                 {
536                         if (comparer == null)
537                                 return ((IComparable) value1).CompareTo(value2);
538                         else
539                                 return comparer.Compare(value1, value2);
540                 }
541         
542                 public virtual void CopyTo (Array array, int index)
543                 {
544                         Copy (this, this.GetLowerBound(0), array, index, this.GetUpperBound (0));
545                 }
546         }
547 }