Array.cs: Fixed BinarySearch when the array is empty (#77030). Added some null check...
[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 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System.Collections;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
36
37 #if NET_2_0
38 using System.Collections.Generic;
39 using System.Runtime.ConstrainedExecution;
40 #endif
41
42 namespace System
43 {
44
45         [Serializable]
46         [MonoTODO ("We are doing way to many double/triple exception checks for the overloaded functions")]
47         [MonoTODO ("Sort overloads parameter checks are VERY inconsistent")]
48         public abstract class Array : ICloneable, ICollection, IList, IEnumerable
49         {
50                 // Constructor
51                 private Array ()
52                 {
53                 }
54
55                 // Properties
56                 public int Length {
57 #if NET_2_0
58                         [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
59 #endif
60                         get {
61                                 int length = this.GetLength (0);
62
63                                 for (int i = 1; i < this.Rank; i++) {
64                                         length *= this.GetLength (i); 
65                                 }
66                                 return length;
67                         }
68                 }
69
70 #if NET_1_1
71                 [ComVisible (false)]
72                 public long LongLength {
73 #if NET_2_0
74                         [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
75 #endif
76                         get { return Length; }
77                 }
78 #endif
79
80                 public int Rank {
81 #if NET_2_0
82                         [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
83 #endif
84                         get {
85                                 return this.GetRank ();
86                         }
87                 }
88
89                 // IList interface
90                 object IList.this [int index] {
91                         get {
92                                 if (unchecked ((uint) index) >= unchecked ((uint) Length))
93                                         throw new ArgumentOutOfRangeException ("index");
94                                 return GetValueImpl (index);
95                         } 
96                         set {
97                                 if (unchecked ((uint) index) >= unchecked ((uint) Length))
98                                         throw new ArgumentOutOfRangeException ("index");
99                                 SetValueImpl (value, index);
100                         }
101                 }
102
103                 int IList.Add (object value)
104                 {
105                         throw new NotSupportedException ();
106                 }
107
108                 void IList.Clear ()
109                 {
110                         Array.Clear (this, this.GetLowerBound (0), this.Length);
111                 }
112
113                 bool IList.Contains (object value)
114                 {
115                         if (this.Rank > 1)
116                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
117
118                         int length = this.Length;
119                         for (int i = 0; i < length; i++) {
120                                 if (Object.Equals (value, this.GetValueImpl (i)))
121                                         return true;
122                         }
123                         return false;
124                 }
125
126 #if NET_2_0
127                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
128 #endif
129                 int IList.IndexOf (object value)
130                 {
131                         if (this.Rank > 1)
132                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
133
134                         int length = this.Length;
135                         for (int i = 0; i < length; i++) {
136                                 if (Object.Equals (value, this.GetValueImpl (i)))
137                                         // array index may not be zero-based.
138                                         // use lower bound
139                                         return i + this.GetLowerBound (0);
140                         }
141
142                         int retVal;
143                         unchecked {
144                                 // lower bound may be MinValue
145                                 retVal = this.GetLowerBound (0) - 1;
146                         }
147
148                         return retVal;
149                 }
150
151                 void IList.Insert (int index, object value)
152                 {
153                         throw new NotSupportedException ();
154                 }
155
156                 void IList.Remove (object value)
157                 {
158                         throw new NotSupportedException ();
159                 }
160
161                 void IList.RemoveAt (int index)
162                 {
163                         throw new NotSupportedException ();
164                 }
165
166                 // InternalCall Methods
167                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
168                 private extern int GetRank ();
169
170                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
171                 public extern int GetLength (int dimension);
172
173 #if NET_1_1
174                 [ComVisible (false)]
175                 public long GetLongLength (int dimension)
176                 {
177                         return GetLength (dimension);
178                 }
179 #endif
180
181 #if NET_2_0
182                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
183 #endif
184                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
185                 public extern int GetLowerBound (int dimension);
186
187                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
188                 public extern object GetValue (params int[] indices);
189
190                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
191                 public extern void SetValue (object value, params int[] indices);
192
193                 // CAUTION! No bounds checking!
194                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
195                 internal extern object GetValueImpl (int pos);
196
197                 // CAUTION! No bounds checking!
198                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
199                 internal extern void SetValueImpl (object value, int pos);
200
201                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
202                 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
203
204                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
205                 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
206
207                 // Properties
208                 int ICollection.Count {
209                         get {
210                                 return Length;
211                         }
212                 }
213
214                 public virtual bool IsSynchronized {
215                         get {
216                                 return false;
217                         }
218                 }
219
220                 public virtual object SyncRoot {
221                         get {
222                                 return this;
223                         }
224                 }
225
226                 public virtual bool IsFixedSize {
227                         get {
228                                 return true;
229                         }
230                 }
231
232                 public virtual bool IsReadOnly {
233                         get {
234                                 return false;
235                         }
236                 }
237
238                 public virtual IEnumerator GetEnumerator ()
239                 {
240                         return new SimpleEnumerator (this);
241                 }
242
243 #if NET_2_0
244                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
245 #endif
246                 public int GetUpperBound (int dimension)
247                 {
248                         return GetLowerBound (dimension) + GetLength (dimension) - 1;
249                 }
250
251                 public object GetValue (int index)
252                 {
253                         if (Rank != 1)
254                                 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
255                         if (index < GetLowerBound (0) || index > GetUpperBound (0))
256                                 throw new IndexOutOfRangeException (Locale.GetText (
257                                         "Index has to be between upper and lower bound of the array."));
258
259                         return GetValueImpl (index - GetLowerBound (0));
260                 }
261
262                 public object GetValue (int index1, int index2)
263                 {
264                         int[] ind = {index1, index2};
265                         return GetValue (ind);
266                 }
267
268                 public object GetValue (int index1, int index2, int index3)
269                 {
270                         int[] ind = {index1, index2, index3};
271                         return GetValue (ind);
272                 }
273
274 #if NET_1_1
275                 [ComVisible (false)]
276                 public object GetValue (long index)
277                 {
278                         if (index < 0 || index > Int32.MaxValue)
279                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
280                                         "Value must be >= 0 and <= Int32.MaxValue."));
281
282                         return GetValue ((int) index);
283                 }
284
285                 [ComVisible (false)]
286                 public object GetValue (long index1, long index2)
287                 {
288                         if (index1 < 0 || index1 > Int32.MaxValue)
289                                 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
290                                         "Value must be >= 0 and <= Int32.MaxValue."));
291
292                         if (index2 < 0 || index2 > Int32.MaxValue)
293                                 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
294                                         "Value must be >= 0 and <= Int32.MaxValue."));
295
296                         return GetValue ((int) index1, (int) index2);
297                 }
298
299                 [ComVisible (false)]
300                 public object GetValue (long index1, long index2, long index3)
301                 {
302                         if (index1 < 0 || index1 > Int32.MaxValue)
303                                 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
304                                         "Value must be >= 0 and <= Int32.MaxValue."));
305
306                         if (index2 < 0 || index2 > Int32.MaxValue)
307                                 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
308                                         "Value must be >= 0 and <= Int32.MaxValue."));
309
310                         if (index3 < 0 || index3 > Int32.MaxValue)
311                                 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
312                                         "Value must be >= 0 and <= Int32.MaxValue."));
313
314                         return GetValue ((int) index1, (int) index2, (int) index3);
315                 }
316
317                 [ComVisible (false)]
318                 public void SetValue (object value, long index)
319                 {
320                         if (index < 0 || index > Int32.MaxValue)
321                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
322                                         "Value must be >= 0 and <= Int32.MaxValue."));
323
324                         SetValue (value, (int) index);
325                 }
326
327                 [ComVisible (false)]
328                 public void SetValue (object value, long index1, long index2)
329                 {
330                         if (index1 < 0 || index1 > Int32.MaxValue)
331                                 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
332                                         "Value must be >= 0 and <= Int32.MaxValue."));
333
334                         if (index2 < 0 || index2 > Int32.MaxValue)
335                                 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
336                                         "Value must be >= 0 and <= Int32.MaxValue."));
337
338                         int[] ind = {(int) index1, (int) index2};
339                         SetValue (value, ind);
340                 }
341
342                 [ComVisible (false)]
343                 public void SetValue (object value, long index1, long index2, long index3)
344                 {
345                         if (index1 < 0 || index1 > Int32.MaxValue)
346                                 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
347                                         "Value must be >= 0 and <= Int32.MaxValue."));
348
349                         if (index2 < 0 || index2 > Int32.MaxValue)
350                                 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
351                                         "Value must be >= 0 and <= Int32.MaxValue."));
352
353                         if (index3 < 0 || index3 > Int32.MaxValue)
354                                 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
355                                         "Value must be >= 0 and <= Int32.MaxValue."));
356
357                         int[] ind = {(int) index1, (int) index2, (int) index3};
358                         SetValue (value, ind);
359                 }
360 #endif
361
362                 public void SetValue (object value, int index)
363                 {
364                         if (Rank != 1)
365                                 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
366                         if (index < GetLowerBound (0) || index > GetUpperBound (0))
367                                 throw new IndexOutOfRangeException (Locale.GetText (
368                                         "Index has to be >= lower bound and <= upper bound of the array."));
369
370                         SetValueImpl (value, index - GetLowerBound (0));
371                 }
372
373                 public void SetValue (object value, int index1, int index2)
374                 {
375                         int[] ind = {index1, index2};
376                         SetValue (value, ind);
377                 }
378
379                 public void SetValue (object value, int index1, int index2, int index3)
380                 {
381                         int[] ind = {index1, index2, index3};
382                         SetValue (value, ind);
383                 }
384
385                 public static Array CreateInstance (Type elementType, int length)
386                 {
387                         int[] lengths = {length};
388
389                         return CreateInstance (elementType, lengths);
390                 }
391
392                 public static Array CreateInstance (Type elementType, int length1, int length2)
393                 {
394                         int[] lengths = {length1, length2};
395
396                         return CreateInstance (elementType, lengths);
397                 }
398
399                 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
400                 {
401                         int[] lengths = {length1, length2, length3};
402
403                         return CreateInstance (elementType, lengths);
404                 }
405
406                 public static Array CreateInstance (Type elementType, int[] lengths)
407                 {
408                         if (elementType == null)
409                                 throw new ArgumentNullException ("elementType");
410                         if (lengths == null)
411                                 throw new ArgumentNullException ("lengths");
412
413                         if (lengths.Length > 255)
414                                 throw new TypeLoadException ();
415
416                         int[] bounds = null;
417
418                         elementType = elementType.UnderlyingSystemType;
419                         if (!elementType.IsSystemType)
420                                 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
421                         
422                         return CreateInstanceImpl (elementType, lengths, bounds);
423                 }
424
425                 public static Array CreateInstance (Type elementType, int[] lengths, int [] bounds)
426                 {
427                         if (elementType == null)
428                                 throw new ArgumentNullException ("elementType");
429                         if (lengths == null)
430                                 throw new ArgumentNullException ("lengths");
431                         if (bounds == null)
432                                 throw new ArgumentNullException ("bounds");
433
434                         elementType = elementType.UnderlyingSystemType;
435                         if (!elementType.IsSystemType)
436                                 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
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 NET_2_0
478                         if (lengths == null)
479                                 throw new ArgumentNullException ("lengths");
480 #endif
481                         return CreateInstance (elementType, GetIntArray (lengths));
482                 }
483
484                 [ComVisible (false)]
485                 public object GetValue (params long [] indices)
486                 {
487 #if NET_2_0
488                         if (indices == null)
489                                 throw new ArgumentNullException ("indices");
490 #endif
491                         return GetValue (GetIntArray (indices));
492                 }
493
494                 [ComVisible (false)]
495                 public void SetValue (object value, params long [] indices)
496                 {
497 #if NET_2_0
498                         if (indices == null)
499                                 throw new ArgumentNullException ("indices");
500 #endif
501                         SetValue (value, GetIntArray (indices));
502                 }
503 #endif
504
505 #if NET_2_0
506                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
507 #endif 
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 (array.Length == 0)
520                                 return -1;
521
522                         if (!(value is IComparable))
523                                 throw new ArgumentException (Locale.GetText ("value does not support IComparable."));
524
525                         return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, null);
526                 }
527
528 #if NET_2_0
529                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
530 #endif
531                 public static int BinarySearch (Array array, object value, IComparer comparer)
532                 {
533                         if (array == null)
534                                 throw new ArgumentNullException ("array");
535
536                         if (array.Rank > 1)
537                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
538
539                         if (array.Length == 0)
540                                 return -1;
541
542                         if ((comparer == null) && (value != null) && !(value is IComparable))
543                                 throw new ArgumentException (Locale.GetText (
544                                         "comparer is null and value does not support IComparable."));
545
546                         return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
547                 }
548
549 #if NET_2_0
550                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
551 #endif
552                 public static int BinarySearch (Array array, int index, int length, object value)
553                 {
554                         if (array == null)
555                                 throw new ArgumentNullException ("array");
556
557                         if (array.Rank > 1)
558                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
559
560                         if (index < array.GetLowerBound (0))
561                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
562                                         "index is less than the lower bound of array."));
563                         if (length < 0)
564                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
565                                         "Value has to be >= 0."));
566                         // re-ordered to avoid possible integer overflow
567                         if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
568                                 throw new ArgumentException (Locale.GetText (
569                                         "index and length do not specify a valid range in array."));
570
571                         if (array.Length == 0)
572                                 return -1;
573
574                         if ((value != null) && (!(value is IComparable)))
575                                 throw new ArgumentException (Locale.GetText (
576                                         "value does not support IComparable"));
577
578                         return DoBinarySearch (array, index, length, value, null);
579                 }
580
581 #if NET_2_0
582                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
583 #endif
584                 public static int BinarySearch (Array array, int index, int length, object value, IComparer comparer)
585                 {
586                         if (array == null)
587                                 throw new ArgumentNullException ("array");
588
589                         if (array.Rank > 1)
590                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
591
592                         if (index < array.GetLowerBound (0))
593                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
594                                         "index is less than the lower bound of array."));
595                         if (length < 0)
596                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
597                                         "Value has to be >= 0."));
598                         // re-ordered to avoid possible integer overflow
599                         if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
600                                 throw new ArgumentException (Locale.GetText (
601                                         "index and length do not specify a valid range in array."));
602
603                         if (array.Length == 0)
604                                 return -1;
605
606                         if ((comparer == null) && (value != null) && !(value is IComparable))
607                                 throw new ArgumentException (Locale.GetText (
608                                         "comparer is null and value does not support IComparable."));
609
610                         return DoBinarySearch (array, index, length, value, comparer);
611                 }
612
613                 static int DoBinarySearch (Array array, int index, int length, object value, IComparer comparer)
614                 {
615                         // cache this in case we need it
616                         if (comparer == null)
617                                 comparer = Comparer.Default;
618
619                         int iMin = index;
620                         // Comment from Tum (tum@veridicus.com):
621                         // *Must* start at index + length - 1 to pass rotor test co2460binarysearch_iioi
622                         int iMax = index + length - 1;
623                         int iCmp = 0;
624                         try {
625                                 while (iMin <= iMax) {
626                                         int iMid = (iMin + iMax) / 2;
627                                         object elt = array.GetValueImpl (iMid);
628
629                                         iCmp = comparer.Compare (elt, value);
630
631                                         if (iCmp == 0)
632                                                 return iMid;
633                                         else if (iCmp > 0)
634                                                 iMax = iMid - 1;
635                                         else
636                                                 iMin = iMid + 1; // compensate for the rounding down
637                                 }
638                         }
639                         catch (Exception e) {
640                                 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
641                         }
642
643                         return ~iMin;
644                 }
645
646 #if NET_2_0
647                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
648 #endif
649                 public static void Clear (Array array, int index, int length)
650                 {
651                         if (array == null)
652                                 throw new ArgumentNullException ("array");
653                         if (length < 0)
654                                 throw new ArgumentOutOfRangeException ("length < 0");
655
656                         int low = array.GetLowerBound (0);
657                         if (index < low)
658                                 throw new IndexOutOfRangeException ("index < lower bound");
659                         index = index - low;
660
661                         // re-ordered to avoid possible integer overflow
662                         if (index > array.Length - length)
663                                 throw new IndexOutOfRangeException ("index + length > size");
664
665                         ClearInternal (array, index, length);
666                 }
667                 
668                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
669                 static extern void ClearInternal (Array a, int index, int count);
670
671                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
672                 public virtual extern object Clone ();
673
674 #if NET_2_0
675                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
676 #endif
677                 public static void Copy (Array sourceArray, Array destinationArray, int length)
678                 {
679                         // need these checks here because we are going to use
680                         // GetLowerBound() on source and dest.
681                         if (sourceArray == null)
682                                 throw new ArgumentNullException ("sourceArray");
683
684                         if (destinationArray == null)
685                                 throw new ArgumentNullException ("destinationArray");
686
687                         Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
688                                 destinationArray.GetLowerBound (0), length);
689                 }
690
691 #if NET_2_0
692                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
693 #endif
694                 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
695                 {
696                         if (sourceArray == null)
697                                 throw new ArgumentNullException ("sourceArray");
698
699                         if (destinationArray == null)
700                                 throw new ArgumentNullException ("destinationArray");
701
702                         if (length < 0)
703                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
704                                         "Value has to be >= 0."));;
705
706                         if (sourceIndex < 0)
707                                 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
708                                         "Value has to be >= 0."));;
709
710                         if (destinationIndex < 0)
711                                 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
712                                         "Value has to be >= 0."));;
713
714                         if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
715                                 return;
716
717                         int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
718                         int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
719
720                         // re-ordered to avoid possible integer overflow
721                         if (source_pos > sourceArray.Length - length || dest_pos > destinationArray.Length - length)
722                                 throw new ArgumentException ("length");
723
724                         if (sourceArray.Rank != destinationArray.Rank)
725                                 throw new RankException (Locale.GetText ("Arrays must be of same size."));
726
727                         Type src_type = sourceArray.GetType ().GetElementType ();
728                         Type dst_type = destinationArray.GetType ().GetElementType ();
729
730                         if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
731                                 for (int i = 0; i < length; i++) {
732                                         Object srcval = sourceArray.GetValueImpl (source_pos + i);
733
734                                         try {
735                                                 destinationArray.SetValueImpl (srcval, dest_pos + i);
736                                         } catch {
737                                                 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
738                                                         (src_type.Equals (typeof (Object))))
739                                                         throw new InvalidCastException ();
740                                                 else
741                                                         throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
742                                                                 "(Types: source={0};  target={1})"), src_type.FullName, dst_type.FullName));
743                                         }
744                                 }
745                         }
746                         else {
747                                 for (int i = length - 1; i >= 0; i--) {
748                                         Object srcval = sourceArray.GetValueImpl (source_pos + i);
749
750                                         try {
751                                                 destinationArray.SetValueImpl (srcval, dest_pos + i);
752                                         } catch {
753                                                 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
754                                                         (src_type.Equals (typeof (Object))))
755                                                         throw new InvalidCastException ();
756                                                 else
757                                                         throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
758                                                                 "(Types: source={0};  target={1})"), src_type.FullName, dst_type.FullName));
759                                         }
760                                 }
761                         }
762                 }
763
764 #if NET_1_1
765 #if NET_2_0
766                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
767 #endif
768                 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
769                                          long destinationIndex, long length)
770                 {
771                         if (sourceArray == null)
772                                 throw new ArgumentNullException ("sourceArray");
773
774                         if (destinationArray == null)
775                                 throw new ArgumentNullException ("destinationArray");
776
777                         if (sourceIndex < Int32.MinValue || sourceIndex > Int32.MaxValue)
778                                 throw new ArgumentOutOfRangeException ("sourceIndex",
779                                         Locale.GetText ("Must be in the Int32 range."));
780
781                         if (destinationIndex < Int32.MinValue || destinationIndex > Int32.MaxValue)
782                                 throw new ArgumentOutOfRangeException ("destinationIndex",
783                                         Locale.GetText ("Must be in the Int32 range."));
784
785                         if (length < 0 || length > Int32.MaxValue)
786                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
787                                         "Value must be >= 0 and <= Int32.MaxValue."));
788
789                         Copy (sourceArray, (int) sourceIndex, destinationArray, (int) destinationIndex, (int) length);
790                 }
791
792 #if NET_2_0
793                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
794 #endif
795                 public static void Copy (Array sourceArray, Array destinationArray, long length)
796                 {
797                         if (length < 0 || length > Int32.MaxValue)
798                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
799                                         "Value must be >= 0 and <= Int32.MaxValue."));
800
801                         Copy (sourceArray, destinationArray, (int) length);
802                 }
803 #endif
804
805 #if NET_2_0
806                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
807 #endif
808                 public static int IndexOf (Array array, object value)
809                 {
810                         if (array == null)
811                                 throw new ArgumentNullException ("array");
812         
813                         return IndexOf (array, value, 0, array.Length);
814                 }
815
816 #if NET_2_0
817                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
818 #endif
819                 public static int IndexOf (Array array, object value, int startIndex)
820                 {
821                         if (array == null)
822                                 throw new ArgumentNullException ("array");
823
824                         return IndexOf (array, value, startIndex, array.Length - startIndex);
825                 }
826
827 #if NET_2_0
828                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
829 #endif
830                 public static int IndexOf (Array array, object value, int startIndex, int count)
831                 {
832                         if (array == null)
833                                 throw new ArgumentNullException ("array");
834
835                         if (array.Rank > 1)
836                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
837
838                         // re-ordered to avoid possible integer overflow
839                         if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
840                                 throw new ArgumentOutOfRangeException ();
841
842                         int max = startIndex + count;
843                         for (int i = startIndex; i < max; i++) {
844                                 if (Object.Equals (value, array.GetValueImpl (i)))
845                                         return i;
846                         }
847
848                         return array.GetLowerBound (0) - 1;
849                 }
850
851                 [MonoTODO]
852                 public void Initialize()
853                 {
854                         //FIXME: We would like to find a compiler that uses
855                         // this method. It looks like this method do nothing
856                         // in C# so no exception is trown by the moment.
857                 }
858
859 #if NET_2_0
860                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
861 #endif
862                 public static int LastIndexOf (Array array, object value)
863                 {
864                         if (array == null)
865                                 throw new ArgumentNullException ("array");
866
867                         return LastIndexOf (array, value, array.Length - 1);
868                 }
869
870 #if NET_2_0
871                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
872 #endif
873                 public static int LastIndexOf (Array array, object value, int startIndex)
874                 {
875                         if (array == null)
876                                 throw new ArgumentNullException ("array");
877
878                         return LastIndexOf (array, value, startIndex, startIndex - array.GetLowerBound (0) + 1);
879                 }
880                 
881 #if NET_2_0
882                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
883 #endif
884                 public static int LastIndexOf (Array array, object value, int startIndex, int count)
885                 {
886                         if (array == null)
887                                 throw new ArgumentNullException ("array");
888         
889                         if (array.Rank > 1)
890                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
891
892                         if (count < 0 || startIndex < array.GetLowerBound (0) ||
893                                 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < array.GetLowerBound (0))
894                                 throw new ArgumentOutOfRangeException ();
895
896                         for (int i = startIndex; i >= startIndex - count + 1; i--) {
897                                 if (Object.Equals (value, array.GetValueImpl (i)))
898                                         return i;
899                         }
900
901                         return array.GetLowerBound (0) - 1;
902                 }
903
904 #if !BOOTSTRAP_WITH_OLDLIB
905                 /* delegate used to swap array elements */
906                 delegate void Swapper (int i, int j);
907 #endif
908
909                 static Swapper get_swapper (Array array)
910                 {
911                         if (array is int[])
912                                 return new Swapper (array.int_swapper);
913                         if (array is double[])
914                                 return new Swapper (array.double_swapper);
915                         if (array is object[]) {
916                                 return new Swapper (array.obj_swapper);
917                         }
918                         return new Swapper (array.slow_swapper);
919                 }
920
921 #if NET_2_0
922                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
923 #endif
924                 public static void Reverse (Array array)
925                 {
926                         if (array == null)
927                                 throw new ArgumentNullException ("array");
928
929                         Reverse (array, array.GetLowerBound (0), array.GetLength (0));
930                 }
931
932 #if NET_2_0
933                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
934 #endif
935                 public static void Reverse (Array array, int index, int length)
936                 {
937                         if (array == null)
938                                 throw new ArgumentNullException ("array");
939
940                         if (array.Rank > 1)
941                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
942
943                         if (index < array.GetLowerBound (0) || length < 0)
944                                 throw new ArgumentOutOfRangeException ();
945
946                         // re-ordered to avoid possible integer overflow
947                         if (index > array.GetUpperBound (0) + 1 - length)
948                                 throw new ArgumentException ();
949
950                         int end = index + length - 1;
951                         object[] oarray = array as object[];
952                         if (oarray != null) {
953                                 while (index < end) {
954                                         object tmp = oarray [index];
955                                         oarray [index] = oarray [end];
956                                         oarray [end] = tmp;
957                                         ++index;
958                                         --end;
959                                 }
960                                 return;
961                         }
962                         int[] iarray = array as int[];
963                         if (iarray != null) {
964                                 while (index < end) {
965                                         int tmp = iarray [index];
966                                         iarray [index] = iarray [end];
967                                         iarray [end] = tmp;
968                                         ++index;
969                                         --end;
970                                 }
971                                 return;
972                         }
973                         double[] darray = array as double[];
974                         if (darray != null) {
975                                 while (index < end) {
976                                         double tmp = darray [index];
977                                         darray [index] = darray [end];
978                                         darray [end] = tmp;
979                                         ++index;
980                                         --end;
981                                 }
982                                 return;
983                         }
984                         // fallback
985                         Swapper swapper = get_swapper (array);
986                         while (index < end) {
987                                 swapper (index, end);
988                                 ++index;
989                                 --end;
990                         }
991                 }
992
993 #if NET_2_0
994                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
995 #endif
996                 public static void Sort (Array array)
997                 {
998                         if (array == null)
999                                 throw new ArgumentNullException ("array");
1000
1001                         Sort (array, null, array.GetLowerBound (0), array.GetLength (0), null);
1002                 }
1003
1004 #if NET_2_0
1005                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1006 #endif
1007                 public static void Sort (Array keys, Array items)
1008                 {
1009                         if (keys == null)
1010                                 throw new ArgumentNullException ("keys");
1011
1012                         Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), null);
1013                 }
1014
1015 #if NET_2_0
1016                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1017 #endif
1018                 public static void Sort (Array array, IComparer comparer)
1019                 {
1020                         if (array == null)
1021                                 throw new ArgumentNullException ("array");
1022
1023                         Sort (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
1024                 }
1025
1026 #if NET_2_0
1027                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1028 #endif
1029                 public static void Sort (Array array, int index, int length)
1030                 {
1031                         Sort (array, null, index, length, null);
1032                 }
1033
1034 #if NET_2_0
1035                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1036 #endif
1037                 public static void Sort (Array keys, Array items, IComparer comparer)
1038                 {
1039                         if (keys == null)
1040                                 throw new ArgumentNullException ("keys");
1041
1042                         Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
1043                 }
1044
1045 #if NET_2_0
1046                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1047 #endif
1048                 public static void Sort (Array keys, Array items, int index, int length)
1049                 {
1050                         Sort (keys, items, index, length, null);
1051                 }
1052
1053 #if NET_2_0
1054                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1055 #endif
1056                 public static void Sort (Array array, int index, int length, IComparer comparer)
1057                 {
1058                         Sort (array, null, index, length, comparer);
1059                 }
1060
1061 #if NET_2_0
1062                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1063 #endif
1064
1065                 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
1066                 {
1067                         if (keys == null)
1068                                 throw new ArgumentNullException ("keys");
1069
1070                         if (keys.Rank > 1 || (items != null && items.Rank > 1))
1071                                 throw new RankException ();
1072
1073                         if (items != null && keys.GetLowerBound (0) != items.GetLowerBound (0))
1074                                 throw new ArgumentException ();
1075
1076                         if (index < keys.GetLowerBound (0))
1077                                 throw new ArgumentOutOfRangeException ("index");
1078
1079                         if (length < 0)
1080                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1081                                         "Value has to be >= 0."));
1082
1083                         if (keys.Length - (index + keys.GetLowerBound (0)) < length || (items != null && index > items.Length - length))
1084                                 throw new ArgumentException ();
1085
1086                         if (length <= 1)
1087                                 return;
1088
1089                         if (comparer == null) {
1090                                 Swapper iswapper;
1091                                 if (items == null)
1092                                         iswapper = null;
1093                                 else 
1094                                         iswapper = get_swapper (items);
1095                                 if (keys is double[]) {
1096                                         combsort (keys as double[], index, length, iswapper);
1097                                         return;
1098                                 }
1099                                 if (keys is int[]) {
1100                                         combsort (keys as int[], index, length, iswapper);
1101                                         return;
1102                                 }
1103                                 if (keys is char[]) {
1104                                         combsort (keys as char[], index, length, iswapper);
1105                                         return;
1106                                 }
1107                         }
1108                         try {
1109                                 int low0 = index;
1110                                 int high0 = index + length - 1;
1111                                 qsort (keys, items, low0, high0, comparer);
1112                         }
1113                         catch (Exception e) {
1114                                 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1115                         }
1116                 }
1117
1118                 /* note, these are instance methods */
1119                 void int_swapper (int i, int j) {
1120                         int[] array = this as int[];
1121                         int val = array [i];
1122                         array [i] = array [j];
1123                         array [j] = val;
1124                 }
1125
1126                 void obj_swapper (int i, int j) {
1127                         object[] array = this as object[];
1128                         object val = array [i];
1129                         array [i] = array [j];
1130                         array [j] = val;
1131                 }
1132
1133                 void slow_swapper (int i, int j) {
1134                         object val = GetValueImpl (i);
1135                         SetValueImpl (GetValue (j), i);
1136                         SetValueImpl (val, j);
1137                 }
1138
1139                 void double_swapper (int i, int j) {
1140                         double[] array = this as double[];
1141                         double val = array [i];
1142                         array [i] = array [j];
1143                         array [j] = val;
1144                 }
1145
1146                 static int new_gap (int gap)
1147                 {
1148                         gap = (gap * 10) / 13;
1149                         if (gap == 9 || gap == 10)
1150                                 return 11;
1151                         if (gap < 1)
1152                                 return 1;
1153                         return gap;
1154                 }
1155
1156                 /* we use combsort because it's fast enough and very small, since we have
1157                  * several specialized versions here.
1158                  */
1159                 static void combsort (double[] array, int start, int size, Swapper swap_items)
1160                 {
1161                         int gap = size;
1162                         while (true) {
1163                                 gap = new_gap (gap);
1164                                 bool swapped = false;
1165                                 int end = start + size - gap;
1166                                 for (int i = start; i < end; i++) {
1167                                         int j = i + gap;
1168                                         if (array [i] > array [j]) {
1169                                                 double val = array [i];
1170                                                 array [i] = array [j];
1171                                                 array [j] = val;
1172                                                 swapped = true;
1173                                                 if (swap_items != null)
1174                                                         swap_items (i, j);
1175                                         }
1176                                 }
1177                                 if (gap == 1 && !swapped)
1178                                         break;
1179                         }
1180                 }
1181
1182                 static void combsort (int[] array, int start, int size, Swapper swap_items)
1183                 {
1184                         int gap = size;
1185                         while (true) {
1186                                 gap = new_gap (gap);
1187                                 bool swapped = false;
1188                                 int end = start + size - gap;
1189                                 for (int i = start; i < end; i++) {
1190                                         int j = i + gap;
1191                                         if (array [i] > array [j]) {
1192                                                 int val = array [i];
1193                                                 array [i] = array [j];
1194                                                 array [j] = val;
1195                                                 swapped = true;
1196                                                 if (swap_items != null)
1197                                                         swap_items (i, j);
1198                                         }
1199                                 }
1200                                 if (gap == 1 && !swapped)
1201                                         break;
1202                         }
1203                 }
1204
1205                 static void combsort (char[] array, int start, int size, Swapper swap_items)
1206                 {
1207                         int gap = size;
1208                         while (true) {
1209                                 gap = new_gap (gap);
1210                                 bool swapped = false;
1211                                 int end = start + size - gap;
1212                                 for (int i = start; i < end; i++) {
1213                                         int j = i + gap;
1214                                         if (array [i] > array [j]) {
1215                                                 char val = array [i];
1216                                                 array [i] = array [j];
1217                                                 array [j] = val;
1218                                                 swapped = true;
1219                                                 if (swap_items != null)
1220                                                         swap_items (i, j);
1221                                         }
1222                                 }
1223                                 if (gap == 1 && !swapped)
1224                                         break;
1225                         }
1226                 }
1227
1228                 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
1229                 {
1230                         if (low0 >= high0)
1231                                 return;
1232
1233                         int low = low0;
1234                         int high = high0;
1235
1236                         object objPivot = keys.GetValueImpl ((low + high) / 2);
1237
1238                         while (low <= high) {
1239                                 // Move the walls in
1240                                 while (low < high0 && compare (keys.GetValueImpl (low), objPivot, comparer) < 0)
1241                                         ++low;
1242                                 while (high > low0 && compare (objPivot, keys.GetValueImpl (high), comparer) < 0)
1243                                         --high;
1244
1245                                 if (low <= high) {
1246                                         swap (keys, items, low, high);
1247                                         ++low;
1248                                         --high;
1249                                 }
1250                         }
1251
1252                         if (low0 < high)
1253                                 qsort (keys, items, low0, high, comparer);
1254                         if (low < high0)
1255                                 qsort (keys, items, low, high0, comparer);
1256                 }
1257
1258                 private static void swap (Array keys, Array items, int i, int j)
1259                 {
1260                         object tmp;
1261
1262                         tmp = keys.GetValueImpl (i);
1263                         keys.SetValueImpl (keys.GetValue (j), i);
1264                         keys.SetValueImpl (tmp, j);
1265
1266                         if (items != null) {
1267                                 tmp = items.GetValueImpl (i);
1268                                 items.SetValueImpl (items.GetValueImpl (j), i);
1269                                 items.SetValueImpl (tmp, j);
1270                         }
1271                 }
1272
1273                 private static int compare (object value1, object value2, IComparer comparer)
1274                 {
1275                         if (value1 == null)
1276                                 return value2 == null ? 0 : -1;
1277                         else if (value2 == null)
1278                                 return 1;
1279                         else if (comparer == null)
1280                                 return ((IComparable) value1).CompareTo (value2);
1281                         else
1282                                 return comparer.Compare (value1, value2);
1283                 }
1284         
1285                 public virtual void CopyTo (Array array, int index)
1286                 {
1287                         if (array == null)
1288                                 throw new ArgumentNullException ("array");
1289
1290                         // The order of these exception checks may look strange,
1291                         // but that's how the microsoft runtime does it.
1292                         if (this.Rank > 1)
1293                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1294                         if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
1295                                 throw new ArgumentException ();
1296                         if (array.Rank > 1)
1297                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1298                         if (index < 0)
1299                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
1300                                         "Value has to be >= 0."));
1301
1302                         Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
1303                 }
1304
1305 #if NET_1_1
1306                 [ComVisible (false)]
1307                 public virtual void CopyTo (Array array, long index)
1308                 {
1309                         if (index < 0 || index > Int32.MaxValue)
1310                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
1311                                         "Value must be >= 0 and <= Int32.MaxValue."));
1312
1313                         CopyTo (array, (int) index);
1314                 }
1315 #endif
1316
1317                 internal class SimpleEnumerator : IEnumerator, ICloneable
1318                 {
1319                         Array enumeratee;
1320                         int currentpos;
1321                         int length;
1322
1323                         public SimpleEnumerator (Array arrayToEnumerate)
1324                         {
1325                                 this.enumeratee = arrayToEnumerate;
1326                                 this.currentpos = -1;
1327                                 this.length = arrayToEnumerate.Length;
1328                         }
1329
1330                         public object Current {
1331                                 get {
1332                                         // Exception messages based on MS implementation
1333                                         if (currentpos < 0 )
1334                                                 throw new InvalidOperationException (Locale.GetText (
1335                                                         "Enumeration has not started."));
1336                                         if  (currentpos >= length)
1337                                                 throw new InvalidOperationException (Locale.GetText (
1338                                                         "Enumeration has already ended"));
1339                                         // Current should not increase the position. So no ++ over here.
1340                                         return enumeratee.GetValueImpl (currentpos);
1341                                 }
1342                         }
1343
1344                         public bool MoveNext()
1345                         {
1346                                 //The docs say Current should throw an exception if last
1347                                 //call to MoveNext returned false. This means currentpos
1348                                 //should be set to length when returning false.
1349                                 if (currentpos < length)
1350                                         currentpos++;
1351                                 if(currentpos < length)
1352                                         return true;
1353                                 else
1354                                         return false;
1355                         }
1356
1357                         public void Reset()
1358                         {
1359                                 currentpos = -1;
1360                         }
1361
1362                         public object Clone ()
1363                         {
1364                                 return MemberwiseClone ();
1365                         }
1366                 }
1367
1368 #if NET_2_0
1369                 public static void Resize<T> (ref T [] array, int newSize)
1370                 {
1371                         Resize<T> (ref array, array == null ? 0 : array.Length, newSize);
1372                 }
1373
1374                 internal static void Resize<T> (ref T[] array, int length, int newSize)
1375                 {
1376                         if (newSize < 0)
1377                                 throw new ArgumentOutOfRangeException ();
1378                         
1379                         if (array == null) {
1380                                 array = new T [newSize];
1381                                 return;
1382                         }
1383                         
1384                         if (array.Length == newSize)
1385                                 return;
1386                         
1387                         T [] a = new T [newSize];
1388                         Array.Copy (array, a, Math.Min (newSize, length));
1389                         array = a;
1390                 }
1391                 
1392                 public static bool TrueForAll <T> (T [] array, Predicate <T> match)
1393                 {
1394                         if (array == null)
1395                                 throw new ArgumentNullException ("array");
1396                         if (match == null)
1397                                 throw new ArgumentNullException ("match");
1398                         
1399                         foreach (T t in array)
1400                                 if (! match (t))
1401                                         return false;
1402                                 
1403                         return true;
1404                 }
1405                 
1406                 public static void ForEach<T> (T [] array, Action <T> action)
1407                 {
1408                         if (array == null)
1409                                 throw new ArgumentNullException ("array");
1410                         if (action == null)
1411                                 throw new ArgumentNullException ("action");
1412                         
1413                         foreach (T t in array)
1414                                 action (t);
1415                 }
1416                 
1417                 public static TOutput[] ConvertAll<TInput, TOutput> (TInput [] array, Converter<TInput, TOutput> converter)
1418                 {
1419                         if (array == null)
1420                                 throw new ArgumentNullException ("array");
1421                         if (converter == null)
1422                                 throw new ArgumentNullException ("converter");
1423                         
1424                         TOutput [] output = new TOutput [array.Length];
1425                         for (int i = 0; i < array.Length; i ++)
1426                                 output [i] = converter (array [i]);
1427                         
1428                         return output;
1429                 }
1430                 
1431                 public static int FindLastIndex<T> (T [] array, Predicate <T> match)
1432                 {
1433                         if (array == null)
1434                                 throw new ArgumentNullException ("array");
1435                         
1436                         return FindLastIndex<T> (array, 0, array.Length, match);
1437                 }
1438                 
1439                 public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
1440                 {
1441                         if (array == null)
1442                                 throw new ArgumentNullException ();
1443                         
1444                         return FindLastIndex<T> (array, startIndex, array.Length - startIndex, match);
1445                 }
1446                 
1447                 public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
1448                 {
1449                         if (array == null)
1450                                 throw new ArgumentNullException ("array");
1451                         if (match == null)
1452                                 throw new ArgumentNullException ("match");
1453                         
1454                         if (startIndex > array.Length || startIndex + count > array.Length)
1455                                 throw new ArgumentOutOfRangeException ();
1456                         
1457                         for (int i = startIndex + count - 1; i >= startIndex; i--)
1458                                 if (match (array [i]))
1459                                         return i;
1460                                 
1461                         return -1;
1462                 }
1463                 
1464                 public static int FindIndex<T> (T [] array, Predicate<T> match)
1465                 {
1466                         if (array == null)
1467                                 throw new ArgumentNullException ("array");
1468                         
1469                         return FindIndex<T> (array, 0, array.Length, match);
1470                 }
1471                 
1472                 public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
1473                 {
1474                         if (array == null)
1475                                 throw new ArgumentNullException ("array");
1476                         
1477                         return FindIndex<T> (array, startIndex, array.Length - startIndex, match);
1478                 }
1479                 
1480                 public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
1481                 {
1482                         if (array == null)
1483                                 throw new ArgumentNullException ("array");
1484                         
1485                         if (match == null)
1486                                 throw new ArgumentNullException ("match");
1487                         
1488                         if (startIndex > array.Length || startIndex + count > array.Length)
1489                                 throw new ArgumentOutOfRangeException ();
1490                         
1491                         for (int i = startIndex; i < startIndex + count; i ++)
1492                                 if (match (array [i]))
1493                                         return i;
1494                                 
1495                         return -1;
1496                 }
1497                 
1498                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1499                 public static int BinarySearch<T> (T [] array, T value)
1500                 {
1501                         if (array == null)
1502                                 throw new ArgumentNullException ("array");
1503                         
1504                         return BinarySearch<T> (array, 0, array.Length, value, null);
1505                 }
1506                 
1507                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1508                 public static int BinarySearch<T> (T [] array, T value, IComparer<T> comparer)
1509                 {
1510                         if (array == null)
1511                                 throw new ArgumentNullException ("array");
1512                         
1513                         return BinarySearch<T> (array, 0, array.Length, value, comparer);
1514                 }
1515                 
1516                 public static int BinarySearch<T> (T [] array, int offset, int length, T value)
1517                 {
1518                         return BinarySearch<T> (array, offset, length, value, null);
1519                 }
1520                 
1521                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1522                 public static int BinarySearch<T> (T [] array, int index, int length, T value, IComparer<T> comparer)
1523                 {
1524                         if (array == null)
1525                                 throw new ArgumentNullException ("array");
1526                         if (index < 0)
1527                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
1528                                         "index is less than the lower bound of array."));
1529                         if (length < 0)
1530                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1531                                         "Value has to be >= 0."));
1532                         // re-ordered to avoid possible integer overflow
1533                         if (index > array.Length - length)
1534                                 throw new ArgumentException (Locale.GetText (
1535                                         "index and length do not specify a valid range in array."));
1536                         if (comparer == null)
1537                                 comparer = Comparer <T>.Default;
1538                         
1539                         int iMin = index;
1540                         int iMax = index + length - 1;
1541                         int iCmp = 0;
1542                         try {
1543                                 while (iMin <= iMax) {
1544                                         int iMid = (iMin + iMax) / 2;
1545                                         iCmp = comparer.Compare (value, array [iMid]);
1546
1547                                         if (iCmp == 0)
1548                                                 return iMid;
1549                                         else if (iCmp < 0)
1550                                                 iMax = iMid - 1;
1551                                         else
1552                                                 iMin = iMid + 1; // compensate for the rounding down
1553                                 }
1554                         } catch (Exception e) {
1555                                 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
1556                         }
1557
1558                         return ~iMin;
1559                 }
1560                 
1561                 public static int IndexOf<T> (T [] array, T value)
1562                 {
1563                         if (array == null)
1564                                 throw new ArgumentNullException ("array");
1565         
1566                         return IndexOf (array, value, 0, array.Length);
1567                 }
1568
1569                 public static int IndexOf<T> (T [] array, T value, int startIndex)
1570                 {
1571                         if (array == null)
1572                                 throw new ArgumentNullException ("array");
1573
1574                         return IndexOf (array, value, startIndex, array.Length - startIndex);
1575                 }
1576
1577                 public static int IndexOf<T> (T [] array, T value, int startIndex, int count)
1578                 {
1579                         if (array == null)
1580                                 throw new ArgumentNullException ("array");
1581                         
1582                         // re-ordered to avoid possible integer overflow
1583                         if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
1584                                 throw new ArgumentOutOfRangeException ();
1585
1586                         int max = startIndex + count;
1587                         for (int i = startIndex; i < max; i++) {
1588                                 if (Object.Equals (value, array [i]))
1589                                         return i;
1590                         }
1591
1592                         return -1;
1593                 }
1594                 
1595                 public static int LastIndexOf<T> (T [] array, T value)
1596                 {
1597                         if (array == null)
1598                                 throw new ArgumentNullException ("array");
1599
1600                         return LastIndexOf (array, value, array.Length - 1);
1601                 }
1602
1603                 public static int LastIndexOf<T> (T [] array, T value, int startIndex)
1604                 {
1605                         if (array == null)
1606                                 throw new ArgumentNullException ("array");
1607
1608                         return LastIndexOf (array, value, startIndex, startIndex + 1);
1609                 }
1610
1611                 public static int LastIndexOf<T> (T [] array, T value, int startIndex, int count)
1612                 {
1613                         if (array == null)
1614                                 throw new ArgumentNullException ("array");
1615                         
1616                         if (count < 0 || startIndex > array.Length || startIndex - count + 1 < 0)
1617                                 throw new ArgumentOutOfRangeException ();
1618
1619                         for (int i = startIndex; i >= startIndex - count + 1; i--) {
1620                                 if (Object.Equals (value, array [i]))
1621                                         return i;
1622                         }
1623
1624                         return -1;
1625                 }
1626                 
1627                 public static T [] FindAll<T> (T [] array, Predicate <T> match)
1628                 {
1629                         if (array == null)
1630                                 throw new ArgumentNullException ("array");
1631
1632                         if (match == null)
1633                                 throw new ArgumentNullException ("match");
1634                         
1635                         int pos = 0;
1636                         T [] d = new T [array.Length];
1637                         foreach (T t in array)
1638                                 if (match (t))
1639                                         d [pos++] = t;
1640                         
1641                         Resize <T> (ref d, pos);
1642                         return d;
1643                 }
1644
1645                 public static bool Exists<T> (T [] array, Predicate <T> match)
1646                 {
1647                         if (array == null)
1648                                 throw new ArgumentNullException ("array");
1649
1650                         if (match == null)
1651                                 throw new ArgumentNullException ("match");
1652                         
1653                         foreach (T t in array)
1654                                 if (match (t))
1655                                         return true;
1656                         return false;
1657                 }
1658
1659                 public static IList<T> AsReadOnly<T> (T[] array)
1660                 {
1661                         if (array == null)
1662                                 throw new ArgumentNullException ("array");
1663                         return new ReadOnlyArray<T> (array);
1664                 }
1665
1666                 public static Nullable<T> Find<T> (T [] array, Predicate<T> match)
1667                 {
1668                         if (array == null)
1669                                 throw new ArgumentNullException ("array");
1670
1671                         if (match == null)
1672                                 throw new ArgumentNullException ("match");
1673                         
1674                         foreach (T t in array)
1675                                 if (match (t))
1676                                         return new Nullable <T> (t);
1677                                 
1678                         return default (Nullable <T>);
1679                 }
1680                 
1681                 public static Nullable<T> FindLast<T> (T [] array, Predicate <T> match)
1682                 {
1683                         if (array == null)
1684                                 throw new ArgumentNullException ("array");
1685
1686                         if (match == null)
1687                                 throw new ArgumentNullException ("match");
1688                         
1689                         for (int i = array.Length - 1; i >= 0; i--)
1690                                 if (match (array [i]))
1691                                         return new Nullable <T> (array [i]);
1692                                 
1693                         return default (Nullable <T>);
1694                 }
1695
1696                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]           
1697                 //
1698                 // The constrained copy should guarantee that if there is an exception thrown
1699                 // during the copy, the destination array remains unchanged.
1700                 // This is related to System.Runtime.Reliability.CER
1701                 public static void ConstrainedCopy (Array s, int s_i, Array d, int d_i, int c)
1702                 {
1703                         Copy (s, s_i, d, d_i, c);
1704                 }
1705 #endif 
1706
1707 #if NET_2_0
1708                 //
1709                 // This is used internally by the runtime to represent arrays; see #74953.
1710                 //
1711                 // Note that you normally can't derive a class from System.Array (CS0644),
1712                 // but GMCS makes an exception here for all classes which are nested inside
1713                 // System.Array.
1714                 //
1715                 internal class InternalArray<T> : Array, IList<T>
1716                 {
1717                         new public IEnumerator<T> GetEnumerator ()
1718                         {
1719                                 return new InternalEnumerator (this);
1720                         }
1721
1722                         public int Count {
1723                                 get {
1724                                         return Length;
1725                                 }
1726                         }
1727
1728                         bool ICollection<T>.IsReadOnly {
1729                                 get {
1730                                         return true;
1731                                 }
1732                         }
1733
1734                         void ICollection<T>.Clear ()
1735                         {
1736                                 throw new NotSupportedException ("Collection is read-only");
1737                         }
1738
1739                         void ICollection<T>.Add (T item)
1740                         {
1741                                 throw new NotSupportedException ("Collection is read-only");
1742                         }
1743
1744                         bool ICollection<T>.Remove (T item)
1745                         {
1746                                 throw new NotSupportedException ("Collection is read-only");
1747                         }
1748
1749                         public bool Contains (T item)
1750                         {
1751                                 if (this.Rank > 1)
1752                                         throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1753
1754                                 int length = this.Length;
1755                                 for (int i = 0; i < length; i++) {
1756                                         T value;
1757                                         GetGenericValueImpl (i, out value);
1758                                         if (item.Equals (value))
1759                                                 return true;
1760                                 }
1761
1762                                 return false;
1763                         }
1764
1765                         public void CopyTo (T[] array, int index)
1766                         {
1767                                 if (array == null)
1768                                         throw new ArgumentNullException ("array");
1769
1770                                 // The order of these exception checks may look strange,
1771                                 // but that's how the microsoft runtime does it.
1772                                 if (this.Rank > 1)
1773                                         throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1774                                 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
1775                                         throw new ArgumentException ();
1776                                 if (array.Rank > 1)
1777                                         throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1778                                 if (index < 0)
1779                                         throw new ArgumentOutOfRangeException (
1780                                                 "index", Locale.GetText ("Value has to be >= 0."));
1781
1782                                 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
1783                         }
1784
1785                         new public T this [int index] {
1786                                 get {
1787                                         if (unchecked ((uint) index) >= unchecked ((uint) Length))
1788                                                 throw new ArgumentOutOfRangeException ("index");
1789
1790                                         T value;
1791                                         GetGenericValueImpl (index, out value);
1792                                         return value;
1793                                 }
1794
1795                                 set {
1796                                         throw new NotSupportedException ("Collection is read-only");
1797                                 }
1798                         }
1799
1800                         void IList<T>.Insert (int index, T item)
1801                         {
1802                                 throw new NotSupportedException ("Collection is read-only");
1803                         }
1804
1805                         void IList<T>.RemoveAt (int index)
1806                         {
1807                                 throw new NotSupportedException ("Collection is read-only");
1808                         }
1809
1810                         public int IndexOf (T item)
1811                         {
1812                                 if (this.Rank > 1)
1813                                         throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1814
1815                                 int length = this.Length;
1816                                 for (int i = 0; i < length; i++) {
1817                                         T value;
1818                                         GetGenericValueImpl (i, out value);
1819                                         if (item.Equals (value))
1820                                                 // array index may not be zero-based.
1821                                                 // use lower bound
1822                                                 return i + this.GetLowerBound (0);
1823                                 }
1824
1825                                 int retVal;
1826                                 unchecked {
1827                                         // lower bound may be MinValue
1828                                         retVal = this.GetLowerBound (0) - 1;
1829                                 }
1830
1831                                 return retVal;
1832                         }
1833
1834                         // CAUTION! No bounds checking!
1835                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
1836                         protected extern void GetGenericValueImpl (int pos, out T value);
1837
1838                         internal struct InternalEnumerator : IEnumerator<T>
1839                         {
1840                                 const int NOT_STARTED = -2;
1841                         
1842                                 // this MUST be -1, because we depend on it in move next.
1843                                 // we just decr the size, so, 0 - 1 == FINISHED
1844                                 const int FINISHED = -1;
1845                         
1846                                 InternalArray<T> array;
1847                                 int idx;
1848
1849                                 internal InternalEnumerator (InternalArray<T> array)
1850                                 {
1851                                         this.array = array;
1852                                         idx = NOT_STARTED;
1853                                 }
1854
1855                                 public void Dispose ()
1856                                 {
1857                                         idx = NOT_STARTED;
1858                                 }
1859
1860                                 public bool MoveNext ()
1861                                 {
1862                                         if (idx == NOT_STARTED)
1863                                                 idx = array.Length;
1864
1865                                         return idx != FINISHED && -- idx != FINISHED;
1866                                 }
1867
1868                                 public T Current {
1869                                         get {
1870                                                 if (idx < 0)
1871                                                         throw new InvalidOperationException ();
1872
1873                                                 return array [array.Length - 1 - idx];
1874                                         }
1875                                 }
1876
1877                                 void IEnumerator.Reset ()
1878                                 {
1879                                         throw new NotImplementedException ();
1880                                 }
1881
1882                                 object IEnumerator.Current {
1883                                         get {
1884                                                 return Current;
1885                                         }
1886                                 }
1887                         }
1888                 }
1889 #endif
1890         }
1891
1892 #if NET_2_0
1893
1894         internal struct ReadOnlyArrayEnumerator <T> : IEnumerator <T> {
1895                 const int NOT_STARTED = -2;
1896                         
1897                 // this MUST be -1, because we depend on it in move next.
1898                 // we just decr the size, so, 0 - 1 == FINISHED
1899                 const int FINISHED = -1;
1900                         
1901                 ReadOnlyArray <T> array;
1902                 int idx;
1903                         
1904                 internal ReadOnlyArrayEnumerator (ReadOnlyArray<T> array)
1905                 {
1906                         this.array = array;
1907                         idx = NOT_STARTED;
1908                 }
1909                         
1910                 public void Dispose ()
1911                 {
1912                         idx = NOT_STARTED;
1913                 }
1914                         
1915                 public bool MoveNext ()
1916                 {
1917                         if (idx == NOT_STARTED)
1918                                 idx = array.Count;
1919                                 
1920                         return idx != FINISHED && -- idx != FINISHED;
1921                 }
1922                         
1923                 public T Current {
1924                         get {
1925                                 if (idx < 0)
1926                                         throw new InvalidOperationException ();
1927                                         
1928                                 return array [array.Count - 1 - idx];
1929                         }
1930                 }
1931
1932                 void IEnumerator.Reset ()
1933                 {
1934                         throw new NotImplementedException ();
1935                 }
1936
1937                 object IEnumerator.Current {
1938                         get {
1939                                 return Current;
1940                         }
1941                 }
1942         }
1943
1944         internal class ReadOnlyArray <T> : ICollection <T>, IList <T>, IEnumerable <T>
1945         {
1946                 T[] arr;
1947
1948                 internal ReadOnlyArray (T[] array) {
1949                         arr = array;
1950                 }
1951
1952                 // ICollection<T> interface
1953                 public int Count {
1954                         get {
1955                                 return arr.Length;
1956                         }
1957                 }
1958
1959                 public bool IsReadOnly {
1960                         get {
1961                                 return true;
1962                         }
1963                 }
1964
1965                 public void Add (T item) {
1966                         throw new NotSupportedException ("Collection is read-only");
1967                 }
1968
1969                 public bool Remove (T item) {
1970                         throw new NotSupportedException ("Collection is read-only");
1971                 }
1972
1973                 public void Clear () {
1974                         throw new NotSupportedException ("Collection is read-only");
1975                 }
1976
1977                 public void CopyTo (T[] array, int index) {
1978                         arr.CopyTo (array, index);
1979                 }
1980
1981                 public bool Contains (T item) {
1982                         return Array.IndexOf <T> (arr, item) != -1;
1983                 }
1984
1985                 // IList<T> interface
1986                 public T this [int index] {
1987                         get {
1988                                 if (unchecked ((uint) index) >= unchecked ((uint) arr.Length))
1989                                         throw new ArgumentOutOfRangeException ("index");
1990                                 return arr [index];
1991                         } 
1992                         set {
1993                                 if (unchecked ((uint) index) >= unchecked ((uint) arr.Length))
1994                                         throw new ArgumentOutOfRangeException ("index");
1995                                 arr [index] = value;
1996                         }
1997                 }
1998
1999                 public void Insert (int index, T item) {
2000                         throw new NotSupportedException ("Collection is read-only");
2001                 }
2002
2003                 public void RemoveAt (int index) {
2004                         throw new NotSupportedException ("Collection is read-only");
2005                 }
2006
2007                 public int IndexOf (T item) {
2008                         return Array.IndexOf <T> (arr, item);
2009                 }
2010
2011                 // IEnumerable<T> interface
2012                 public IEnumerator<T> GetEnumerator () {
2013                         return new ReadOnlyArrayEnumerator <T> (this);
2014                 }
2015
2016                 IEnumerator IEnumerable.GetEnumerator () {
2017                         return new ReadOnlyArrayEnumerator <T> (this);
2018                 }
2019         }
2020 #endif
2021
2022 #if BOOTSTRAP_WITH_OLDLIB
2023         /* delegate used to swap array elements, keep defined outside Array */
2024         delegate void Swapper (int i, int j);
2025 #endif
2026 }