[arm64] Add a test file for codegen macros. Not used.
[mono.git] / mcs / class / corlib / corert / Array.Portable.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 using System.Runtime;
6 using System.Threading;
7 using System.Collections;
8 using System.Diagnostics;
9 using System.Collections.Generic;
10 using System.Collections.ObjectModel;
11 using System.Runtime.InteropServices;
12 using System.Runtime.CompilerServices;
13 using System.Diagnostics.Contracts;
14 #if MONO
15 using System.Diagnostics.Private;
16 #endif
17
18 namespace System
19 {
20     public abstract partial class Array : ICollection, IEnumerable, IList, IStructuralComparable, IStructuralEquatable, ICloneable
21     {
22         public static Array CreateInstance(Type elementType, params long[] lengths)
23         {
24             if (lengths == null)
25                 throw new ArgumentNullException(nameof(lengths));
26             if (lengths.Length == 0)
27                 throw new ArgumentException(SR.Arg_NeedAtLeast1Rank);
28
29             int[] intLengths = new int[lengths.Length];
30
31             for (int i = 0; i < lengths.Length; ++i)
32             {
33                 long len = lengths[i];
34                 if (len > int.MaxValue || len < int.MinValue)
35                     throw new ArgumentOutOfRangeException("len", SR.ArgumentOutOfRange_HugeArrayNotSupported);
36                 intLengths[i] = (int)len;
37             }
38
39             return Array.CreateInstance(elementType, intLengths);
40         }
41
42         public static ReadOnlyCollection<T> AsReadOnly<T>(T[] array)
43         {
44             if (array == null)
45             {
46                 throw new ArgumentNullException(nameof(array));
47             }
48
49             // T[] implements IList<T>.
50             return new ReadOnlyCollection<T>(array);
51         }
52
53         public static void Resize<T>(ref T[] array, int newSize)
54         {
55             if (newSize < 0)
56                 throw new ArgumentOutOfRangeException(nameof(newSize), SR.ArgumentOutOfRange_NeedNonNegNum);
57
58             T[] larray = array;
59             if (larray == null)
60             {
61                 array = new T[newSize];
62                 return;
63             }
64
65             if (larray.Length != newSize)
66             {
67                 T[] newArray = new T[newSize];
68                 Copy(larray, 0, newArray, 0, larray.Length > newSize ? newSize : larray.Length);
69                 array = newArray;
70             }
71         }
72
73         // Number of elements in the Array.
74         int ICollection.Count
75         { get { return Length; } }
76
77         // Is this Array read-only?
78         bool IList.IsReadOnly
79         { get { return false; } }
80
81         Object IList.this[int index]
82         {
83             get
84             {
85                 return GetValue(index);
86             }
87
88             set
89             {
90                 SetValue(value, index);
91             }
92         }
93
94         int IList.Add(Object value)
95         {
96             throw new NotSupportedException(SR.NotSupported_FixedSizeCollection);
97         }
98
99         bool IList.Contains(Object value)
100         {
101             return Array.IndexOf(this, value) >= 0;
102         }
103
104         void IList.Clear()
105         {
106             Array.Clear(this, GetLowerBound(0), this.Length);
107         }
108
109         int IList.IndexOf(Object value)
110         {
111             return Array.IndexOf(this, value);
112         }
113
114         void IList.Insert(int index, Object value)
115         {
116             throw new NotSupportedException(SR.NotSupported_FixedSizeCollection);
117         }
118
119         void IList.Remove(Object value)
120         {
121             throw new NotSupportedException(SR.NotSupported_FixedSizeCollection);
122         }
123
124         void IList.RemoveAt(int index)
125         {
126             throw new NotSupportedException(SR.NotSupported_FixedSizeCollection);
127         }
128
129         // CopyTo copies a collection into an Array, starting at a particular
130         // index into the array.
131         // 
132         // This method is to support the ICollection interface, and calls
133         // Array.Copy internally.  If you aren't using ICollection explicitly,
134         // call Array.Copy to avoid an extra indirection.
135         // 
136         public void CopyTo(Array array, int index)
137         {
138             // Note: Array.Copy throws a RankException and we want a consistent ArgumentException for all the IList CopyTo methods.
139             if (array != null && array.Rank != 1)
140                 throw new ArgumentException(SR.Arg_RankMultiDimNotSupported);
141
142             Array.Copy(this, GetLowerBound(0), array, index, Length);
143         }
144
145         // Make a new array which is a deep copy of the original array.
146         // 
147         public Object Clone()
148         {
149             return MemberwiseClone();
150         }
151
152         Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer)
153         {
154             if (other == null)
155             {
156                 return 1;
157             }
158
159             Array o = other as Array;
160
161             if (o == null || this.Length != o.Length)
162             {
163                 throw new ArgumentException(SR.ArgumentException_OtherNotArrayOfCorrectLength, nameof(other));
164             }
165
166             int i = 0;
167             int c = 0;
168
169             while (i < o.Length && c == 0)
170             {
171                 object left = GetValue(i);
172                 object right = o.GetValue(i);
173
174                 c = comparer.Compare(left, right);
175                 i++;
176             }
177
178             return c;
179         }
180
181         Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer)
182         {
183             if (other == null)
184             {
185                 return false;
186             }
187
188             if (Object.ReferenceEquals(this, other))
189             {
190                 return true;
191             }
192
193             Array o = other as Array;
194
195             if (o == null || o.Length != this.Length)
196             {
197                 return false;
198             }
199
200             int i = 0;
201             while (i < o.Length)
202             {
203                 object left = GetValue(i);
204                 object right = o.GetValue(i);
205
206                 if (!comparer.Equals(left, right))
207                 {
208                     return false;
209                 }
210                 i++;
211             }
212
213             return true;
214         }
215
216         // From System.Web.Util.HashCodeCombiner
217         internal static int CombineHashCodes(int h1, int h2)
218         {
219             return (((h1 << 5) + h1) ^ h2);
220         }
221
222         int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
223         {
224             if (comparer == null)
225                 throw new ArgumentNullException(nameof(comparer));
226
227             int ret = 0;
228
229             for (int i = (this.Length >= 8 ? this.Length - 8 : 0); i < this.Length; i++)
230             {
231                 ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(i)));
232             }
233
234             return ret;
235         }
236
237         // Searches an array for a given element using a binary search algorithm.
238         // Elements of the array are compared to the search value using the
239         // IComparable interface, which must be implemented by all elements
240         // of the array and the given search value. This method assumes that the
241         // array is already sorted according to the IComparable interface;
242         // if this is not the case, the result will be incorrect.
243         //
244         // The method returns the index of the given value in the array. If the
245         // array does not contain the given value, the method returns a negative
246         // integer. The bitwise complement operator (~) can be applied to a
247         // negative result to produce the index of the first element (if any) that
248         // is larger than the given search value.
249         // 
250         public static int BinarySearch(Array array, Object value)
251         {
252             if (array == null)
253                 throw new ArgumentNullException(nameof(array));
254             return BinarySearch(array, array.GetLowerBound(0), array.Length, value, null);
255         }
256
257         public static TOutput[] ConvertAll<TInput, TOutput>(TInput[] array, Converter<TInput, TOutput> converter)
258         {
259             if (array == null)
260                 throw new ArgumentNullException(nameof(array));
261
262             if (converter == null)
263                 throw new ArgumentNullException(nameof(converter));
264
265             Contract.Ensures(Contract.Result<TOutput[]>() != null);
266             Contract.Ensures(Contract.Result<TOutput[]>().Length == array.Length);
267             Contract.EndContractBlock();
268
269             TOutput[] newArray = new TOutput[array.Length];
270             for (int i = 0; i < array.Length; i++)
271             {
272                 newArray[i] = converter(array[i]);
273             }
274             return newArray;
275         }
276
277         public static void Copy(Array sourceArray, Array destinationArray, long length)
278         {
279             if (length > Int32.MaxValue || length < Int32.MinValue)
280                 throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_HugeArrayNotSupported);
281
282             Array.Copy(sourceArray, destinationArray, (int)length);
283         }
284
285         public static void Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length)
286         {
287             if (sourceIndex > Int32.MaxValue || sourceIndex < Int32.MinValue)
288                 throw new ArgumentOutOfRangeException(nameof(sourceIndex), SR.ArgumentOutOfRange_HugeArrayNotSupported);
289             if (destinationIndex > Int32.MaxValue || destinationIndex < Int32.MinValue)
290                 throw new ArgumentOutOfRangeException(nameof(destinationIndex), SR.ArgumentOutOfRange_HugeArrayNotSupported);
291             if (length > Int32.MaxValue || length < Int32.MinValue)
292                 throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_HugeArrayNotSupported);
293
294             Array.Copy(sourceArray, (int)sourceIndex, destinationArray, (int)destinationIndex, (int)length);
295         }
296
297         public void CopyTo(Array array, long index)
298         {
299             if (index > Int32.MaxValue || index < Int32.MinValue)
300                 throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_HugeArrayNotSupported);
301             Contract.EndContractBlock();
302
303             this.CopyTo(array, (int)index);
304         }
305
306         public static void ForEach<T>(T[] array, Action<T> action)
307         {
308             if (array == null)
309                 throw new ArgumentNullException(nameof(array));
310
311             if (action == null)
312                 throw new ArgumentNullException(nameof(action));
313
314             Contract.EndContractBlock();
315
316             for (int i = 0; i < array.Length; i++)
317             {
318                 action(array[i]);
319             }
320         }
321
322         public long LongLength
323         {
324             get
325             {
326                 long ret = GetLength(0);
327
328                 for (int i = 1; i < Rank; ++i)
329                 {
330                     ret = ret * GetLength(i);
331                 }
332
333                 return ret;
334             }
335         }
336
337         public long GetLongLength(int dimension)
338         {
339             // This method does throw an IndexOutOfRangeException for compat if dimension < 0 or >= Rank
340             // by calling GetUpperBound
341             return GetLength(dimension);
342         }
343
344         public Object GetValue(long index)
345         {
346             if (index > Int32.MaxValue || index < Int32.MinValue)
347                 throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_HugeArrayNotSupported);
348             Contract.EndContractBlock();
349
350             return this.GetValue((int)index);
351         }
352
353         public Object GetValue(long index1, long index2)
354         {
355             if (index1 > Int32.MaxValue || index1 < Int32.MinValue)
356                 throw new ArgumentOutOfRangeException(nameof(index1), SR.ArgumentOutOfRange_HugeArrayNotSupported);
357             if (index2 > Int32.MaxValue || index2 < Int32.MinValue)
358                 throw new ArgumentOutOfRangeException(nameof(index2), SR.ArgumentOutOfRange_HugeArrayNotSupported);
359             Contract.EndContractBlock();
360
361             return this.GetValue((int)index1, (int)index2);
362         }
363
364         public Object GetValue(long index1, long index2, long index3)
365         {
366             if (index1 > Int32.MaxValue || index1 < Int32.MinValue)
367                 throw new ArgumentOutOfRangeException(nameof(index1), SR.ArgumentOutOfRange_HugeArrayNotSupported);
368             if (index2 > Int32.MaxValue || index2 < Int32.MinValue)
369                 throw new ArgumentOutOfRangeException(nameof(index2), SR.ArgumentOutOfRange_HugeArrayNotSupported);
370             if (index3 > Int32.MaxValue || index3 < Int32.MinValue)
371                 throw new ArgumentOutOfRangeException(nameof(index3), SR.ArgumentOutOfRange_HugeArrayNotSupported);
372             Contract.EndContractBlock();
373
374             return this.GetValue((int)index1, (int)index2, (int)index3);
375         }
376
377         public Object GetValue(params long[] indices)
378         {
379             if (indices == null)
380                 throw new ArgumentNullException(nameof(indices));
381             if (Rank != indices.Length)
382                 throw new ArgumentException(SR.Arg_RankIndices);
383             Contract.EndContractBlock();
384
385             int[] intIndices = new int[indices.Length];
386
387             for (int i = 0; i < indices.Length; ++i)
388             {
389                 long index = indices[i];
390                 if (index > Int32.MaxValue || index < Int32.MinValue)
391                     throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_HugeArrayNotSupported);
392                 intIndices[i] = (int)index;
393             }
394
395             return this.GetValue(intIndices);
396         }
397
398         public void Initialize()
399         {
400             // Project N port note: On the desktop, this api is a nop unless the array element type is a value type with
401             // an explicit nullary constructor. Such a type cannot be expressed in C# so Project N does not support this.
402             // The ILC toolchain fails the build if it encounters such a type.
403             return;
404         }        
405
406         public bool IsFixedSize { get { return true; } }
407
408         public bool IsReadOnly { get { return false; } }
409
410         // Is this Array synchronized (i.e., thread-safe)?  If you want a synchronized
411         // collection, you can use SyncRoot as an object to synchronize your 
412         // collection with.  You could also call GetSynchronized() 
413         // to get a synchronized wrapper around the Array.
414         public bool IsSynchronized { get { return false; } }
415
416         // Returns an object appropriate for synchronizing access to this 
417         // Array.
418         public Object SyncRoot { get { return this; } }
419
420         // Searches a section of an array for a given element using a binary search
421         // algorithm. Elements of the array are compared to the search value using
422         // the IComparable interface, which must be implemented by all
423         // elements of the array and the given search value. This method assumes
424         // that the array is already sorted according to the IComparable
425         // interface; if this is not the case, the result will be incorrect.
426         //
427         // The method returns the index of the given value in the array. If the
428         // array does not contain the given value, the method returns a negative
429         // integer. The bitwise complement operator (~) can be applied to a
430         // negative result to produce the index of the first element (if any) that
431         // is larger than the given search value.
432         // 
433         public static int BinarySearch(Array array, int index, int length, Object value)
434         {
435             return BinarySearch(array, index, length, value, null);
436         }
437
438         // Searches an array for a given element using a binary search algorithm.
439         // Elements of the array are compared to the search value using the given
440         // IComparer interface. If comparer is null, elements of the
441         // array are compared to the search value using the IComparable
442         // interface, which in that case must be implemented by all elements of the
443         // array and the given search value. This method assumes that the array is
444         // already sorted; if this is not the case, the result will be incorrect.
445         // 
446         // The method returns the index of the given value in the array. If the
447         // array does not contain the given value, the method returns a negative
448         // integer. The bitwise complement operator (~) can be applied to a
449         // negative result to produce the index of the first element (if any) that
450         // is larger than the given search value.
451         // 
452         public static int BinarySearch(Array array, Object value, IComparer comparer)
453         {
454             if (array == null)
455                 throw new ArgumentNullException(nameof(array));
456             return BinarySearch(array, array.GetLowerBound(0), array.Length, value, comparer);
457         }
458
459         // Searches a section of an array for a given element using a binary search
460         // algorithm. Elements of the array are compared to the search value using
461         // the given IComparer interface. If comparer is null,
462         // elements of the array are compared to the search value using the
463         // IComparable interface, which in that case must be implemented by
464         // all elements of the array and the given search value. This method
465         // assumes that the array is already sorted; if this is not the case, the
466         // result will be incorrect.
467         // 
468         // The method returns the index of the given value in the array. If the
469         // array does not contain the given value, the method returns a negative
470         // integer. The bitwise complement operator (~) can be applied to a
471         // negative result to produce the index of the first element (if any) that
472         // is larger than the given search value.
473         // 
474         public static int BinarySearch(Array array, int index, int length, Object value, IComparer comparer)
475         {
476             if (array == null)
477                 throw new ArgumentNullException(nameof(array));
478
479             if (index < 0 || length < 0)
480                 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum);
481             if (array.Length - index < length)
482                 throw new ArgumentException(SR.Argument_InvalidOffLen);
483             if (array.Rank != 1)
484                 throw new RankException(SR.Rank_MultiDimNotSupported);
485
486             if (comparer == null) comparer = LowLevelComparer.Default;
487
488             int lo = index;
489             int hi = index + length - 1;
490             Object[] objArray = array as Object[];
491             if (objArray != null)
492             {
493                 while (lo <= hi)
494                 {
495                     // i might overflow if lo and hi are both large positive numbers. 
496                     int i = GetMedian(lo, hi);
497
498                     int c;
499                     try
500                     {
501                         c = comparer.Compare(objArray[i], value);
502                     }
503                     catch (Exception e)
504                     {
505                         throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
506                     }
507                     if (c == 0) return i;
508                     if (c < 0)
509                     {
510                         lo = i + 1;
511                     }
512                     else
513                     {
514                         hi = i - 1;
515                     }
516                 }
517             }
518             else
519             {
520                 while (lo <= hi)
521                 {
522                     int i = GetMedian(lo, hi);
523
524                     int c;
525                     try
526                     {
527                         c = comparer.Compare(array.GetValue(i), value);
528                     }
529                     catch (Exception e)
530                     {
531                         throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
532                     }
533                     if (c == 0) return i;
534                     if (c < 0)
535                     {
536                         lo = i + 1;
537                     }
538                     else
539                     {
540                         hi = i - 1;
541                     }
542                 }
543             }
544             return ~lo;
545         }
546
547         private static int GetMedian(int low, int hi)
548         {
549             // Note both may be negative, if we are dealing with arrays w/ negative lower bounds.
550             return low + ((hi - low) >> 1);
551         }
552
553         public static int BinarySearch<T>(T[] array, T value)
554         {
555             if (array == null)
556                 throw new ArgumentNullException(nameof(array));
557             return BinarySearch<T>(array, 0, array.Length, value, null);
558         }
559
560         public static int BinarySearch<T>(T[] array, T value, System.Collections.Generic.IComparer<T> comparer)
561         {
562             if (array == null)
563                 throw new ArgumentNullException(nameof(array));
564             return BinarySearch<T>(array, 0, array.Length, value, comparer);
565         }
566
567         public static int BinarySearch<T>(T[] array, int index, int length, T value)
568         {
569             return BinarySearch<T>(array, index, length, value, null);
570         }
571
572         public static int BinarySearch<T>(T[] array, int index, int length, T value, System.Collections.Generic.IComparer<T> comparer)
573         {
574             if (array == null)
575                 throw new ArgumentNullException(nameof(array));
576             if (index < 0 || length < 0)
577                 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum);
578             if (array.Length - index < length)
579                 throw new ArgumentException(SR.Argument_InvalidOffLen);
580
581             return ArraySortHelper<T>.BinarySearch(array, index, length, value, comparer);
582         }
583
584         // Returns the index of the first occurrence of a given value in an array.
585         // The array is searched forwards, and the elements of the array are
586         // compared to the given value using the Object.Equals method.
587         // 
588         public static int IndexOf(Array array, Object value)
589         {
590             if (array == null)
591             {
592                 throw new ArgumentNullException(nameof(array));
593             }
594
595             return IndexOf(array, value, array.GetLowerBound(0), array.Length);
596         }
597
598         // Returns the index of the first occurrence of a given value in a range of
599         // an array. The array is searched forwards, starting at index
600         // startIndex and ending at the last element of the array. The
601         // elements of the array are compared to the given value using the
602         // Object.Equals method.
603         // 
604         public static int IndexOf(Array array, Object value, int startIndex)
605         {
606             if (array == null)
607             {
608                 throw new ArgumentNullException(nameof(array));
609             }
610
611             int lb = array.GetLowerBound(0);
612             return IndexOf(array, value, startIndex, array.Length - startIndex + lb);
613         }
614
615         // Returns the index of the first occurrence of a given value in a range of
616         // an array. The array is searched forwards, starting at index
617         // startIndex and upto count elements. The
618         // elements of the array are compared to the given value using the
619         // Object.Equals method.
620         // 
621         public static int IndexOf(Array array, Object value, int startIndex, int count)
622         {
623             if (array == null)
624                 throw new ArgumentNullException(nameof(array));
625             if (array.Rank != 1)
626                 throw new RankException(SR.Rank_MultiDimNotSupported);
627             int lb = array.GetLowerBound(0);
628             if (startIndex < lb || startIndex > array.Length + lb)
629                 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
630             if (count < 0 || count > array.Length - startIndex + lb)
631                 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
632
633             Object[] objArray = array as Object[];
634             int endIndex = startIndex + count;
635             if (objArray != null)
636             {
637                 if (value == null)
638                 {
639                     for (int i = startIndex; i < endIndex; i++)
640                     {
641                         if (objArray[i] == null) return i;
642                     }
643                 }
644                 else
645                 {
646                     for (int i = startIndex; i < endIndex; i++)
647                     {
648                         Object obj = objArray[i];
649                         if (obj != null && obj.Equals(value)) return i;
650                     }
651                 }
652             }
653             else
654             {
655                 for (int i = startIndex; i < endIndex; i++)
656                 {
657                     Object obj = array.GetValue(i);
658                     if (obj == null)
659                     {
660                         if (value == null) return i;
661                     }
662                     else
663                     {
664                         if (obj.Equals(value)) return i;
665                     }
666                 }
667             }
668             return lb - 1;
669         }
670
671         /// <summary>
672         /// This version is called from Array<T>.IndexOf and Contains<T>, so it's in every unique array instance due to array interface implementation.
673         /// Do not call into IndexOf<T>(Array array, Object value, int startIndex, int count) for size and space reasons.
674         /// Otherwise there will be two IndexOf methods for each unique array instance, and extra parameter checking which are not needed for the common case.
675         /// </summary>
676         public static int IndexOf<T>(T[] array, T value)
677         {
678             if (array == null)
679             {
680                 throw new ArgumentNullException(nameof(array));
681             }
682
683             // See comment above Array.GetComparerForReferenceTypesOnly for details
684             EqualityComparer<T> comparer = GetComparerForReferenceTypesOnly<T>();
685
686             if (comparer != null)
687             {
688                 for (int i = 0; i < array.Length; i++)
689                 {
690                     if (comparer.Equals(array[i], value))
691                         return i;
692                 }
693             }
694             else
695             {
696                 for (int i = 0; i < array.Length; i++)
697                 {
698                     if (StructOnlyEquals<T>(array[i], value))
699                         return i;
700                 }
701             }
702
703             return -1;
704         }
705
706         public static int IndexOf<T>(T[] array, T value, int startIndex)
707         {
708             if (array == null)
709             {
710                 throw new ArgumentNullException(nameof(array));
711             }
712
713             return IndexOf(array, value, startIndex, array.Length - startIndex);
714         }
715
716         public static int IndexOf<T>(T[] array, T value, int startIndex, int count)
717         {
718             if (array == null)
719             {
720                 throw new ArgumentNullException(nameof(array));
721             }
722
723             if (startIndex < 0 || startIndex > array.Length)
724             {
725                 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
726             }
727
728             if (count < 0 || count > array.Length - startIndex)
729             {
730                 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
731             }
732
733             int endIndex = startIndex + count;
734
735             // See comment above Array.GetComparerForReferenceTypesOnly for details
736             EqualityComparer<T> comparer = GetComparerForReferenceTypesOnly<T>();
737
738             if (comparer != null)
739             {
740                 for (int i = startIndex; i < endIndex; i++)
741                 {
742                     if (comparer.Equals(array[i], value))
743                         return i;
744                 }
745             }
746             else
747             {
748                 for (int i = startIndex; i < endIndex; i++)
749                 {
750                     if (StructOnlyEquals<T>(array[i], value))
751                         return i;
752                 }
753             }
754
755             return -1;
756         }
757
758         public static int LastIndexOf(Array array, Object value)
759         {
760             if (array == null)
761                 throw new ArgumentNullException(nameof(array));
762
763             return LastIndexOf(array, value, array.Length - 1, array.Length);
764         }
765
766         // Returns the index of the last occurrence of a given value in a range of
767         // an array. The array is searched backwards, starting at index
768         // startIndex and ending at index 0. The elements of the array are
769         // compared to the given value using the Object.Equals method.
770         // 
771         public static int LastIndexOf(Array array, Object value, int startIndex)
772         {
773             if (array == null)
774                 throw new ArgumentNullException(nameof(array));
775
776             return LastIndexOf(array, value, startIndex, startIndex + 1);
777         }
778
779         // Returns the index of the last occurrence of a given value in a range of
780         // an array. The array is searched backwards, starting at index
781         // startIndex and counting uptocount elements. The elements of
782         // the array are compared to the given value using the Object.Equals
783         // method.
784         // 
785         public static int LastIndexOf(Array array, Object value, int startIndex, int count)
786         {
787             if (array == null)
788                 throw new ArgumentNullException(nameof(array));
789
790             if (array.Length == 0)
791             {
792                 return -1;
793             }
794
795             if (startIndex < 0 || startIndex >= array.Length)
796                 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
797             if (count < 0)
798                 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
799             if (count > startIndex + 1)
800                 throw new ArgumentOutOfRangeException("endIndex", SR.ArgumentOutOfRange_EndIndexStartIndex);
801             if (array.Rank != 1)
802                 throw new RankException(SR.Rank_MultiDimNotSupported);
803
804             Object[] objArray = array as Object[];
805             int endIndex = startIndex - count + 1;
806             if (objArray != null)
807             {
808                 if (value == null)
809                 {
810                     for (int i = startIndex; i >= endIndex; i--)
811                     {
812                         if (objArray[i] == null) return i;
813                     }
814                 }
815                 else
816                 {
817                     for (int i = startIndex; i >= endIndex; i--)
818                     {
819                         Object obj = objArray[i];
820                         if (obj != null && obj.Equals(value)) return i;
821                     }
822                 }
823             }
824             else
825             {
826                 for (int i = startIndex; i >= endIndex; i--)
827                 {
828                     Object obj = array.GetValue(i);
829                     if (obj == null)
830                     {
831                         if (value == null) return i;
832                     }
833                     else
834                     {
835                         if (obj.Equals(value)) return i;
836                     }
837                 }
838             }
839             return -1;  // Return lb-1 for arrays with negative lower bounds.
840         }
841
842         public static int LastIndexOf<T>(T[] array, T value)
843         {
844             if (array == null)
845             {
846                 throw new ArgumentNullException(nameof(array));
847             }
848
849             return LastIndexOf(array, value, array.Length - 1, array.Length);
850         }
851
852         public static int LastIndexOf<T>(T[] array, T value, int startIndex)
853         {
854             if (array == null)
855             {
856                 throw new ArgumentNullException(nameof(array));
857             }
858
859             // if array is empty and startIndex is 0, we need to pass 0 as count
860             return LastIndexOf(array, value, startIndex, (array.Length == 0) ? 0 : (startIndex + 1));
861         }
862
863         public static int LastIndexOf<T>(T[] array, T value, int startIndex, int count)
864         {
865             if (array == null)
866             {
867                 throw new ArgumentNullException(nameof(array));
868             }
869
870             if (array.Length == 0)
871             {
872                 //
873                 // Special case for 0 length List
874                 // accept -1 and 0 as valid startIndex for compablility reason.
875                 //
876                 if (startIndex != -1 && startIndex != 0)
877                 {
878                     throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
879                 }
880
881                 // only 0 is a valid value for count if array is empty
882                 if (count != 0)
883                 {
884                     throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
885                 }
886                 return -1;
887             }
888
889             // Make sure we're not out of range            
890             if (startIndex < 0 || startIndex >= array.Length)
891             {
892                 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
893             }
894
895             // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
896             if (count < 0 || startIndex - count + 1 < 0)
897             {
898                 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
899             }
900
901             // See comment above Array.GetComparerForReferenceTypesOnly for details
902             EqualityComparer<T> comparer = GetComparerForReferenceTypesOnly<T>();
903
904             int endIndex = startIndex - count + 1;
905             if (comparer != null)
906             {
907                 for (int i = startIndex; i >= endIndex; i--)
908                 {
909                     if (comparer.Equals(array[i], value))
910                         return i;
911                 }
912             }
913             else
914             {
915                 for (int i = startIndex; i >= endIndex; i--)
916                 {
917                     if (StructOnlyEquals<T>(array[i], value))
918                         return i;
919                 }
920             }
921
922             return -1;
923         }
924
925         // Reverses all elements of the given array. Following a call to this
926         // method, an element previously located at index i will now be
927         // located at index length - i - 1, where length is the
928         // length of the array.
929         // 
930         public static void Reverse(Array array)
931         {
932             if (array == null)
933                 throw new ArgumentNullException(nameof(array));
934
935             Reverse(array, array.GetLowerBound(0), array.Length);
936         }
937
938         // Reverses the elements in a range of an array. Following a call to this
939         // method, an element in the range given by index and count
940         // which was previously located at index i will now be located at
941         // index index + (index + count - i - 1).
942         // Reliability note: This may fail because it may have to box objects.
943         // 
944         public static void Reverse(Array array, int index, int length)
945         {
946             if (array == null)
947                 throw new ArgumentNullException(nameof(array));
948             int lowerBound = array.GetLowerBound(0);
949             if (index < lowerBound || length < 0)
950                 throw new ArgumentOutOfRangeException((index < lowerBound ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum);
951             if (array.Length - (index - lowerBound) < length)
952                 throw new ArgumentException(SR.Argument_InvalidOffLen);
953             if (array.Rank != 1)
954                 throw new RankException(SR.Rank_MultiDimNotSupported);
955
956             int i = index;
957             int j = index + length - 1;
958             Object[] objArray = array as Object[];
959             if (objArray != null)
960             {
961                 while (i < j)
962                 {
963                     Object temp = objArray[i];
964                     objArray[i] = objArray[j];
965                     objArray[j] = temp;
966                     i++;
967                     j--;
968                 }
969             }
970             else
971             {
972                 while (i < j)
973                 {
974                     Object temp = array.GetValue(i);
975                     array.SetValue(array.GetValue(j), i);
976                     array.SetValue(temp, j);
977                     i++;
978                     j--;
979                 }
980             }
981         }
982
983         public static void Reverse<T>(T[] array)
984         {
985             if (array == null)
986                 throw new ArgumentNullException(nameof(array));
987
988             Reverse(array, 0, array.Length);
989         }
990
991         public static void Reverse<T>(T[] array, int index, int length)
992         {
993             if (array == null)
994                 throw new ArgumentNullException(nameof(array));
995             if (index < 0 || length < 0)
996                 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum);
997             if (array.Length - index < length)
998                 throw new ArgumentException(SR.Argument_InvalidOffLen);
999
1000             int i = index;
1001             int j = index + length - 1;
1002             while (i < j)
1003             {
1004                 T temp = array[i];
1005                 array[i] = array[j];
1006                 array[j] = temp;
1007                 i++;
1008                 j--;
1009             }
1010         }
1011
1012         public void SetValue(object value, long index)
1013         {
1014             if (index > int.MaxValue || index < int.MinValue)
1015                 throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_HugeArrayNotSupported);
1016
1017             SetValue(value, (int)index);
1018         }
1019
1020         public void SetValue(object value, long index1, long index2)
1021         {
1022             if (index1 > int.MaxValue || index1 < int.MinValue)
1023                 throw new ArgumentOutOfRangeException(nameof(index1), SR.ArgumentOutOfRange_HugeArrayNotSupported);
1024             if (index2 > int.MaxValue || index2 < int.MinValue)
1025                 throw new ArgumentOutOfRangeException(nameof(index2), SR.ArgumentOutOfRange_HugeArrayNotSupported);
1026
1027             SetValue(value, (int)index1, (int)index2);
1028         }
1029
1030         public void SetValue(object value, long index1, long index2, long index3)
1031         {
1032             if (index1 > int.MaxValue || index1 < int.MinValue)
1033                 throw new ArgumentOutOfRangeException(nameof(index1), SR.ArgumentOutOfRange_HugeArrayNotSupported);
1034             if (index2 > int.MaxValue || index2 < int.MinValue)
1035                 throw new ArgumentOutOfRangeException(nameof(index2), SR.ArgumentOutOfRange_HugeArrayNotSupported);
1036             if (index3 > int.MaxValue || index3 < int.MinValue)
1037                 throw new ArgumentOutOfRangeException(nameof(index3), SR.ArgumentOutOfRange_HugeArrayNotSupported);
1038
1039             SetValue(value, (int)index1, (int)index2, (int)index3);
1040         }
1041
1042         public void SetValue(object value, params long[] indices)
1043         {
1044             if (indices == null)
1045                 throw new ArgumentNullException(nameof(indices));
1046             if (Rank != indices.Length)
1047                 throw new ArgumentException(SR.Arg_RankIndices);
1048
1049             int[] intIndices = new int[indices.Length];
1050
1051             for (int i = 0; i < indices.Length; ++i)
1052             {
1053                 long index = indices[i];
1054                 if (index > int.MaxValue || index < int.MinValue)
1055                     throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_HugeArrayNotSupported);
1056                 intIndices[i] = (int)index;
1057             }
1058
1059             SetValue(value, intIndices);
1060         }
1061
1062         // Sorts the elements of an array. The sort compares the elements to each
1063         // other using the IComparable interface, which must be implemented
1064         // by all elements of the array.
1065         // 
1066         public static void Sort(Array array)
1067         {
1068             if (array == null)
1069                 throw new ArgumentNullException(nameof(array));
1070
1071             Sort(array, null, array.GetLowerBound(0), array.Length, null);
1072         }
1073
1074         // Sorts the elements in a section of an array. The sort compares the
1075         // elements to each other using the IComparable interface, which
1076         // must be implemented by all elements in the given section of the array.
1077         // 
1078         public static void Sort(Array array, int index, int length)
1079         {
1080             Sort(array, null, index, length, null);
1081         }
1082
1083         // Sorts the elements of an array. The sort compares the elements to each
1084         // other using the given IComparer interface. If comparer is
1085         // null, the elements are compared to each other using the
1086         // IComparable interface, which in that case must be implemented by
1087         // all elements of the array.
1088         // 
1089         public static void Sort(Array array, IComparer comparer)
1090         {
1091             if (array == null)
1092                 throw new ArgumentNullException(nameof(array));
1093
1094             Sort(array, null, array.GetLowerBound(0), array.Length, comparer);
1095         }
1096
1097         // Sorts the elements in a section of an array. The sort compares the
1098         // elements to each other using the given IComparer interface. If
1099         // comparer is null, the elements are compared to each other using
1100         // the IComparable interface, which in that case must be implemented
1101         // by all elements in the given section of the array.
1102         // 
1103         public static void Sort(Array array, int index, int length, IComparer comparer)
1104         {
1105             Sort(array, null, index, length, comparer);
1106         }
1107
1108         public static void Sort(Array keys, Array items)
1109         {
1110             if (keys == null)
1111             {
1112                 throw new ArgumentNullException(nameof(keys));
1113             }
1114
1115             Sort(keys, items, keys.GetLowerBound(0), keys.Length, null);
1116         }
1117
1118         public static void Sort(Array keys, Array items, IComparer comparer)
1119         {
1120             if (keys == null)
1121             {
1122                 throw new ArgumentNullException(nameof(keys));
1123             }
1124
1125             Sort(keys, items, keys.GetLowerBound(0), keys.Length, comparer);
1126         }
1127
1128         public static void Sort(Array keys, Array items, int index, int length)
1129         {
1130             Sort(keys, items, index, length, null);
1131         }
1132
1133         public static void Sort(Array keys, Array items, int index, int length, IComparer comparer)
1134         {
1135             if (keys == null)
1136                 throw new ArgumentNullException(nameof(keys));
1137             if (keys.Rank != 1 || (items != null && items.Rank != 1))
1138                 throw new RankException(SR.Rank_MultiDimNotSupported);
1139             int keysLowerBound = keys.GetLowerBound(0);
1140             if (items != null && keysLowerBound != items.GetLowerBound(0))
1141                 throw new ArgumentException(SR.Arg_LowerBoundsMustMatch);
1142             if (index < keysLowerBound || length < 0)
1143                 throw new ArgumentOutOfRangeException((length < 0 ? nameof(length) : nameof(index)), SR.ArgumentOutOfRange_NeedNonNegNum);
1144             if (keys.Length - (index - keysLowerBound) < length || (items != null && (index - keysLowerBound) > items.Length - length))
1145                 throw new ArgumentException(SR.Argument_InvalidOffLen);
1146
1147             if (length > 1)
1148             {
1149 #if CORERT
1150                 IComparer<Object> comparerT = new ComparerAsComparerT(comparer);
1151                 Object[] objKeys = keys as Object[];
1152                 Object[] objItems = items as Object[];
1153
1154                 // Unfortunately, on Project N, we don't have the ability to specialize ArraySortHelper<> on demand
1155                 // for value types. Rather than incur a boxing cost on every compare and every swap (and maintain a separate introsort algorithm
1156                 // just for this), box them all, sort them as an Object[] array and unbox them back.
1157
1158                 // Check if either of the arrays need to be copied.
1159                 if (objKeys == null)
1160                 {
1161                     objKeys = new Object[index + length];
1162                     Array.CopyImplValueTypeArrayToReferenceArray(keys, index, objKeys, index, length, reliable: false);
1163                 }
1164                 if (objItems == null && items != null)
1165                 {
1166                     objItems = new Object[index + length];
1167                     Array.CopyImplValueTypeArrayToReferenceArray(items, index, objItems, index, length, reliable: false);
1168                 }
1169
1170                 Sort<Object, Object>(objKeys, objItems, index, length, comparerT);
1171
1172                 // If either array was copied, copy it back into the original
1173                 if (objKeys != keys)
1174                 {
1175                     Array.CopyImplReferenceArrayToValueTypeArray(objKeys, index, keys, index, length, reliable: false);
1176                 }
1177                 if (objItems != items)
1178                 {
1179                     Array.CopyImplReferenceArrayToValueTypeArray(objItems, index, items, index, length, reliable: false);
1180                 }
1181 #else
1182                 Object[] objKeys = keys as Object[];
1183                 Object[] objItems = null;
1184                 if (objKeys != null)
1185                     objItems = items as Object[];
1186                 if (objKeys != null && (items == null || objItems != null))
1187                 {
1188                     SorterObjectArray sorter = new SorterObjectArray(objKeys, objItems, comparer);
1189                     sorter.Sort(index, length);
1190                 }
1191                 else
1192                 {
1193                         SorterGenericArray sorter = new SorterGenericArray(keys, items, comparer);
1194                         sorter.Sort(index, length);
1195                 }
1196 #endif                
1197             }
1198         }
1199
1200         // Wraps an IComparer inside an IComparer<Object>.
1201         private sealed class ComparerAsComparerT : IComparer<Object>
1202         {
1203             public ComparerAsComparerT(IComparer comparer)
1204             {
1205                 _comparer = (comparer == null) ? LowLevelComparer.Default : comparer;
1206             }
1207
1208             public int Compare(Object x, Object y)
1209             {
1210                 return _comparer.Compare(x, y);
1211             }
1212
1213             private IComparer _comparer;
1214         }
1215
1216         public static void Sort<T>(T[] array)
1217         {
1218             if (array == null)
1219                 throw new ArgumentNullException(nameof(array));
1220
1221             Sort<T>(array, 0, array.Length, null);
1222         }
1223
1224         public static void Sort<T>(T[] array, int index, int length)
1225         {
1226             Sort<T>(array, index, length, null);
1227         }
1228
1229         public static void Sort<T>(T[] array, System.Collections.Generic.IComparer<T> comparer)
1230         {
1231             if (array == null)
1232                 throw new ArgumentNullException(nameof(array));
1233             Sort<T>(array, 0, array.Length, comparer);
1234         }
1235
1236         public static void Sort<T>(T[] array, int index, int length, System.Collections.Generic.IComparer<T> comparer)
1237         {
1238             if (array == null)
1239                 throw new ArgumentNullException(nameof(array));
1240             if (index < 0 || length < 0)
1241                 throw new ArgumentOutOfRangeException((length < 0 ? nameof(length) : nameof(index)), SR.ArgumentOutOfRange_NeedNonNegNum);
1242             if (array.Length - index < length)
1243                 throw new ArgumentException(SR.Argument_InvalidOffLen);
1244
1245             if (length > 1)
1246                 ArraySortHelper<T>.Sort(array, index, length, comparer);
1247         }
1248
1249         public static void Sort<T>(T[] array, Comparison<T> comparison)
1250         {
1251             if (array == null)
1252             {
1253                 throw new ArgumentNullException(nameof(array));
1254             }
1255
1256             if (comparison == null)
1257             {
1258                 throw new ArgumentNullException(nameof(comparison));
1259             }
1260
1261             ArraySortHelper<T>.Sort(array, 0, array.Length, comparison);
1262         }
1263
1264         public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items)
1265         {
1266             if (keys == null)
1267                 throw new ArgumentNullException(nameof(keys));
1268             Contract.EndContractBlock();
1269             Sort<TKey, TValue>(keys, items, 0, keys.Length, null);
1270         }
1271
1272         public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length)
1273         {
1274             Sort<TKey, TValue>(keys, items, index, length, null);
1275         }
1276
1277         public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, IComparer<TKey> comparer)
1278         {
1279             if (keys == null)
1280                 throw new ArgumentNullException(nameof(keys));
1281             Contract.EndContractBlock();
1282             Sort<TKey, TValue>(keys, items, 0, keys.Length, comparer);
1283         }
1284
1285         public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length, IComparer<TKey> comparer)
1286         {
1287             if (keys == null)
1288                 throw new ArgumentNullException(nameof(keys));
1289             if (index < 0 || length < 0)
1290                 throw new ArgumentOutOfRangeException((length < 0 ? nameof(length) : nameof(index)), SR.ArgumentOutOfRange_NeedNonNegNum);
1291             if (keys.Length - index < length || (items != null && index > items.Length - length))
1292                 throw new ArgumentException(SR.Argument_InvalidOffLen);
1293             Contract.EndContractBlock();
1294
1295             if (length > 1)
1296             {
1297                 if (items == null)
1298                 {
1299                     Sort<TKey>(keys, index, length, comparer);
1300                     return;
1301                 }
1302
1303                 ArraySortHelper<TKey, TValue>.Default.Sort(keys, items, index, length, comparer);
1304             }
1305         }
1306
1307         public static T[] Empty<T>()
1308         {
1309             return EmptyArray<T>.Value;
1310         }
1311
1312         public static bool Exists<T>(T[] array, Predicate<T> match)
1313         {
1314             return Array.FindIndex(array, match) != -1;
1315         }
1316
1317         public static void Fill<T>(T[] array, T value)
1318         {
1319             if (array == null)
1320             {
1321                 throw new ArgumentNullException(nameof(array));
1322             }
1323
1324             for (int i = 0; i < array.Length; i++)
1325             {
1326                 array[i] = value;
1327             }
1328         }
1329
1330         public static void Fill<T>(T[] array, T value, int startIndex, int count)
1331         {
1332             if (array == null)
1333             {
1334                 throw new ArgumentNullException(nameof(array));
1335             }
1336
1337             if (startIndex < 0 || startIndex > array.Length)
1338             {
1339                 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
1340             }
1341
1342             if (count < 0 || startIndex > array.Length - count)
1343             {
1344                 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
1345             }
1346
1347             for (int i = startIndex; i < startIndex + count; i++)
1348             {
1349                 array[i] = value;
1350             }
1351         }
1352
1353         public static T Find<T>(T[] array, Predicate<T> match)
1354         {
1355             if (array == null)
1356             {
1357                 throw new ArgumentNullException(nameof(array));
1358             }
1359
1360             if (match == null)
1361             {
1362                 throw new ArgumentNullException(nameof(match));
1363             }
1364
1365             for (int i = 0; i < array.Length; i++)
1366             {
1367                 if (match(array[i]))
1368                 {
1369                     return array[i];
1370                 }
1371             }
1372             return default(T);
1373         }
1374
1375         public static int FindIndex<T>(T[] array, Predicate<T> match)
1376         {
1377             if (array == null)
1378             {
1379                 throw new ArgumentNullException(nameof(array));
1380             }
1381
1382             return FindIndex(array, 0, array.Length, match);
1383         }
1384
1385         public static int FindIndex<T>(T[] array, int startIndex, Predicate<T> match)
1386         {
1387             if (array == null)
1388             {
1389                 throw new ArgumentNullException(nameof(array));
1390             }
1391
1392             return FindIndex(array, startIndex, array.Length - startIndex, match);
1393         }
1394
1395         public static int FindIndex<T>(T[] array, int startIndex, int count, Predicate<T> match)
1396         {
1397             if (array == null)
1398             {
1399                 throw new ArgumentNullException(nameof(array));
1400             }
1401
1402             if (startIndex < 0 || startIndex > array.Length)
1403             {
1404                 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
1405             }
1406
1407             if (count < 0 || startIndex > array.Length - count)
1408             {
1409                 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
1410             }
1411
1412             if (match == null)
1413             {
1414                 throw new ArgumentNullException(nameof(match));
1415             }
1416
1417             int endIndex = startIndex + count;
1418             for (int i = startIndex; i < endIndex; i++)
1419             {
1420                 if (match(array[i])) return i;
1421             }
1422             return -1;
1423         }
1424
1425         public static T FindLast<T>(T[] array, Predicate<T> match)
1426         {
1427             if (array == null)
1428             {
1429                 throw new ArgumentNullException(nameof(array));
1430             }
1431
1432             if (match == null)
1433             {
1434                 throw new ArgumentNullException(nameof(match));
1435             }
1436
1437             for (int i = array.Length - 1; i >= 0; i--)
1438             {
1439                 if (match(array[i]))
1440                 {
1441                     return array[i];
1442                 }
1443             }
1444             return default(T);
1445         }
1446
1447         public static int FindLastIndex<T>(T[] array, Predicate<T> match)
1448         {
1449             if (array == null)
1450             {
1451                 throw new ArgumentNullException(nameof(array));
1452             }
1453
1454             return FindLastIndex(array, array.Length - 1, array.Length, match);
1455         }
1456
1457         public static int FindLastIndex<T>(T[] array, int startIndex, Predicate<T> match)
1458         {
1459             if (array == null)
1460             {
1461                 throw new ArgumentNullException(nameof(array));
1462             }
1463
1464             return FindLastIndex(array, startIndex, startIndex + 1, match);
1465         }
1466
1467         public static int FindLastIndex<T>(T[] array, int startIndex, int count, Predicate<T> match)
1468         {
1469             if (array == null)
1470             {
1471                 throw new ArgumentNullException(nameof(array));
1472             }
1473
1474             if (match == null)
1475             {
1476                 throw new ArgumentNullException(nameof(match));
1477             }
1478
1479             if (array.Length == 0)
1480             {
1481                 // Special case for 0 length List
1482                 if (startIndex != -1)
1483                 {
1484                     throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
1485                 }
1486             }
1487             else
1488             {
1489                 // Make sure we're not out of range            
1490                 if (startIndex < 0 || startIndex >= array.Length)
1491                 {
1492                     throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
1493                 }
1494             }
1495
1496             // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
1497             if (count < 0 || startIndex - count + 1 < 0)
1498             {
1499                 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
1500             }
1501
1502             int endIndex = startIndex - count;
1503             for (int i = startIndex; i > endIndex; i--)
1504             {
1505                 if (match(array[i]))
1506                 {
1507                     return i;
1508                 }
1509             }
1510             return -1;
1511         }
1512
1513         public static bool TrueForAll<T>(T[] array, Predicate<T> match)
1514         {
1515             if (array == null)
1516             {
1517                 throw new ArgumentNullException(nameof(array));
1518             }
1519
1520             if (match == null)
1521             {
1522                 throw new ArgumentNullException(nameof(match));
1523             }
1524
1525             for (int i = 0; i < array.Length; i++)
1526             {
1527                 if (!match(array[i]))
1528                 {
1529                     return false;
1530                 }
1531             }
1532             return true;
1533         }
1534
1535         public IEnumerator GetEnumerator()
1536         {
1537             return new ArrayEnumerator(this);
1538         }
1539
1540         // These functions look odd, as they are part of a complex series of compiler intrinsics
1541         // designed to produce very high quality code for equality comparison cases without utilizing
1542         // reflection like other platforms. The major complication is that the specification of
1543         // IndexOf is that it is supposed to use IEquatable<T> if possible, but that requirement
1544         // cannot be expressed in IL directly due to the lack of constraints.
1545         // Instead, specialization at call time is used within the compiler. 
1546         // 
1547         // General Approach
1548         // - Perform fancy redirection for Array.GetComparerForReferenceTypesOnly<T>(). If T is a reference 
1549         //   type or UniversalCanon, have this redirect to EqualityComparer<T>.get_Default, Otherwise, use 
1550         //   the function as is. (will return null in that case)
1551         // - Change the contents of the IndexOf functions to have a pair of loops. One for if 
1552         //   GetComparerForReferenceTypesOnly returns null, and one for when it does not. 
1553         //   - If it does not return null, call the EqualityComparer<T> code.
1554         //   - If it does return null, use a special function StructOnlyEquals<T>(). 
1555         //     - Calls to that function result in calls to a pair of helper function in 
1556         //       EqualityComparerHelpers (StructOnlyEqualsIEquatable, or StructOnlyEqualsNullable) 
1557         //       depending on whether or not they are the right function to call.
1558         // - The end result is that in optimized builds, we have the same single function compiled size 
1559         //   characteristics that the old EqualsOnlyComparer<T>.Equals function had, but we maintain 
1560         //   correctness as well.
1561         private static EqualityComparer<T> GetComparerForReferenceTypesOnly<T>()
1562         {
1563 #if !CORERT
1564                 return System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences<T> () ? EqualityComparer<T>.Default : null;
1565 #else
1566             return EqualityComparer<T>.Default;
1567 #endif
1568         }
1569
1570         private static bool StructOnlyEquals<T>(T left, T right)
1571         {
1572             return left.Equals(right);
1573         }
1574
1575         private sealed class ArrayEnumerator : IEnumerator, ICloneable
1576         {
1577             private Array _array;
1578             private int _index;
1579             private int _endIndex; // cache array length, since it's a little slow.
1580
1581             internal ArrayEnumerator(Array array)
1582             {
1583                 _array = array;
1584                 _index = -1;
1585                 _endIndex = array.Length;
1586             }
1587
1588             public bool MoveNext()
1589             {
1590                 if (_index < _endIndex)
1591                 {
1592                     _index++;
1593                     return (_index < _endIndex);
1594                 }
1595                 return false;
1596             }
1597
1598             public Object Current
1599             {
1600                 get
1601                 {
1602                     if (_index < 0) throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted);
1603                     if (_index >= _endIndex) throw new InvalidOperationException(SR.InvalidOperation_EnumEnded);
1604                     return _array.GetValueWithFlattenedIndex_NoErrorCheck(_index);
1605                 }
1606             }
1607
1608             public void Reset()
1609             {
1610                 _index = -1;
1611             }
1612
1613             public object Clone()
1614             {
1615                 return MemberwiseClone();
1616             }
1617         }
1618     }
1619 }