2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / System / Array.cs
1 //
2 // System.Array.cs
3 //
4 // Authors:
5 //   Joe Shaw (joe@ximian.com)
6 //   Martin Baulig (martin@gnome.org)
7 //   Dietmar Maurer (dietmar@ximian.com)
8 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 //
10 // (C) 2001-2003 Ximian, Inc.  http://www.ximian.com
11 //
12
13 //
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
39 #if NET_2_0
40 using System.Collections.Generic;
41 #endif
42 namespace System
43 {
44         [Serializable]
45         [MonoTODO ("We are doing way to many double/triple exception checks for the overloaded functions")]
46         [MonoTODO ("Sort overloads parameter checks are VERY inconsistent")]
47         public abstract class Array : ICloneable, ICollection, IList, IEnumerable
48         {
49                 // Constructor
50                 private Array ()
51                 {
52                 }
53
54                 // Properties
55                 public int Length {
56                         get {
57                                 int length = this.GetLength (0);
58
59                                 for (int i = 1; i < this.Rank; i++) {
60                                         length *= this.GetLength (i); 
61                                 }
62                                 return length;
63                         }
64                 }
65
66 #if NET_1_1
67                 [ComVisible (false)]
68                 public long LongLength {
69                         get { return Length; }
70                 }
71 #endif
72
73                 public int Rank {
74                         get {
75                                 return this.GetRank ();
76                         }
77                 }
78
79                 // IList interface
80                 object IList.this [int index] {
81                         get {
82                                 if (unchecked ((uint) index) >= unchecked ((uint) Length))
83                                         throw new ArgumentOutOfRangeException ("index");
84                                 return GetValueImpl (index);
85                         } 
86                         set {
87                                 if (unchecked ((uint) index) >= unchecked ((uint) Length))
88                                         throw new ArgumentOutOfRangeException ("index");
89                                 SetValueImpl (value, index);
90                         }
91                 }
92
93                 int IList.Add (object value)
94                 {
95                         throw new NotSupportedException ();
96                 }
97
98                 void IList.Clear ()
99                 {
100                         Array.Clear (this, this.GetLowerBound (0), this.Length);
101                 }
102
103                 bool IList.Contains (object value)
104                 {
105                         if (this.Rank > 1)
106                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
107
108                         int length = this.Length;
109                         for (int i = 0; i < length; i++) {
110                                 if (Object.Equals (value, this.GetValueImpl (i)))
111                                         return true;
112                         }
113                         return false;
114                 }
115
116                 int IList.IndexOf (object value)
117                 {
118                         if (this.Rank > 1)
119                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
120
121                         int length = this.Length;
122                         for (int i = 0; i < length; i++) {
123                                 if (Object.Equals (value, this.GetValueImpl (i)))
124                                         // array index may not be zero-based.
125                                         // use lower bound
126                                         return i + this.GetLowerBound (0);
127                         }
128
129                         int retVal;
130                         unchecked {
131                                 // lower bound may be MinValue
132                                 retVal = this.GetLowerBound (0) - 1;
133                         }
134
135                         return retVal;
136                 }
137
138                 void IList.Insert (int index, object value)
139                 {
140                         throw new NotSupportedException ();
141                 }
142
143                 void IList.Remove (object value)
144                 {
145                         throw new NotSupportedException ();
146                 }
147
148                 void IList.RemoveAt (int index)
149                 {
150                         throw new NotSupportedException ();
151                 }
152
153                 // InternalCall Methods
154                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
155                 private extern int GetRank ();
156
157                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
158                 public extern int GetLength (int dimension);
159
160 #if NET_1_1
161                 [ComVisible (false)]
162                 public long GetLongLength (int dimension)
163                 {
164                         return GetLength (dimension);
165                 }
166 #endif
167
168                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
169                 public extern int GetLowerBound (int dimension);
170
171                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
172                 public extern object GetValue (int[] indices);
173
174                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
175                 public extern void SetValue (object value, int[] indices);
176
177                 // CAUTION! No bounds checking!
178                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
179                 internal extern object GetValueImpl (int pos);
180
181                 // CAUTION! No bounds checking!
182                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
183                 internal extern void SetValueImpl (object value, int pos);
184
185                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
186                 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
187
188                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
189                 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
190
191                 // Properties
192                 int ICollection.Count {
193                         get {
194                                 return Length;
195                         }
196                 }
197
198                 public virtual bool IsSynchronized {
199                         get {
200                                 return false;
201                         }
202                 }
203
204                 public virtual object SyncRoot {
205                         get {
206                                 return this;
207                         }
208                 }
209
210                 public virtual bool IsFixedSize {
211                         get {
212                                 return true;
213                         }
214                 }
215
216                 public virtual bool IsReadOnly {
217                         get {
218                                 return false;
219                         }
220                 }
221
222                 public virtual IEnumerator GetEnumerator ()
223                 {
224                         return new SimpleEnumerator (this);
225                 }
226
227                 public int GetUpperBound (int dimension)
228                 {
229                         return GetLowerBound (dimension) + GetLength (dimension) - 1;
230                 }
231
232                 public object GetValue (int index)
233                 {
234                         if (Rank != 1)
235                                 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
236                         if (index < GetLowerBound (0) || index > GetUpperBound (0))
237                                 throw new IndexOutOfRangeException (Locale.GetText (
238                                         "Index has to be between upper and lower bound of the array."));
239
240                         return GetValueImpl (index - GetLowerBound (0));
241                 }
242
243                 public object GetValue (int index1, int index2)
244                 {
245                         int[] ind = {index1, index2};
246                         return GetValue (ind);
247                 }
248
249                 public object GetValue (int index1, int index2, int index3)
250                 {
251                         int[] ind = {index1, index2, index3};
252                         return GetValue (ind);
253                 }
254
255 #if NET_1_1
256                 [ComVisible (false)]
257                 public object GetValue (long index)
258                 {
259                         if (index < 0 || index > Int32.MaxValue)
260                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
261                                         "Value must be >= 0 and <= Int32.MaxValue."));
262
263                         return GetValue ((int) index);
264                 }
265
266                 [ComVisible (false)]
267                 public object GetValue (long index1, long index2)
268                 {
269                         if (index1 < 0 || index1 > Int32.MaxValue)
270                                 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
271                                         "Value must be >= 0 and <= Int32.MaxValue."));
272
273                         if (index2 < 0 || index2 > Int32.MaxValue)
274                                 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
275                                         "Value must be >= 0 and <= Int32.MaxValue."));
276
277                         return GetValue ((int) index1, (int) index2);
278                 }
279
280                 [ComVisible (false)]
281                 public object GetValue (long index1, long index2, long index3)
282                 {
283                         if (index1 < 0 || index1 > Int32.MaxValue)
284                                 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
285                                         "Value must be >= 0 and <= Int32.MaxValue."));
286
287                         if (index2 < 0 || index2 > Int32.MaxValue)
288                                 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
289                                         "Value must be >= 0 and <= Int32.MaxValue."));
290
291                         if (index3 < 0 || index3 > Int32.MaxValue)
292                                 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
293                                         "Value must be >= 0 and <= Int32.MaxValue."));
294
295                         return GetValue ((int) index1, (int) index2, (int) index3);
296                 }
297
298                 [ComVisible (false)]
299                 public void SetValue (object value, long index)
300                 {
301                         if (index < 0 || index > Int32.MaxValue)
302                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
303                                         "Value must be >= 0 and <= Int32.MaxValue."));
304
305                         SetValue (value, (int) index);
306                 }
307
308                 [ComVisible (false)]
309                 public void SetValue (object value, long index1, long index2)
310                 {
311                         if (index1 < 0 || index1 > Int32.MaxValue)
312                                 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
313                                         "Value must be >= 0 and <= Int32.MaxValue."));
314
315                         if (index2 < 0 || index2 > Int32.MaxValue)
316                                 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
317                                         "Value must be >= 0 and <= Int32.MaxValue."));
318
319                         int[] ind = {(int) index1, (int) index2};
320                         SetValue (value, ind);
321                 }
322
323                 [ComVisible (false)]
324                 public void SetValue (object value, long index1, long index2, long index3)
325                 {
326                         if (index1 < 0 || index1 > Int32.MaxValue)
327                                 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
328                                         "Value must be >= 0 and <= Int32.MaxValue."));
329
330                         if (index2 < 0 || index2 > Int32.MaxValue)
331                                 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
332                                         "Value must be >= 0 and <= Int32.MaxValue."));
333
334                         if (index3 < 0 || index3 > Int32.MaxValue)
335                                 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
336                                         "Value must be >= 0 and <= Int32.MaxValue."));
337
338                         int[] ind = {(int) index1, (int) index2, (int) index3};
339                         SetValue (value, ind);
340                 }
341 #endif
342
343 //              // This function is currently unused, but just in case we need it later on ... */
344 //              internal int IndexToPos (int[] idxs)
345 //              {
346 //                      if (idxs == null)
347 //                              throw new ArgumentNullException ("idxs");
348 //
349 //                      if ((idxs.Rank != 1) || (idxs.Length != Rank))
350 //                              throw new ArgumentException ();
351 //
352 //                      if ((idxs [0] < GetLowerBound (0)) || (idxs [0] > GetUpperBound (0)))
353 //                              throw new IndexOutOfRangeException();
354 //
355 //                      int pos = idxs [0] - GetLowerBound (0);
356 //                      for (int i = 1; i < Rank; i++) {
357 //                              if ((idxs [i] < GetLowerBound (i)) || (idxs [i] > GetUpperBound (i)))
358 //                                      throw new IndexOutOfRangeException();
359 //
360 //                              pos *= GetLength (i);
361 //                              pos += idxs [i] - GetLowerBound (i);
362 //                      }
363 //
364 //                      return pos;
365 //              }
366
367                 public void SetValue (object value, int index)
368                 {
369                         if (Rank != 1)
370                                 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
371                         if (index < GetLowerBound (0) || index > GetUpperBound (0))
372                                 throw new IndexOutOfRangeException (Locale.GetText (
373                                         "Index has to be >= lower bound and <= upper bound of the array."));
374
375                         SetValueImpl (value, index - GetLowerBound (0));
376                 }
377
378                 public void SetValue (object value, int index1, int index2)
379                 {
380                         int[] ind = {index1, index2};
381                         SetValue (value, ind);
382                 }
383
384                 public void SetValue (object value, int index1, int index2, int index3)
385                 {
386                         int[] ind = {index1, index2, index3};
387                         SetValue (value, ind);
388                 }
389
390                 public static Array CreateInstance (Type elementType, int length)
391                 {
392                         int[] lengths = {length};
393                         int[] bounds = null;
394
395                         return CreateInstanceImpl (elementType, lengths, bounds);
396                 }
397
398                 public static Array CreateInstance (Type elementType, int length1, int length2)
399                 {
400                         int[] lengths = {length1, length2};
401                         int[] bounds = null;
402
403                         return CreateInstanceImpl (elementType, lengths, bounds);
404                 }
405
406                 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
407                 {
408                         int[] lengths = {length1, length2, length3};
409                         int[] bounds = null;
410
411                         return CreateInstanceImpl (elementType, lengths, bounds);
412                 }
413
414                 public static Array CreateInstance (Type elementType, int[] lengths)
415                 {
416                         if (elementType == null)
417                                 throw new ArgumentNullException ("elementType");
418                         if (lengths == null)
419                                 throw new ArgumentNullException ("lengths");
420
421                         if (lengths.Length > 255)
422                                 throw new TypeLoadException ();
423
424                         int[] bounds = null;
425                         
426                         return CreateInstanceImpl (elementType, lengths, bounds);
427                 }
428
429                 public static Array CreateInstance (Type elementType, int[] lengths, int [] bounds)
430                 {
431                         if (elementType == null)
432                                 throw new ArgumentNullException ("elementType");
433                         if (lengths == null)
434                                 throw new ArgumentNullException ("lengths");
435                         if (bounds == null)
436                                 throw new ArgumentNullException ("bounds");
437
438                         if (lengths.Length < 1)
439                                 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
440
441                         if (lengths.Length != bounds.Length)
442                                 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
443
444                         for (int j = 0; j < bounds.Length; j ++) {
445                                 if (lengths [j] < 0)
446                                         throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
447                                                 "Each value has to be >= 0."));
448                                 if ((long)bounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
449                                         throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
450                                                 "Length + bound must not exceed Int32.MaxValue."));
451                         }
452
453                         if (lengths.Length > 255)
454                                 throw new TypeLoadException ();
455
456                         return CreateInstanceImpl (elementType, lengths, bounds);
457                 }
458
459 #if NET_1_1
460                 static int [] GetIntArray (long [] values)
461                 {
462                         int len = values.Length;
463                         int [] ints = new int [len];
464                         for (int i = 0; i < len; i++) {
465                                 long current = values [i];
466                                 if (current < 0 || current > (long) Int32.MaxValue)
467                                         throw new ArgumentOutOfRangeException ("values", Locale.GetText (
468                                                 "Each value has to be >= 0 and <= Int32.MaxValue."));
469
470                                 ints [i] = (int) current;
471                         }
472                         return ints;
473                 }
474
475                 public static Array CreateInstance (Type elementType, params long [] lengths)
476                 {
477                         if (lengths == null) {
478                                 // LAMESPEC: Docs say we should throw a ArgumentNull, but .NET
479                                 // 1.1 actually throws a NullReference.
480                                 throw new NullReferenceException (Locale.GetText ("'lengths' cannot be null."));
481                         }
482                         return CreateInstance (elementType, GetIntArray (lengths));
483                 }
484
485                 [ComVisible (false)]
486                 public object GetValue (long [] indices)
487                 {
488                         if (indices == null) {
489                                 // LAMESPEC: Docs say we should throw a ArgumentNull, but .NET
490                                 // 1.1 actually throws a NullReference.
491                                 throw new NullReferenceException (Locale.GetText ("'indices' cannot be null."));
492                         }
493                         return GetValue (GetIntArray (indices));
494                 }
495
496                 [ComVisible (false)]
497                 public void SetValue (object value, long [] indices)
498                 {
499                         if (indices == null) {
500                                 // LAMESPEC: Docs say we should throw a ArgumentNull, but .NET
501                                 // 1.1 actually throws a NullReference.
502                                 throw new NullReferenceException (Locale.GetText ("'indices' cannot be null."));
503                         }
504                         SetValue (value, GetIntArray (indices));
505                 }
506 #endif
507
508                 public static int BinarySearch (Array array, object value)
509                 {
510                         if (array == null)
511                                 throw new ArgumentNullException ("array");
512
513                         if (value == null)
514                                 return -1;
515
516                         if (array.Rank > 1)
517                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
518
519                         if (!(value is IComparable))
520                                 throw new ArgumentException (Locale.GetText ("value does not support IComparable."));
521
522                         return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, null);
523                 }
524
525                 public static int BinarySearch (Array array, object value, IComparer comparer)
526                 {
527                         if (array == null)
528                                 throw new ArgumentNullException ("array");
529
530                         if (array.Rank > 1)
531                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
532
533                         if ((comparer == null) && (value != null) && !(value is IComparable))
534                                 throw new ArgumentException (Locale.GetText (
535                                         "comparer is null and value does not support IComparable."));
536
537                         return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
538                 }
539
540                 public static int BinarySearch (Array array, int index, int length, object value)
541                 {
542                         if (array == null)
543                                 throw new ArgumentNullException ("array");
544
545                         if (array.Rank > 1)
546                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
547
548                         if (index < array.GetLowerBound (0))
549                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
550                                         "index is less than the lower bound of array."));
551                         if (length < 0)
552                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
553                                         "Value has to be >= 0."));
554                         // re-ordered to avoid possible integer overflow
555                         if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
556                                 throw new ArgumentException (Locale.GetText (
557                                         "index and length do not specify a valid range in array."));
558                         if ((value != null) && (!(value is IComparable)))
559                                 throw new ArgumentException (Locale.GetText (
560                                         "value does not support IComparable"));
561
562                         return DoBinarySearch (array, index, length, value, null);
563                 }
564
565                 public static int BinarySearch (Array array, int index, int length, object value, IComparer comparer)
566                 {
567                         if (array == null)
568                                 throw new ArgumentNullException ("array");
569
570                         if (array.Rank > 1)
571                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
572
573                         if (index < array.GetLowerBound (0))
574                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
575                                         "index is less than the lower bound of array."));
576                         if (length < 0)
577                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
578                                         "Value has to be >= 0."));
579                         // re-ordered to avoid possible integer overflow
580                         if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
581                                 throw new ArgumentException (Locale.GetText (
582                                         "index and length do not specify a valid range in array."));
583
584                         if ((comparer == null) && (value != null) && !(value is IComparable))
585                                 throw new ArgumentException (Locale.GetText (
586                                         "comparer is null and value does not support IComparable."));
587
588                         return DoBinarySearch (array, index, length, value, comparer);
589                 }
590
591                 static int DoBinarySearch (Array array, int index, int length, object value, IComparer comparer)
592                 {
593                         // cache this in case we need it
594                         if (comparer == null)
595                                 comparer = Comparer.Default;
596
597                         int iMin = index;
598                         // Comment from Tum (tum@veridicus.com):
599                         // *Must* start at index + length - 1 to pass rotor test co2460binarysearch_iioi
600                         int iMax = index + length - 1;
601                         int iCmp = 0;
602                         try {
603                                 while (iMin <= iMax) {
604                                         int iMid = (iMin + iMax) / 2;
605                                         object elt = array.GetValueImpl (iMid);
606
607                                         iCmp = comparer.Compare (value, elt);
608
609                                         if (iCmp == 0)
610                                                 return iMid;
611                                         else if (iCmp < 0)
612                                                 iMax = iMid - 1;
613                                         else
614                                                 iMin = iMid + 1; // compensate for the rounding down
615                                 }
616                         }
617                         catch (Exception e) {
618                                 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
619                         }
620
621                         return ~iMin;
622                 }
623
624                 public static void Clear (Array array, int index, int length)
625                 {
626                         if (array == null)
627                                 throw new ArgumentNullException ("array");
628                         if (length < 0)
629                                 throw new ArgumentOutOfRangeException ("length < 0");
630
631                         int low = array.GetLowerBound (0);
632                         if (index < low)
633                                 throw new IndexOutOfRangeException ("index < lower bound");
634                         index = index - low;
635
636                         // re-ordered to avoid possible integer overflow
637                         if (index > array.Length - length)
638                                 throw new IndexOutOfRangeException ("index + length > size");
639
640                         ClearInternal (array, index, length);
641                 }
642                 
643                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
644                 static extern void ClearInternal (Array a, int index, int count);
645
646                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
647                 public virtual extern object Clone ();
648
649                 public static void Copy (Array sourceArray, Array destinationArray, int length)
650                 {
651                         // need these checks here because we are going to use
652                         // GetLowerBound() on source and dest.
653                         if (sourceArray == null)
654                                 throw new ArgumentNullException ("sourceArray");
655
656                         if (destinationArray == null)
657                                 throw new ArgumentNullException ("destinationArray");
658
659                         Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
660                                 destinationArray.GetLowerBound (0), length);
661                 }
662
663                 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
664                 {
665                         if (sourceArray == null)
666                                 throw new ArgumentNullException ("sourceArray");
667
668                         if (destinationArray == null)
669                                 throw new ArgumentNullException ("destinationArray");
670
671                         if (length < 0)
672                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
673                                         "Value has to be >= 0."));;
674
675                         if (sourceIndex < 0)
676                                 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
677                                         "Value has to be >= 0."));;
678
679                         if (destinationIndex < 0)
680                                 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
681                                         "Value has to be >= 0."));;
682
683                         if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
684                                 return;
685
686                         int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
687                         int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
688
689                         // re-ordered to avoid possible integer overflow
690                         if (source_pos > sourceArray.Length - length || dest_pos > destinationArray.Length - length)
691                                 throw new ArgumentException ("length");
692
693                         if (sourceArray.Rank != destinationArray.Rank)
694                                 throw new RankException (Locale.GetText ("Arrays must be of same size."));
695
696                         Type src_type = sourceArray.GetType ().GetElementType ();
697                         Type dst_type = destinationArray.GetType ().GetElementType ();
698
699                         if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
700                                 for (int i = 0; i < length; i++) {
701                                         Object srcval = sourceArray.GetValueImpl (source_pos + i);
702
703                                         try {
704                                                 destinationArray.SetValueImpl (srcval, dest_pos + i);
705                                         } catch {
706                                                 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
707                                                         (src_type.Equals (typeof (Object))))
708                                                         throw new InvalidCastException ();
709                                                 else
710                                                         throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
711                                                                 "(Types: source={0};  target={1})"), src_type.FullName, dst_type.FullName));
712                                         }
713                                 }
714                         }
715                         else {
716                                 for (int i = length - 1; i >= 0; i--) {
717                                         Object srcval = sourceArray.GetValueImpl (source_pos + i);
718
719                                         try {
720                                                 destinationArray.SetValueImpl (srcval, dest_pos + i);
721                                         } catch {
722                                                 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
723                                                         (src_type.Equals (typeof (Object))))
724                                                         throw new InvalidCastException ();
725                                                 else
726                                                         throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
727                                                                 "(Types: source={0};  target={1})"), src_type.FullName, dst_type.FullName));
728                                         }
729                                 }
730                         }
731                 }
732
733 #if NET_1_1
734                 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
735                                          long destinationIndex, long length)
736                 {
737                         if (sourceArray == null)
738                                 throw new ArgumentNullException ("sourceArray");
739
740                         if (destinationArray == null)
741                                 throw new ArgumentNullException ("destinationArray");
742
743                         if (sourceIndex < Int32.MinValue || sourceIndex > Int32.MaxValue)
744                                 throw new ArgumentOutOfRangeException ("sourceIndex",
745                                         Locale.GetText ("Must be in the Int32 range."));
746
747                         if (destinationIndex < Int32.MinValue || destinationIndex > Int32.MaxValue)
748                                 throw new ArgumentOutOfRangeException ("destinationIndex",
749                                         Locale.GetText ("Must be in the Int32 range."));
750
751                         if (length < 0 || length > Int32.MaxValue)
752                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
753                                         "Value must be >= 0 and <= Int32.MaxValue."));
754
755                         Copy (sourceArray, (int) sourceIndex, destinationArray, (int) destinationIndex, (int) length);
756                 }
757
758                 public static void Copy (Array sourceArray, Array destinationArray, long length)
759                 {
760                         if (length < 0 || length > Int32.MaxValue)
761                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
762                                         "Value must be >= 0 and <= Int32.MaxValue."));
763
764                         Copy (sourceArray, destinationArray, (int) length);
765                 }
766 #endif
767
768                 public static int IndexOf (Array array, object value)
769                 {
770                         if (array == null)
771                                 throw new ArgumentNullException ("array");
772         
773                         return IndexOf (array, value, 0, array.Length);
774                 }
775
776                 public static int IndexOf (Array array, object value, int startIndex)
777                 {
778                         if (array == null)
779                                 throw new ArgumentNullException ("array");
780
781                         return IndexOf (array, value, startIndex, array.Length - startIndex);
782                 }
783
784                 public static int IndexOf (Array array, object value, int startIndex, int count)
785                 {
786                         if (array == null)
787                                 throw new ArgumentNullException ("array");
788
789                         if (array.Rank > 1)
790                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
791
792                         // re-ordered to avoid possible integer overflow
793                         if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
794                                 throw new ArgumentOutOfRangeException ();
795
796                         int max = startIndex + count;
797                         for (int i = startIndex; i < max; i++) {
798                                 if (Object.Equals (array.GetValueImpl (i), value))
799                                         return i;
800                         }
801
802                         return array.GetLowerBound (0) - 1;
803                 }
804
805                 [MonoTODO]
806                 public void Initialize()
807                 {
808                         //FIXME: We would like to find a compiler that uses
809                         // this method. It looks like this method do nothing
810                         // in C# so no exception is trown by the moment.
811                 }
812
813                 public static int LastIndexOf (Array array, object value)
814                 {
815                         if (array == null)
816                                 throw new ArgumentNullException ("array");
817
818                         return LastIndexOf (array, value, array.Length - 1);
819                 }
820
821                 public static int LastIndexOf (Array array, object value, int startIndex)
822                 {
823                         if (array == null)
824                                 throw new ArgumentNullException ("array");
825
826                         return LastIndexOf (array, value, startIndex, startIndex - array.GetLowerBound (0) + 1);
827                 }
828                 
829                 public static int LastIndexOf (Array array, object value, int startIndex, int count)
830                 {
831                         if (array == null)
832                                 throw new ArgumentNullException ("array");
833         
834                         if (array.Rank > 1)
835                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
836
837                         if (count < 0 || startIndex < array.GetLowerBound (0) ||
838                                 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < array.GetLowerBound (0))
839                                 throw new ArgumentOutOfRangeException ();
840
841                         for (int i = startIndex; i >= startIndex - count + 1; i--) {
842                                 if (Object.Equals (array.GetValueImpl (i), value))
843                                         return i;
844                         }
845
846                         return array.GetLowerBound (0) - 1;
847                 }
848
849                 public static void Reverse (Array array)
850                 {
851                         if (array == null)
852                                 throw new ArgumentNullException ("array");
853
854                         Reverse (array, array.GetLowerBound (0), array.GetLength (0));
855                 }
856
857                 public static void Reverse (Array array, int index, int length)
858                 {
859                         if (array == null)
860                                 throw new ArgumentNullException ("array");
861
862                         if (array.Rank > 1)
863                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
864
865                         if (index < array.GetLowerBound (0) || length < 0)
866                                 throw new ArgumentOutOfRangeException ();
867
868                         // re-ordered to avoid possible integer overflow
869                         if (index > array.GetUpperBound (0) + 1 - length)
870                                 throw new ArgumentException ();
871
872                         for (int i = 0; i < length / 2; i++)
873                         {
874                                 object tmp;
875
876                                 tmp = array.GetValueImpl (index + i);
877                                 array.SetValueImpl (array.GetValueImpl (index + length - i - 1), index + i);
878                                 array.SetValueImpl (tmp, index + length - i - 1);
879                         }
880                 }
881
882                 public static void Sort (Array array)
883                 {
884                         if (array == null)
885                                 throw new ArgumentNullException ("array");
886
887                         Sort (array, null, array.GetLowerBound (0), array.GetLength (0), null);
888                 }
889
890                 public static void Sort (Array keys, Array items)
891                 {
892                         if (keys == null)
893                                 throw new ArgumentNullException ("keys");
894
895                         Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), null);
896                 }
897
898                 public static void Sort (Array array, IComparer comparer)
899                 {
900                         if (array == null)
901                                 throw new ArgumentNullException ("array");
902
903                         Sort (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
904                 }
905
906                 public static void Sort (Array array, int index, int length)
907                 {
908                         Sort (array, null, index, length, null);
909                 }
910
911                 public static void Sort (Array keys, Array items, IComparer comparer)
912                 {
913                         if (keys == null)
914                                 throw new ArgumentNullException ("keys");
915
916                         Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
917                 }
918
919                 public static void Sort (Array keys, Array items, int index, int length)
920                 {
921                         Sort (keys, items, index, length, null);
922                 }
923
924                 public static void Sort (Array array, int index, int length, IComparer comparer)
925                 {
926                         Sort (array, null, index, length, comparer);
927                 }
928
929                 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
930                 {
931                         if (keys == null)
932                                 throw new ArgumentNullException ("keys");
933
934                         if (keys.Rank > 1 || (items != null && items.Rank > 1))
935                                 throw new RankException ();
936
937                         if (items != null && keys.GetLowerBound (0) != items.GetLowerBound (0))
938                                 throw new ArgumentException ();
939
940                         if (index < keys.GetLowerBound (0))
941                                 throw new ArgumentOutOfRangeException ("index");
942
943                         if (length < 0)
944                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
945                                         "Value has to be >= 0."));
946
947                         if (keys.Length - (index + keys.GetLowerBound (0)) < length
948                                 || (items != null && index > items.Length - length))
949                                 throw new ArgumentException ();
950
951                         try {
952                                 int low0 = index;
953                                 int high0 = index + length - 1;
954                                 qsort (keys, items, low0, high0, comparer);
955                         }
956                         catch (Exception e) {
957                                 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
958                         }
959                 }
960
961                 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
962                 {
963                         if (low0 >= high0)
964                                 return;
965
966                         int low = low0;
967                         int high = high0;
968
969                         object objPivot = keys.GetValueImpl ((low + high) / 2);
970
971                         while (low <= high) {
972                                 // Move the walls in
973                                 while (low < high0 && compare (keys.GetValueImpl (low), objPivot, comparer) < 0)
974                                         ++low;
975                                 while (high > low0 && compare (objPivot, keys.GetValueImpl (high), comparer) < 0)
976                                         --high;
977
978                                 if (low <= high) {
979                                         swap (keys, items, low, high);
980                                         ++low;
981                                         --high;
982                                 }
983                         }
984
985                         if (low0 < high)
986                                 qsort (keys, items, low0, high, comparer);
987                         if (low < high0)
988                                 qsort (keys, items, low, high0, comparer);
989                 }
990
991                 private static void swap (Array keys, Array items, int i, int j)
992                 {
993                         object tmp;
994
995                         tmp = keys.GetValueImpl (i);
996                         keys.SetValueImpl (keys.GetValue (j), i);
997                         keys.SetValueImpl (tmp, j);
998
999                         if (items != null) {
1000                                 tmp = items.GetValueImpl (i);
1001                                 items.SetValueImpl (items.GetValueImpl (j), i);
1002                                 items.SetValueImpl (tmp, j);
1003                         }
1004                 }
1005
1006                 private static int compare (object value1, object value2, IComparer comparer)
1007                 {
1008                         if (value1 == null)
1009                                 return value2 == null ? 0 : -1;
1010                         else if (value2 == null)
1011                                 return 1;
1012                         else if (comparer == null)
1013                                 return ((IComparable) value1).CompareTo (value2);
1014                         else
1015                                 return comparer.Compare (value1, value2);
1016                 }
1017         
1018                 public virtual void CopyTo (Array array, int index)
1019                 {
1020                         if (array == null)
1021                                 throw new ArgumentNullException ("array");
1022
1023                         // The order of these exception checks may look strange,
1024                         // but that's how the microsoft runtime does it.
1025                         if (this.Rank > 1)
1026                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1027                         if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
1028                                 throw new ArgumentException ();
1029                         if (array.Rank > 1)
1030                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1031                         if (index < 0)
1032                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
1033                                         "Value has to be >= 0."));
1034
1035                         Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
1036                 }
1037
1038 #if NET_1_1
1039                 [ComVisible (false)]
1040                 public virtual void CopyTo (Array array, long index)
1041                 {
1042                         if (index < 0 || index > Int32.MaxValue)
1043                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
1044                                         "Value must be >= 0 and <= Int32.MaxValue."));
1045
1046                         CopyTo (array, (int) index);
1047                 }
1048 #endif
1049
1050                 internal class SimpleEnumerator : IEnumerator, ICloneable
1051                 {
1052                         Array enumeratee;
1053                         int currentpos;
1054                         int length;
1055
1056                         public SimpleEnumerator (Array arrayToEnumerate)
1057                         {
1058                                 this.enumeratee = arrayToEnumerate;
1059                                 this.currentpos = -1;
1060                                 this.length = arrayToEnumerate.Length;
1061                         }
1062
1063                         public object Current {
1064                                 get {
1065                                         // Exception messages based on MS implementation
1066                                         if (currentpos < 0 )
1067                                                 throw new InvalidOperationException (Locale.GetText (
1068                                                         "Enumeration has not started."));
1069                                         if  (currentpos >= length)
1070                                                 throw new InvalidOperationException (Locale.GetText (
1071                                                         "Enumeration has already ended"));
1072                                         // Current should not increase the position. So no ++ over here.
1073                                         return enumeratee.GetValueImpl (currentpos);
1074                                 }
1075                         }
1076
1077                         public bool MoveNext()
1078                         {
1079                                 //The docs say Current should throw an exception if last
1080                                 //call to MoveNext returned false. This means currentpos
1081                                 //should be set to length when returning false.
1082                                 if (currentpos < length)
1083                                         currentpos++;
1084                                 if(currentpos < length)
1085                                         return true;
1086                                 else
1087                                         return false;
1088                         }
1089
1090                         public void Reset()
1091                         {
1092                                 currentpos = -1;
1093                         }
1094
1095                         public object Clone ()
1096                         {
1097                                 return MemberwiseClone ();
1098                         }
1099                 }
1100 #if NET_2_0
1101                 [CLSCompliant (false)]
1102                 public static void Resize <T> (ref T [] arr, int sz) {
1103                         if (sz < 0)
1104                                 throw new ArgumentOutOfRangeException ();
1105                         
1106                         if (arr == null) {
1107                                 arr = new T [sz];
1108                                 return;
1109                         }
1110                         
1111                         if (arr.Length == sz)
1112                                 return;
1113                         
1114                         T [] a = new T [sz];
1115                         Array.Copy (arr, a, Math.Min (sz, arr.Length));
1116                         arr = a;
1117                 }
1118                 
1119                 [CLSCompliant (false)]
1120                 public static bool TrueForAll <T> (T [] array, Predicate <T> p)
1121                 {
1122                         if (array == null || p == null)
1123                                 throw new ArgumentNullException ();
1124                         
1125                         foreach (T t in array)
1126                                 if (! p (t))
1127                                         return false;
1128                                 
1129                         return true;
1130                 }
1131                 [CLSCompliant (false)]
1132                 public static void ForEach <T> (T [] array, Action <T> a)
1133                 {
1134                         if (array == null || a == null)
1135                                 throw new ArgumentNullException ();
1136                         
1137                         foreach (T t in array)
1138                                 a (t);
1139                 }
1140                 
1141                 [CLSCompliant (false)]
1142                 public static U [] ConvertAll <T, U> (T [] s, Converter <T, U> c)
1143                 {
1144                         if (s == null || c == null)
1145                                 throw new ArgumentNullException ();
1146                         
1147                         U [] r = new U [s.Length];
1148                         
1149                         for (int i = 0; i < s.Length; i ++)
1150                                 r [i] = c (s [i]);
1151                         
1152                         return r;
1153                 }
1154                 
1155                 [CLSCompliant (false)]
1156                 public static int FindLastIndex <T> (T [] a, Predicate <T> c)
1157                 {
1158                         if (a == null)
1159                                 throw new ArgumentNullException ();
1160                         
1161                         return FindLastIndex <T> (a, 0, a.Length, c);
1162                 }
1163                 
1164                 [CLSCompliant (false)]
1165                 public static int FindLastIndex <T> (T [] a, int idx, Predicate <T> c)
1166                 {
1167                         if (a == null)
1168                                 throw new ArgumentNullException ();
1169                         
1170                         return FindLastIndex <T> (a, idx, a.Length - idx, c);
1171                 }
1172                 
1173                 [CLSCompliant (false)]
1174                 public static int FindLastIndex <T> (T [] a, int idx, int cnt, Predicate <T> c)
1175                 {
1176                         if (a == null || c == null)
1177                                 throw new ArgumentNullException ();
1178                         
1179                         if (idx > a.Length || idx + cnt > a.Length)
1180                                 throw new ArgumentOutOfRangeException ();
1181                         
1182                         for (int i = idx + cnt - 1; i >= idx; i --)
1183                                 if (c (a [i]))
1184                                         return i;
1185                                 
1186                         return -1;
1187                 }
1188                 
1189                 [CLSCompliant (false)]
1190                 public static int FindIndex <T> (T [] a, Predicate <T> c)
1191                 {
1192                         if (a == null)
1193                                 throw new ArgumentNullException ();
1194                         
1195                         return FindIndex <T> (a, 0, a.Length, c);
1196                 }
1197                 
1198                 [CLSCompliant (false)]
1199                 public static int FindIndex <T> (T [] a, int idx, Predicate <T> c)
1200                 {
1201                         if (a == null)
1202                                 throw new ArgumentNullException ();
1203                         
1204                         return FindIndex <T> (a, idx, a.Length - idx, c);
1205                 }
1206                 
1207                 [CLSCompliant (false)]
1208                 public static int FindIndex <T> (T [] a, int idx, int cnt, Predicate <T> c)
1209                 {
1210                         if (a == null || c == null)
1211                                 throw new ArgumentNullException ();
1212                         
1213                         if (idx > a.Length || idx + cnt > a.Length)
1214                                 throw new ArgumentOutOfRangeException ();
1215                         
1216                         for (int i = idx; i < idx + cnt; i ++)
1217                                 if (c (a [i]))
1218                                         return i;
1219                                 
1220                         return -1;
1221                 }
1222                 
1223                 [CLSCompliant (false)]
1224                 public static int BinarySearch <T> (T [] a, T x)
1225                 {
1226                         if (a == null)
1227                                 throw new ArgumentNullException ("a");
1228                         
1229                         return BinarySearch <T> (a, 0, a.Length, x, null);
1230                 }
1231                 
1232                 [CLSCompliant (false)]
1233                 public static int BinarySearch <T> (T [] a, T x, IComparer <T> c)
1234                 {
1235                         if (a == null)
1236                                 throw new ArgumentNullException ("a");
1237                         
1238                         return BinarySearch <T> (a, 0, a.Length, x, c);
1239                 }
1240                 
1241                 [CLSCompliant (false)]
1242                 public static int BinarySearch <T> (T [] a, int offset, int length, T x)
1243                 {
1244                         return BinarySearch <T> (a, offset, length, x, null);
1245                 }
1246                 
1247                 [CLSCompliant (false)]
1248                 public static int BinarySearch <T> (T [] array, int index, int length, T x, IComparer <T> c)
1249                 {
1250                         if (array == null)
1251                                 throw new ArgumentNullException ("array");
1252                         if (index < 0)
1253                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
1254                                         "index is less than the lower bound of array."));
1255                         if (length < 0)
1256                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1257                                         "Value has to be >= 0."));
1258                         // re-ordered to avoid possible integer overflow
1259                         if (index > array.Length - length)
1260                                 throw new ArgumentException (Locale.GetText (
1261                                         "index and length do not specify a valid range in array."));
1262                         if (c == null)
1263                                 c = Comparer <T>.Default;
1264                         
1265                         int iMin = index;
1266                         int iMax = index + length - 1;
1267                         int iCmp = 0;
1268                         try {
1269                                 while (iMin <= iMax) {
1270                                         int iMid = (iMin + iMax) / 2;
1271                                         iCmp = c.Compare (x, array [iMid]);
1272
1273                                         if (iCmp == 0)
1274                                                 return iMid;
1275                                         else if (iCmp < 0)
1276                                                 iMax = iMid - 1;
1277                                         else
1278                                                 iMin = iMid + 1; // compensate for the rounding down
1279                                 }
1280                         }
1281                         catch (Exception e) {
1282                                 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
1283                         }
1284
1285                         return ~iMin;
1286                 }
1287                 
1288                 [CLSCompliant (false)]
1289                 public static int IndexOf <T> (T [] array, T value)
1290                 {
1291                         if (array == null)
1292                                 throw new ArgumentNullException ("array");
1293         
1294                         return IndexOf (array, value, 0, array.Length);
1295                 }
1296
1297                 [CLSCompliant (false)]
1298                 public static int IndexOf <T> (T [] array, T value, int startIndex)
1299                 {
1300                         if (array == null)
1301                                 throw new ArgumentNullException ("array");
1302
1303                         return IndexOf (array, value, startIndex, array.Length - startIndex);
1304                 }
1305
1306                 [CLSCompliant (false)]
1307                 public static int IndexOf <T> (T [] array, T value, int startIndex, int count)
1308                 {
1309                         if (array == null)
1310                                 throw new ArgumentNullException ("array");
1311                         
1312                         // re-ordered to avoid possible integer overflow
1313                         if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
1314                                 throw new ArgumentOutOfRangeException ();
1315
1316                         int max = startIndex + count;
1317                         for (int i = startIndex; i < max; i++) {
1318                                 if (Object.Equals (array [i], value))
1319                                 if (Object.Equals (array [i], value))
1320                                         return i;
1321                         }
1322
1323                         return -1;
1324                 }
1325                 
1326                 [CLSCompliant (false)]
1327                 public static int LastIndexOf <T> (T [] array, T value)
1328                 {
1329                         if (array == null)
1330                                 throw new ArgumentNullException ("array");
1331
1332                         return LastIndexOf (array, value, array.Length - 1);
1333                 }
1334
1335                 [CLSCompliant (false)]
1336                 public static int LastIndexOf <T> (T [] array, T value, int startIndex)
1337                 {
1338                         if (array == null)
1339                                 throw new ArgumentNullException ("array");
1340
1341                         return LastIndexOf (array, value, startIndex, startIndex + 1);
1342                 }
1343
1344                 [CLSCompliant (false)]
1345                 public static int LastIndexOf <T> (T [] array, T value, int startIndex, int count)
1346                 {
1347                         if (array == null)
1348                                 throw new ArgumentNullException ("array");
1349                         
1350                         if (count < 0 || startIndex > array.Length || startIndex - count + 1 < 0)
1351                                 throw new ArgumentOutOfRangeException ();
1352
1353                         for (int i = startIndex; i >= startIndex - count + 1; i--) {
1354                                 if (Object.Equals (array [i], value))
1355                                         return i;
1356                         }
1357
1358                         return -1;
1359                 }
1360                 
1361                 [CLSCompliant (false)]
1362                 public static T [] FindAll <T> (T [] a, Predicate <T> p)
1363                 {
1364                         if (a == null || p == null)
1365                                 throw new ArgumentNullException ();
1366                         
1367                         int pos = 0;
1368                         T [] d = new T [a.Length];
1369                         foreach (T t in a)
1370                                 if (p (t))
1371                                         d [pos ++] = t;
1372                         
1373                         Resize <T> (ref a, pos);
1374                         return a;
1375                 }
1376
1377                 [CLSCompliant (false)]
1378                 public static bool Exists <T> (T [] a, Predicate <T> p)
1379                 {
1380                         if (a == null || p == null)
1381                                 throw new ArgumentNullException ();
1382                         
1383                         foreach (T t in a)
1384                                 if (p (t))
1385                                         return true;
1386                         return false;
1387                 }
1388
1389                 [CLSCompliant (false)]
1390                 [MonoTODO]
1391                 public static IList<T> AsReadOnly<T> (T[] array)
1392                 {
1393                         if (array == null)
1394                                 throw new ArgumentNullException ("array");
1395                         return new ReadOnlyArray <T> (array);
1396                 }
1397                 
1398 #if FIXME
1399                 [CLSCompliant (false)]
1400                 public static Nullable <T> Find <T> (T [] a, Predicate <T> p)
1401                 {
1402                         if (a == null || p == null)
1403                                 throw new ArgumentNullException ();
1404                         
1405                         foreach (T t in a)
1406                                 if (p (t))
1407                                         return new Nullable <T> (t);
1408                                 
1409                         return default (Nullable <T>);
1410                 }
1411                 
1412                 [CLSCompliant (false)]
1413                 public static Nullable <T> FindLast <T> (T [] a, Predicate <T> p)
1414                 {
1415                         if (a == null || p == null)
1416                                 throw new ArgumentNullException ();
1417                         
1418                         for (int i = a.Length - 1; i >= 0; i--)
1419                                 if (p (a [i]))
1420                                         return new Nullable <T> (a [i]);
1421                                 
1422                         return default (Nullable <T>);
1423                 }
1424 #endif
1425                 
1426                 // Fixme: wtf is constrained about this
1427                 public static void ConstrainedCopy (Array s, int s_i, Array d, int d_i, int c)
1428                 {
1429                         Copy (s, s_i, d, d_i, c);
1430                 }               
1431 #endif
1432         }
1433
1434
1435 #if NET_2_0
1436                 
1437         internal struct ReadOnlyArrayEnumerator <T> : IEnumerator <T> {
1438                 const int NOT_STARTED = -2;
1439                         
1440                 // this MUST be -1, because we depend on it in move next.
1441                 // we just decr the size, so, 0 - 1 == FINISHED
1442                 const int FINISHED = -1;
1443                         
1444                 ReadOnlyArray <T> array;
1445                 int idx;
1446                         
1447                 internal ReadOnlyArrayEnumerator (ReadOnlyArray<T> array)
1448                 {
1449                         this.array = array;
1450                         idx = NOT_STARTED;
1451                 }
1452                         
1453                 public void Dispose ()
1454                 {
1455                         idx = NOT_STARTED;
1456                 }
1457                         
1458                 public bool MoveNext ()
1459                 {
1460                         if (idx == NOT_STARTED)
1461                                 idx = array.Count;
1462                                 
1463                         return idx != FINISHED && -- idx != FINISHED;
1464                 }
1465                         
1466                 public T Current {
1467                         get {
1468                                 if (idx < 0)
1469                                         throw new InvalidOperationException ();
1470                                         
1471                                 return array [array.Count - 1 - idx];
1472                         }
1473                 }
1474         }
1475
1476         internal class ReadOnlyArray <T> : ICollection <T>, IList <T>, IEnumerable <T>
1477         {
1478                 T[] arr;
1479
1480                 internal ReadOnlyArray (T[] array) {
1481                         arr = array;
1482                 }
1483
1484                 // ICollection<T> interface
1485                 public int Count {
1486                         get {
1487                                 return arr.Length;
1488                         }
1489                 }
1490
1491                 public bool IsReadOnly {
1492                         get {
1493                                 return true;
1494                         }
1495                 }
1496
1497                 public void Add (T item) {
1498                         throw new NotSupportedException ("Collection is read-only");
1499                 }
1500
1501                 public bool Remove (T item) {
1502                         throw new NotSupportedException ("Collection is read-only");
1503                 }
1504
1505                 public void Clear () {
1506                         throw new NotSupportedException ("Collection is read-only");
1507                 }
1508
1509                 public void CopyTo (T[] array, int index) {
1510                         arr.CopyTo (array, index);
1511                 }
1512
1513                 public bool Contains (T item) {
1514                         int length = arr.Length;
1515                         for (int i = 0; i < length; i++) {
1516                                 if (arr [i] == item)
1517                                         return true;
1518                         }
1519                         return false;
1520                 }
1521
1522                 // IList<T> interface
1523                 public T this [int index] {
1524                         get {
1525                                 if (unchecked ((uint) index) >= unchecked ((uint) arr.Length))
1526                                         throw new ArgumentOutOfRangeException ("index");
1527                                 return arr [index];
1528                         } 
1529                         set {
1530                                 if (unchecked ((uint) index) >= unchecked ((uint) arr.Length))
1531                                         throw new ArgumentOutOfRangeException ("index");
1532                                 arr [index] = value;
1533                         }
1534                 }
1535
1536                 public void Insert (int index, T item) {
1537                         throw new NotSupportedException ("Collection is read-only");
1538                 }
1539
1540                 public void RemoveAt (int index) {
1541                         throw new NotSupportedException ("Collection is read-only");
1542                 }
1543
1544                 public int IndexOf (T item) {
1545                         int length = arr.Length;
1546                         for (int i = 0; i < length; i++) {
1547                                 if (arr [i] == item)
1548                                         return i;
1549                         }
1550                         return -1;
1551                 }
1552
1553                 // IEnumerable<T> interface
1554                 public IEnumerator<T> GetEnumerator () {
1555                         return new ReadOnlyArrayEnumerator <T> (this);
1556                 }
1557         }
1558
1559 #endif
1560 }