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