[corlib] Use array managed parts from corert to fix bugs in sorting and arguments...
[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 //   Jeffrey Stedfast (fejj@novell.com)
10 //   Marek Safar (marek.safar@gmail.com)
11 //
12 // (C) 2001-2003 Ximian, Inc.  http://www.ximian.com
13 // Copyright (C) 2004-2011 Novell, Inc (http://www.novell.com)
14 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
39
40 using System.Collections.Generic;
41 using System.Collections.ObjectModel;
42 using System.Runtime.ConstrainedExecution;
43 #if !FULL_AOT_RUNTIME
44 using System.Reflection.Emit;
45 #endif
46
47 namespace System
48 {
49         public abstract partial class Array
50         {
51                 // Constructor
52                 private Array ()
53                 {
54                 }
55
56                 /*
57                  * These methods are used to implement the implicit generic interfaces 
58                  * implemented by arrays in NET 2.0.
59                  * Only make those methods generic which really need it, to avoid
60                  * creating useless instantiations.
61                  */
62                 internal int InternalArray__ICollection_get_Count ()
63                 {
64                         return Length;
65                 }
66
67                 internal bool InternalArray__ICollection_get_IsReadOnly ()
68                 {
69                         return true;
70                 }
71
72                 internal IEnumerator<T> InternalArray__IEnumerable_GetEnumerator<T> ()
73                 {
74                         return new InternalEnumerator<T> (this);
75                 }
76
77                 internal void InternalArray__ICollection_Clear ()
78                 {
79                         throw new NotSupportedException ("Collection is read-only");
80                 }
81
82                 internal void InternalArray__ICollection_Add<T> (T item)
83                 {
84                         throw new NotSupportedException ("Collection is of a fixed size");
85                 }
86
87                 internal bool InternalArray__ICollection_Remove<T> (T item)
88                 {
89                         throw new NotSupportedException ("Collection is of a fixed size");
90                 }
91
92                 internal bool InternalArray__ICollection_Contains<T> (T item)
93                 {
94                         if (this.Rank > 1)
95                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
96
97                         int length = this.Length;
98                         for (int i = 0; i < length; i++) {
99                                 T value;
100                                 GetGenericValueImpl (i, out value);
101                                 if (item == null){
102                                         if (value == null) {
103                                                 return true;
104                                         }
105
106                                         continue;
107                                 }
108
109                                 if (item.Equals (value)) {
110                                         return true;
111                                 }
112                         }
113
114                         return false;
115                 }
116
117                 int IList.IndexOf (object value)
118                 {
119                         if (this.Rank > 1)
120                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
121
122                         int length = this.Length;
123                         for (int i = 0; i < length; i++) {
124                                 if (Object.Equals (this.GetValueImpl (i), value))
125                                         // array index may not be zero-based.
126                                         // use lower bound
127                                         return i + this.GetLowerBound (0);
128                         }
129
130                         unchecked {
131                                 // lower bound may be MinValue
132                                 return this.GetLowerBound (0) - 1;
133                         }
134                 }
135
136                 internal void InternalArray__ICollection_CopyTo<T> (T[] array, int index)
137                 {
138                         if (array == null)
139                                 throw new ArgumentNullException ("array");
140
141                         // The order of these exception checks may look strange,
142                         // but that's how the microsoft runtime does it.
143                         if (this.Rank > 1)
144                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
145                         if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
146                                 throw new ArgumentException ("Destination array was not long " +
147                                         "enough. Check destIndex and length, and the array's " +
148                                         "lower bounds.");
149                         if (array.Rank > 1)
150                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
151                         if (index < 0)
152                                 throw new ArgumentOutOfRangeException (
153                                         "index", Locale.GetText ("Value has to be >= 0."));
154
155                         Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
156                 }
157
158                 internal T InternalArray__IReadOnlyList_get_Item<T> (int index)
159                 {
160                         if (unchecked ((uint) index) >= unchecked ((uint) Length))
161                                 throw new ArgumentOutOfRangeException ("index");
162
163                         T value;
164                         GetGenericValueImpl (index, out value);
165                         return value;
166                 }
167
168                 internal int InternalArray__IReadOnlyCollection_get_Count ()
169                 {
170                         return Length;
171                 }
172
173                 internal void InternalArray__Insert<T> (int index, T item)
174                 {
175                         throw new NotSupportedException ("Collection is of a fixed size");
176                 }
177
178                 internal void InternalArray__RemoveAt (int index)
179                 {
180                         throw new NotSupportedException ("Collection is of a fixed size");
181                 }
182
183                 internal int InternalArray__IndexOf<T> (T item)
184                 {
185                         if (this.Rank > 1)
186                                 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
187
188                         int length = this.Length;
189                         for (int i = 0; i < length; i++) {
190                                 T value;
191                                 GetGenericValueImpl (i, out value);
192                                 if (item == null){
193                                         if (value == null)
194                                                 return i + this.GetLowerBound (0);
195
196                                         continue;
197                                 }
198                                 if (value.Equals (item))
199                                         // array index may not be zero-based.
200                                         // use lower bound
201                                         return i + this.GetLowerBound (0);
202                         }
203
204                         unchecked {
205                                 // lower bound may be MinValue
206                                 return this.GetLowerBound (0) - 1;
207                         }
208                 }
209
210                 internal T InternalArray__get_Item<T> (int index)
211                 {
212                         if (unchecked ((uint) index) >= unchecked ((uint) Length))
213                                 throw new ArgumentOutOfRangeException ("index");
214
215                         T value;
216                         GetGenericValueImpl (index, out value);
217                         return value;
218                 }
219
220                 internal void InternalArray__set_Item<T> (int index, T item)
221                 {
222                         if (unchecked ((uint) index) >= unchecked ((uint) Length))
223                                 throw new ArgumentOutOfRangeException ("index");
224
225                         object[] oarray = this as object [];
226                         if (oarray != null) {
227                                 oarray [index] = (object)item;
228                                 return;
229                         }
230                         SetGenericValueImpl (index, ref item);
231                 }
232
233                 // CAUTION! No bounds checking!
234                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
235                 internal extern void GetGenericValueImpl<T> (int pos, out T value);
236
237                 // CAUTION! No bounds checking!
238                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
239                 internal extern void SetGenericValueImpl<T> (int pos, ref T value);
240
241                 internal struct InternalEnumerator<T> : IEnumerator<T>
242                 {
243                         const int NOT_STARTED = -2;
244                         
245                         // this MUST be -1, because we depend on it in move next.
246                         // we just decr the size, so, 0 - 1 == FINISHED
247                         const int FINISHED = -1;
248                         
249                         Array array;
250                         int idx;
251
252                         internal InternalEnumerator (Array array)
253                         {
254                                 this.array = array;
255                                 idx = NOT_STARTED;
256                         }
257
258                         public void Dispose ()
259                         {
260                                 idx = NOT_STARTED;
261                         }
262
263                         public bool MoveNext ()
264                         {
265                                 if (idx == NOT_STARTED)
266                                         idx = array.Length;
267
268                                 return idx != FINISHED && -- idx != FINISHED;
269                         }
270
271                         public T Current {
272                                 get {
273                                         if (idx == NOT_STARTED)
274                                                 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
275                                         if (idx == FINISHED)
276                                                 throw new InvalidOperationException ("Enumeration already finished");
277
278                                         return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
279                                 }
280                         }
281
282                         void IEnumerator.Reset ()
283                         {
284                                 idx = NOT_STARTED;
285                         }
286
287                         object IEnumerator.Current {
288                                 get {
289                                         return Current;
290                                 }
291                         }
292                 }
293
294                 // Properties
295                 public int Length {
296                         [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
297                         get {
298                                 int length = this.GetLength (0);
299
300                                 for (int i = 1; i < this.Rank; i++) {
301                                         length *= this.GetLength (i); 
302                                 }
303                                 return length;
304                         }
305                 }
306
307                 public int Rank {
308                         [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
309                         get {
310                                 return this.GetRank ();
311                         }
312                 }
313
314                 // InternalCall Methods
315                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
316                 extern int GetRank ();
317
318                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
319                 public extern int GetLength (int dimension);
320
321                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
322                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
323                 public extern int GetLowerBound (int dimension);
324
325                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
326                 public extern object GetValue (params int[] indices);
327
328                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
329                 public extern void SetValue (object value, params int[] indices);
330
331                 // CAUTION! No bounds checking!
332                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
333                 internal extern object GetValueImpl (int pos);
334
335                 // CAUTION! No bounds checking!
336                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
337                 internal extern void SetValueImpl (object value, int pos);
338
339                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
340                 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
341
342                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
343                 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
344
345                 public bool IsReadOnly {
346                         get {
347                                 return false;
348                         }
349                 }
350
351                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
352                 public int GetUpperBound (int dimension)
353                 {
354                         return GetLowerBound (dimension) + GetLength (dimension) - 1;
355                 }
356
357                 public object GetValue (int index)
358                 {
359                         if (Rank != 1)
360                                 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
361                         if (index < GetLowerBound (0) || index > GetUpperBound (0))
362                                 throw new IndexOutOfRangeException (Locale.GetText (
363                                         "Index has to be between upper and lower bound of the array."));
364
365                         return GetValueImpl (index - GetLowerBound (0));
366                 }
367
368                 public object GetValue (int index1, int index2)
369                 {
370                         int[] ind = {index1, index2};
371                         return GetValue (ind);
372                 }
373
374                 public object GetValue (int index1, int index2, int index3)
375                 {
376                         int[] ind = {index1, index2, index3};
377                         return GetValue (ind);
378                 }
379
380                 [ComVisible (false)]
381                 public void SetValue (object value, long index)
382                 {
383                         if (index < 0 || index > Int32.MaxValue)
384                                 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
385                                         "Value must be >= 0 and <= Int32.MaxValue."));
386
387                         SetValue (value, (int) index);
388                 }
389
390                 [ComVisible (false)]
391                 public void SetValue (object value, long index1, long index2)
392                 {
393                         if (index1 < 0 || index1 > Int32.MaxValue)
394                                 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
395                                         "Value must be >= 0 and <= Int32.MaxValue."));
396
397                         if (index2 < 0 || index2 > Int32.MaxValue)
398                                 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
399                                         "Value must be >= 0 and <= Int32.MaxValue."));
400
401                         int[] ind = {(int) index1, (int) index2};
402                         SetValue (value, ind);
403                 }
404
405                 [ComVisible (false)]
406                 public void SetValue (object value, long index1, long index2, long index3)
407                 {
408                         if (index1 < 0 || index1 > Int32.MaxValue)
409                                 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
410                                         "Value must be >= 0 and <= Int32.MaxValue."));
411
412                         if (index2 < 0 || index2 > Int32.MaxValue)
413                                 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
414                                         "Value must be >= 0 and <= Int32.MaxValue."));
415
416                         if (index3 < 0 || index3 > Int32.MaxValue)
417                                 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
418                                         "Value must be >= 0 and <= Int32.MaxValue."));
419
420                         int[] ind = {(int) index1, (int) index2, (int) index3};
421                         SetValue (value, ind);
422                 }
423
424                 public void SetValue (object value, int index)
425                 {
426                         if (Rank != 1)
427                                 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
428                         if (index < GetLowerBound (0) || index > GetUpperBound (0))
429                                 throw new IndexOutOfRangeException (Locale.GetText (
430                                         "Index has to be >= lower bound and <= upper bound of the array."));
431
432                         SetValueImpl (value, index - GetLowerBound (0));
433                 }
434
435                 public void SetValue (object value, int index1, int index2)
436                 {
437                         int[] ind = {index1, index2};
438                         SetValue (value, ind);
439                 }
440
441                 public void SetValue (object value, int index1, int index2, int index3)
442                 {
443                         int[] ind = {index1, index2, index3};
444                         SetValue (value, ind);
445                 }
446
447                 internal static Array UnsafeCreateInstance(Type elementType, int[] lengths, int[] lowerBounds)
448                 {
449                         return CreateInstance(elementType, lengths, lowerBounds);
450                 }
451
452                 internal static Array UnsafeCreateInstance (Type elementType, int length1, int length2)
453                 {
454                         return CreateInstance (elementType, length1, length2);
455                 }
456
457                 internal static Array UnsafeCreateInstance (Type elementType, params int[] lengths)
458                 {
459                         return CreateInstance(elementType, lengths);
460                 }
461
462                 public static Array CreateInstance (Type elementType, int length)
463                 {
464                         int[] lengths = {length};
465
466                         return CreateInstance (elementType, lengths);
467                 }
468
469                 public static Array CreateInstance (Type elementType, int length1, int length2)
470                 {
471                         int[] lengths = {length1, length2};
472
473                         return CreateInstance (elementType, lengths);
474                 }
475
476                 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
477                 {
478                         int[] lengths = {length1, length2, length3};
479
480                         return CreateInstance (elementType, lengths);
481                 }
482
483                 public static Array CreateInstance (Type elementType, params int[] lengths)
484                 {
485                         if (elementType == null)
486                                 throw new ArgumentNullException ("elementType");
487                         if (lengths == null)
488                                 throw new ArgumentNullException ("lengths");
489
490                         if (lengths.Length > 255)
491                                 throw new TypeLoadException ();
492
493                         int[] bounds = null;
494
495                         elementType = elementType.UnderlyingSystemType as RuntimeType;
496                         if (elementType == null)
497                                 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
498                         if (elementType.Equals (typeof (void)))
499                                 throw new NotSupportedException ("Array type can not be void");
500                         if (elementType.ContainsGenericParameters)
501                                 throw new NotSupportedException ("Array type can not be an open generic type");
502 #if !FULL_AOT_RUNTIME
503                         if ((elementType is TypeBuilder) && !(elementType as TypeBuilder).IsCreated ())
504                                 throw new NotSupportedException ("Can't create an array of the unfinished type '" + elementType + "'.");
505 #endif
506                         
507                         return CreateInstanceImpl (elementType, lengths, bounds);
508                 }
509
510                 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
511                 {
512                         if (elementType == null)
513                                 throw new ArgumentNullException ("elementType");
514                         if (lengths == null)
515                                 throw new ArgumentNullException ("lengths");
516                         if (lowerBounds == null)
517                                 throw new ArgumentNullException ("lowerBounds");
518
519                         elementType = elementType.UnderlyingSystemType as RuntimeType;
520                         if (elementType == null)
521                                 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
522                         if (elementType.Equals (typeof (void)))
523                                 throw new NotSupportedException ("Array type can not be void");
524                         if (elementType.ContainsGenericParameters)
525                                 throw new NotSupportedException ("Array type can not be an open generic type");
526
527                         if (lengths.Length < 1)
528                                 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
529
530                         if (lengths.Length != lowerBounds.Length)
531                                 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
532
533                         for (int j = 0; j < lowerBounds.Length; j ++) {
534                                 if (lengths [j] < 0)
535                                         throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
536                                                 "Each value has to be >= 0."));
537                                 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
538                                         throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
539                                                 "Length + bound must not exceed Int32.MaxValue."));
540                         }
541
542                         if (lengths.Length > 255)
543                                 throw new TypeLoadException ();
544
545                         return CreateInstanceImpl (elementType, lengths, lowerBounds);
546                 }
547
548                 static int [] GetIntArray (long [] values)
549                 {
550                         int len = values.Length;
551                         int [] ints = new int [len];
552                         for (int i = 0; i < len; i++) {
553                                 long current = values [i];
554                                 if (current < 0 || current > (long) Int32.MaxValue)
555                                         throw new ArgumentOutOfRangeException ("values", Locale.GetText (
556                                                 "Each value has to be >= 0 and <= Int32.MaxValue."));
557
558                                 ints [i] = (int) current;
559                         }
560                         return ints;
561                 }
562
563                 public static Array CreateInstance (Type elementType, params long [] lengths)
564                 {
565                         if (lengths == null)
566                                 throw new ArgumentNullException ("lengths");
567                         return CreateInstance (elementType, GetIntArray (lengths));
568                 }
569
570                 [ComVisible (false)]
571                 public void SetValue (object value, params long [] indices)
572                 {
573                         if (indices == null)
574                                 throw new ArgumentNullException ("indices");
575                         SetValue (value, GetIntArray (indices));
576                 }
577
578                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
579                 public static void Clear (Array array, int index, int length)
580                 {
581                         if (array == null)
582                                 throw new ArgumentNullException ("array");
583                         if (length < 0)
584                                 throw new IndexOutOfRangeException ("length < 0");
585
586                         int low = array.GetLowerBound (0);
587                         if (index < low)
588                                 throw new IndexOutOfRangeException ("index < lower bound");
589                         index = index - low;
590
591                         // re-ordered to avoid possible integer overflow
592                         if (index > array.Length - length)
593                                 throw new IndexOutOfRangeException ("index + length > size");
594
595                         ClearInternal (array, index, length);
596                 }
597                 
598                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
599                 static extern void ClearInternal (Array a, int index, int count);
600
601                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
602                 public static void Copy (Array sourceArray, Array destinationArray, int length)
603                 {
604                         // need these checks here because we are going to use
605                         // GetLowerBound() on source and dest.
606                         if (sourceArray == null)
607                                 throw new ArgumentNullException ("sourceArray");
608
609                         if (destinationArray == null)
610                                 throw new ArgumentNullException ("destinationArray");
611
612                         Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
613                                 destinationArray.GetLowerBound (0), length);
614                 }
615
616                 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
617                 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
618                 {
619                         if (sourceArray == null)
620                                 throw new ArgumentNullException ("sourceArray");
621
622                         if (destinationArray == null)
623                                 throw new ArgumentNullException ("destinationArray");
624
625                         if (length < 0)
626                                 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
627                                         "Value has to be >= 0."));;
628
629                         if (sourceArray.Rank != destinationArray.Rank)
630                                 throw new RankException(SR.Rank_MultiDimNotSupported);
631
632                         if (sourceIndex < 0)
633                                 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
634                                         "Value has to be >= 0."));;
635
636                         if (destinationIndex < 0)
637                                 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
638                                         "Value has to be >= 0."));;
639
640                         if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
641                                 return;
642
643                         int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
644                         int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
645
646                         if (dest_pos < 0)
647                                 throw new ArgumentOutOfRangeException ("destinationIndex", "Index was less than the array's lower bound in the first dimension.");
648
649                         // re-ordered to avoid possible integer overflow
650                         if (source_pos > sourceArray.Length - length)
651                                 throw new ArgumentException ("length");
652
653                         if (dest_pos > destinationArray.Length - length) {
654                                 string msg = "Destination array was not long enough. Check " +
655                                         "destIndex and length, and the array's lower bounds";
656                                 throw new ArgumentException (msg, string.Empty);
657                         }
658
659                         Type src_type = sourceArray.GetType ().GetElementType ();
660                         Type dst_type = destinationArray.GetType ().GetElementType ();
661
662                         if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
663                                 for (int i = 0; i < length; i++) {
664                                         Object srcval = sourceArray.GetValueImpl (source_pos + i);
665
666                                         try {
667                                                 destinationArray.SetValueImpl (srcval, dest_pos + i);
668                                         } catch (ArgumentException) {
669                                                 throw CreateArrayTypeMismatchException ();
670                                         } catch {
671                                                 if (CanAssignArrayElement (src_type, dst_type))
672                                                         throw;
673
674                                                 throw CreateArrayTypeMismatchException ();
675                                         }
676                                 }
677                         }
678                         else {
679                                 for (int i = length - 1; i >= 0; i--) {
680                                         Object srcval = sourceArray.GetValueImpl (source_pos + i);
681
682                                         try {
683                                                 destinationArray.SetValueImpl (srcval, dest_pos + i);
684                                         } catch (ArgumentException) {
685                                                 throw CreateArrayTypeMismatchException ();
686                                         } catch {
687                                                 if (CanAssignArrayElement (src_type, dst_type))
688                                                         throw;
689
690                                                 throw CreateArrayTypeMismatchException ();
691                                         }
692                                 }
693                         }
694                 }
695
696                 static Exception CreateArrayTypeMismatchException ()
697                 {
698                         return new ArrayTypeMismatchException ();
699                 }
700
701                 static bool CanAssignArrayElement (Type source, Type target)
702                 {
703                         if (source.IsValueType)
704                                 return source.IsAssignableFrom (target);
705
706                         if (source.IsInterface)
707                                 return !target.IsValueType;
708
709                         if (target.IsInterface)
710                                 return !source.IsValueType;
711
712                         return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
713                 }
714
715                 public static T [] FindAll<T> (T [] array, Predicate <T> match)
716                 {
717                         if (array == null)
718                                 throw new ArgumentNullException ("array");
719
720                         if (match == null)
721                                 throw new ArgumentNullException ("match");
722
723                         int pos = 0;
724                         T [] d = new T [array.Length];
725                         foreach (T t in array)
726                                 if (match (t))
727                                         d [pos++] = t;
728
729                         Resize <T> (ref d, pos);
730                         return d;
731                 }
732
733                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
734                 //
735                 // The constrained copy should guarantee that if there is an exception thrown
736                 // during the copy, the destination array remains unchanged.
737                 // This is related to System.Runtime.Reliability.CER
738                 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
739                 {
740                         Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
741                 }
742
743                 object GetValueWithFlattenedIndex_NoErrorCheck (int flattenedIndex)
744                 {
745                         return GetValueImpl (flattenedIndex);
746                 }
747
748                 #region Unsafe array operations
749
750                 //
751                 // Loads array index with no safety checks (JIT intristics)
752                 //
753                 internal static T UnsafeLoad<T> (T[] array, int index) {
754                         return array [index];
755                 }
756
757                 //
758                 // Stores values at specified array index with no safety checks (JIT intristics)
759                 //
760                 internal static void UnsafeStore<T> (T[] array, int index, T value) {
761                         array [index] = value;
762                 }
763
764                 //
765                 // Moved value from instance into target of different type with no checks (JIT intristics)
766                 //
767                 // Restrictions:
768                 //
769                 // S and R must either:
770                 //       both be blitable valuetypes
771                 //       both be reference types (IOW, an unsafe cast)
772                 // S and R cannot be float or double
773                 // S and R must either:
774                 //       both be a struct
775                 //       both be a scalar
776                 // S and R must either:
777                 //       be of same size
778                 //       both be a scalar of size <= 4
779                 //
780                 internal static R UnsafeMov<S,R> (S instance) {
781                         return (R)(object) instance;
782                 }
783
784                 #endregion
785
786                 internal sealed class FunctorComparer<T> : IComparer<T> {
787                         Comparison<T> comparison;
788
789                         public FunctorComparer(Comparison<T> comparison) {
790                                 this.comparison = comparison;
791                         }
792
793                         public int Compare(T x, T y) {
794                                 return comparison(x, y);
795                         }
796                 }
797         }
798 }