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.
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;
15 using System.Diagnostics.Private;
20 public abstract partial class Array : ICollection, IEnumerable, IList, IStructuralComparable, IStructuralEquatable, ICloneable
22 public static ReadOnlyCollection<T> AsReadOnly<T>(T[] array)
26 throw new ArgumentNullException(nameof(array));
29 // T[] implements IList<T>.
30 return new ReadOnlyCollection<T>(array);
33 public static void Resize<T>(ref T[] array, int newSize)
36 throw new ArgumentOutOfRangeException(nameof(newSize), SR.ArgumentOutOfRange_NeedNonNegNum);
41 array = new T[newSize];
45 if (larray.Length != newSize)
47 T[] newArray = new T[newSize];
48 Copy(larray, 0, newArray, 0, larray.Length > newSize ? newSize : larray.Length);
53 // Number of elements in the Array.
55 { get { return Length; } }
57 // Is this Array read-only?
59 { get { return false; } }
61 Object IList.this[int index]
65 return GetValue(index);
70 SetValue(value, index);
74 int IList.Add(Object value)
76 throw new NotSupportedException(SR.NotSupported_FixedSizeCollection);
79 bool IList.Contains(Object value)
81 return Array.IndexOf(this, value) >= 0;
86 Array.Clear(this, 0, this.Length);
89 void IList.Insert(int index, Object value)
91 throw new NotSupportedException(SR.NotSupported_FixedSizeCollection);
94 void IList.Remove(Object value)
96 throw new NotSupportedException(SR.NotSupported_FixedSizeCollection);
99 void IList.RemoveAt(int index)
101 throw new NotSupportedException(SR.NotSupported_FixedSizeCollection);
104 // CopyTo copies a collection into an Array, starting at a particular
105 // index into the array.
107 // This method is to support the ICollection interface, and calls
108 // Array.Copy internally. If you aren't using ICollection explicitly,
109 // call Array.Copy to avoid an extra indirection.
111 public void CopyTo(Array array, int index)
113 // Note: Array.Copy throws a RankException and we want a consistent ArgumentException for all the IList CopyTo methods.
114 if (array != null && array.Rank != 1)
115 throw new ArgumentException(SR.Arg_RankMultiDimNotSupported);
117 Array.Copy(this, 0, array, index, Length);
120 // Make a new array which is a deep copy of the original array.
122 public Object Clone()
124 return MemberwiseClone();
127 Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer)
134 Array o = other as Array;
136 if (o == null || this.Length != o.Length)
138 throw new ArgumentException(SR.ArgumentException_OtherNotArrayOfCorrectLength, nameof(other));
144 while (i < o.Length && c == 0)
146 object left = GetValue(i);
147 object right = o.GetValue(i);
149 c = comparer.Compare(left, right);
156 Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer)
163 if (Object.ReferenceEquals(this, other))
168 Array o = other as Array;
170 if (o == null || o.Length != this.Length)
178 object left = GetValue(i);
179 object right = o.GetValue(i);
181 if (!comparer.Equals(left, right))
191 // From System.Web.Util.HashCodeCombiner
192 internal static int CombineHashCodes(int h1, int h2)
194 return (((h1 << 5) + h1) ^ h2);
197 int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
199 if (comparer == null)
200 throw new ArgumentNullException(nameof(comparer));
204 for (int i = (this.Length >= 8 ? this.Length - 8 : 0); i < this.Length; i++)
206 ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(i)));
212 // Searches an array for a given element using a binary search algorithm.
213 // Elements of the array are compared to the search value using the
214 // IComparable interface, which must be implemented by all elements
215 // of the array and the given search value. This method assumes that the
216 // array is already sorted according to the IComparable interface;
217 // if this is not the case, the result will be incorrect.
219 // The method returns the index of the given value in the array. If the
220 // array does not contain the given value, the method returns a negative
221 // integer. The bitwise complement operator (~) can be applied to a
222 // negative result to produce the index of the first element (if any) that
223 // is larger than the given search value.
225 public static int BinarySearch(Array array, Object value)
228 throw new ArgumentNullException(nameof(array));
229 return BinarySearch(array, 0, array.Length, value, null);
232 public static TOutput[] ConvertAll<TInput, TOutput>(TInput[] array, Converter<TInput, TOutput> converter)
235 throw new ArgumentNullException(nameof(array));
237 if (converter == null)
238 throw new ArgumentNullException(nameof(converter));
240 Contract.Ensures(Contract.Result<TOutput[]>() != null);
241 Contract.Ensures(Contract.Result<TOutput[]>().Length == array.Length);
242 Contract.EndContractBlock();
244 TOutput[] newArray = new TOutput[array.Length];
245 for (int i = 0; i < array.Length; i++)
247 newArray[i] = converter(array[i]);
252 public static void Copy(Array sourceArray, Array destinationArray, long length)
254 if (length > Int32.MaxValue || length < Int32.MinValue)
255 throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_HugeArrayNotSupported);
257 Array.Copy(sourceArray, destinationArray, (int)length);
260 public static void Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length)
262 if (sourceIndex > Int32.MaxValue || sourceIndex < Int32.MinValue)
263 throw new ArgumentOutOfRangeException(nameof(sourceIndex), SR.ArgumentOutOfRange_HugeArrayNotSupported);
264 if (destinationIndex > Int32.MaxValue || destinationIndex < Int32.MinValue)
265 throw new ArgumentOutOfRangeException(nameof(destinationIndex), SR.ArgumentOutOfRange_HugeArrayNotSupported);
266 if (length > Int32.MaxValue || length < Int32.MinValue)
267 throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_HugeArrayNotSupported);
269 Array.Copy(sourceArray, (int)sourceIndex, destinationArray, (int)destinationIndex, (int)length);
272 public void CopyTo(Array array, long index)
274 if (index > Int32.MaxValue || index < Int32.MinValue)
275 throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_HugeArrayNotSupported);
276 Contract.EndContractBlock();
278 this.CopyTo(array, (int)index);
281 public static void ForEach<T>(T[] array, Action<T> action)
284 throw new ArgumentNullException(nameof(array));
287 throw new ArgumentNullException(nameof(action));
289 Contract.EndContractBlock();
291 for (int i = 0; i < array.Length; i++)
297 public long LongLength
301 long ret = GetLength(0);
303 for (int i = 1; i < Rank; ++i)
305 ret = ret * GetLength(i);
312 public long GetLongLength(int dimension)
314 // This method does throw an IndexOutOfRangeException for compat if dimension < 0 or >= Rank
315 // by calling GetUpperBound
316 return GetLength(dimension);
319 public Object GetValue(long index)
321 if (index > Int32.MaxValue || index < Int32.MinValue)
322 throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_HugeArrayNotSupported);
323 Contract.EndContractBlock();
325 return this.GetValue((int)index);
328 public Object GetValue(long index1, long index2)
330 if (index1 > Int32.MaxValue || index1 < Int32.MinValue)
331 throw new ArgumentOutOfRangeException(nameof(index1), SR.ArgumentOutOfRange_HugeArrayNotSupported);
332 if (index2 > Int32.MaxValue || index2 < Int32.MinValue)
333 throw new ArgumentOutOfRangeException(nameof(index2), SR.ArgumentOutOfRange_HugeArrayNotSupported);
334 Contract.EndContractBlock();
336 return this.GetValue((int)index1, (int)index2);
339 public Object GetValue(long index1, long index2, long index3)
341 if (index1 > Int32.MaxValue || index1 < Int32.MinValue)
342 throw new ArgumentOutOfRangeException(nameof(index1), SR.ArgumentOutOfRange_HugeArrayNotSupported);
343 if (index2 > Int32.MaxValue || index2 < Int32.MinValue)
344 throw new ArgumentOutOfRangeException(nameof(index2), SR.ArgumentOutOfRange_HugeArrayNotSupported);
345 if (index3 > Int32.MaxValue || index3 < Int32.MinValue)
346 throw new ArgumentOutOfRangeException(nameof(index3), SR.ArgumentOutOfRange_HugeArrayNotSupported);
347 Contract.EndContractBlock();
349 return this.GetValue((int)index1, (int)index2, (int)index3);
352 public Object GetValue(params long[] indices)
355 throw new ArgumentNullException(nameof(indices));
356 if (Rank != indices.Length)
357 throw new ArgumentException(SR.Arg_RankIndices);
358 Contract.EndContractBlock();
360 int[] intIndices = new int[indices.Length];
362 for (int i = 0; i < indices.Length; ++i)
364 long index = indices[i];
365 if (index > Int32.MaxValue || index < Int32.MinValue)
366 throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_HugeArrayNotSupported);
367 intIndices[i] = (int)index;
370 return this.GetValue(intIndices);
373 public void Initialize()
375 // Project N port note: On the desktop, this api is a nop unless the array element type is a value type with
376 // an explicit nullary constructor. Such a type cannot be expressed in C# so Project N does not support this.
377 // The ILC toolchain fails the build if it encounters such a type.
381 public bool IsFixedSize { get { return true; } }
383 // Is this Array synchronized (i.e., thread-safe)? If you want a synchronized
384 // collection, you can use SyncRoot as an object to synchronize your
385 // collection with. You could also call GetSynchronized()
386 // to get a synchronized wrapper around the Array.
387 public bool IsSynchronized { get { return false; } }
389 // Returns an object appropriate for synchronizing access to this
391 public Object SyncRoot { get { return this; } }
393 // Searches a section of an array for a given element using a binary search
394 // algorithm. Elements of the array are compared to the search value using
395 // the IComparable interface, which must be implemented by all
396 // elements of the array and the given search value. This method assumes
397 // that the array is already sorted according to the IComparable
398 // interface; if this is not the case, the result will be incorrect.
400 // The method returns the index of the given value in the array. If the
401 // array does not contain the given value, the method returns a negative
402 // integer. The bitwise complement operator (~) can be applied to a
403 // negative result to produce the index of the first element (if any) that
404 // is larger than the given search value.
406 public static int BinarySearch(Array array, int index, int length, Object value)
408 return BinarySearch(array, index, length, value, null);
411 // Searches an array for a given element using a binary search algorithm.
412 // Elements of the array are compared to the search value using the given
413 // IComparer interface. If comparer is null, elements of the
414 // array are compared to the search value using the IComparable
415 // interface, which in that case must be implemented by all elements of the
416 // array and the given search value. This method assumes that the array is
417 // already sorted; if this is not the case, the result will be incorrect.
419 // The method returns the index of the given value in the array. If the
420 // array does not contain the given value, the method returns a negative
421 // integer. The bitwise complement operator (~) can be applied to a
422 // negative result to produce the index of the first element (if any) that
423 // is larger than the given search value.
425 public static int BinarySearch(Array array, Object value, IComparer comparer)
428 throw new ArgumentNullException(nameof(array));
429 return BinarySearch(array, 0, array.Length, value, comparer);
432 // Searches a section of an array for a given element using a binary search
433 // algorithm. Elements of the array are compared to the search value using
434 // the given IComparer interface. If comparer is null,
435 // elements of the array are compared to the search value using the
436 // IComparable interface, which in that case must be implemented by
437 // all elements of the array and the given search value. This method
438 // assumes that the array is already sorted; if this is not the case, the
439 // result will be incorrect.
441 // The method returns the index of the given value in the array. If the
442 // array does not contain the given value, the method returns a negative
443 // integer. The bitwise complement operator (~) can be applied to a
444 // negative result to produce the index of the first element (if any) that
445 // is larger than the given search value.
447 public static int BinarySearch(Array array, int index, int length, Object value, IComparer comparer)
450 throw new ArgumentNullException(nameof(array));
452 if (index < 0 || length < 0)
453 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum);
454 if (array.Length - index < length)
455 throw new ArgumentException(SR.Argument_InvalidOffLen);
457 throw new RankException(SR.Rank_MultiDimNotSupported);
459 if (comparer == null) comparer = LowLevelComparer.Default;
462 int hi = index + length - 1;
463 Object[] objArray = array as Object[];
464 if (objArray != null)
468 // i might overflow if lo and hi are both large positive numbers.
469 int i = GetMedian(lo, hi);
474 c = comparer.Compare(objArray[i], value);
478 throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
480 if (c == 0) return i;
495 int i = GetMedian(lo, hi);
500 c = comparer.Compare(array.GetValue(i), value);
504 throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
506 if (c == 0) return i;
520 private static int GetMedian(int low, int hi)
522 // Note both may be negative, if we are dealing with arrays w/ negative lower bounds.
523 return low + ((hi - low) >> 1);
526 public static int BinarySearch<T>(T[] array, T value)
529 throw new ArgumentNullException(nameof(array));
530 return BinarySearch<T>(array, 0, array.Length, value, null);
533 public static int BinarySearch<T>(T[] array, T value, System.Collections.Generic.IComparer<T> comparer)
536 throw new ArgumentNullException(nameof(array));
537 return BinarySearch<T>(array, 0, array.Length, value, comparer);
540 public static int BinarySearch<T>(T[] array, int index, int length, T value)
542 return BinarySearch<T>(array, index, length, value, null);
545 public static int BinarySearch<T>(T[] array, int index, int length, T value, System.Collections.Generic.IComparer<T> comparer)
548 throw new ArgumentNullException(nameof(array));
549 if (index < 0 || length < 0)
550 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum);
551 if (array.Length - index < length)
552 throw new ArgumentException(SR.Argument_InvalidOffLen);
554 return ArraySortHelper<T>.BinarySearch(array, index, length, value, comparer);
557 // Returns the index of the first occurrence of a given value in an array.
558 // The array is searched forwards, and the elements of the array are
559 // compared to the given value using the Object.Equals method.
561 public static int IndexOf(Array array, Object value)
565 throw new ArgumentNullException(nameof(array));
568 return IndexOf(array, value, 0, array.Length);
571 // Returns the index of the first occurrence of a given value in a range of
572 // an array. The array is searched forwards, starting at index
573 // startIndex and ending at the last element of the array. The
574 // elements of the array are compared to the given value using the
575 // Object.Equals method.
577 public static int IndexOf(Array array, Object value, int startIndex)
581 throw new ArgumentNullException(nameof(array));
584 return IndexOf(array, value, startIndex, array.Length - startIndex);
587 // Returns the index of the first occurrence of a given value in a range of
588 // an array. The array is searched forwards, starting at index
589 // startIndex and upto count elements. The
590 // elements of the array are compared to the given value using the
591 // Object.Equals method.
593 public static int IndexOf(Array array, Object value, int startIndex, int count)
596 throw new ArgumentNullException(nameof(array));
598 throw new RankException(SR.Rank_MultiDimNotSupported);
599 if (startIndex < 0 || startIndex > array.Length)
600 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
601 if (count < 0 || count > array.Length - startIndex)
602 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
604 Object[] objArray = array as Object[];
605 int endIndex = startIndex + count;
606 if (objArray != null)
610 for (int i = startIndex; i < endIndex; i++)
612 if (objArray[i] == null) return i;
617 for (int i = startIndex; i < endIndex; i++)
619 Object obj = objArray[i];
620 if (obj != null && obj.Equals(value)) return i;
626 for (int i = startIndex; i < endIndex; i++)
628 Object obj = array.GetValue(i);
631 if (value == null) return i;
635 if (obj.Equals(value)) return i;
643 /// This version is called from Array<T>.IndexOf and Contains<T>, so it's in every unique array instance due to array interface implementation.
644 /// Do not call into IndexOf<T>(Array array, Object value, int startIndex, int count) for size and space reasons.
645 /// Otherwise there will be two IndexOf methods for each unique array instance, and extra parameter checking which are not needed for the common case.
647 public static int IndexOf<T>(T[] array, T value)
651 throw new ArgumentNullException(nameof(array));
654 // See comment above Array.GetComparerForReferenceTypesOnly for details
655 EqualityComparer<T> comparer = GetComparerForReferenceTypesOnly<T>();
657 if (comparer != null)
659 for (int i = 0; i < array.Length; i++)
661 if (comparer.Equals(array[i], value))
667 for (int i = 0; i < array.Length; i++)
669 if (StructOnlyEquals<T>(array[i], value))
677 public static int IndexOf<T>(T[] array, T value, int startIndex)
681 throw new ArgumentNullException(nameof(array));
684 return IndexOf(array, value, startIndex, array.Length - startIndex);
687 public static int IndexOf<T>(T[] array, T value, int startIndex, int count)
691 throw new ArgumentNullException(nameof(array));
694 if (startIndex < 0 || startIndex > array.Length)
696 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
699 if (count < 0 || count > array.Length - startIndex)
701 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
704 int endIndex = startIndex + count;
706 // See comment above Array.GetComparerForReferenceTypesOnly for details
707 EqualityComparer<T> comparer = GetComparerForReferenceTypesOnly<T>();
709 if (comparer != null)
711 for (int i = startIndex; i < endIndex; i++)
713 if (comparer.Equals(array[i], value))
719 for (int i = startIndex; i < endIndex; i++)
721 if (StructOnlyEquals<T>(array[i], value))
729 public static int LastIndexOf(Array array, Object value)
732 throw new ArgumentNullException(nameof(array));
734 return LastIndexOf(array, value, array.Length - 1, array.Length);
737 // Returns the index of the last occurrence of a given value in a range of
738 // an array. The array is searched backwards, starting at index
739 // startIndex and ending at index 0. The elements of the array are
740 // compared to the given value using the Object.Equals method.
742 public static int LastIndexOf(Array array, Object value, int startIndex)
745 throw new ArgumentNullException(nameof(array));
747 return LastIndexOf(array, value, startIndex, startIndex + 1);
750 // Returns the index of the last occurrence of a given value in a range of
751 // an array. The array is searched backwards, starting at index
752 // startIndex and counting uptocount elements. The elements of
753 // the array are compared to the given value using the Object.Equals
756 public static int LastIndexOf(Array array, Object value, int startIndex, int count)
759 throw new ArgumentNullException(nameof(array));
761 if (array.Length == 0)
766 if (startIndex < 0 || startIndex >= array.Length)
767 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
769 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
770 if (count > startIndex + 1)
771 throw new ArgumentOutOfRangeException("endIndex", SR.ArgumentOutOfRange_EndIndexStartIndex);
773 throw new RankException(SR.Rank_MultiDimNotSupported);
775 Object[] objArray = array as Object[];
776 int endIndex = startIndex - count + 1;
777 if (objArray != null)
781 for (int i = startIndex; i >= endIndex; i--)
783 if (objArray[i] == null) return i;
788 for (int i = startIndex; i >= endIndex; i--)
790 Object obj = objArray[i];
791 if (obj != null && obj.Equals(value)) return i;
797 for (int i = startIndex; i >= endIndex; i--)
799 Object obj = array.GetValue(i);
802 if (value == null) return i;
806 if (obj.Equals(value)) return i;
810 return -1; // Return lb-1 for arrays with negative lower bounds.
813 public static int LastIndexOf<T>(T[] array, T value)
817 throw new ArgumentNullException(nameof(array));
820 return LastIndexOf(array, value, array.Length - 1, array.Length);
823 public static int LastIndexOf<T>(T[] array, T value, int startIndex)
827 throw new ArgumentNullException(nameof(array));
830 // if array is empty and startIndex is 0, we need to pass 0 as count
831 return LastIndexOf(array, value, startIndex, (array.Length == 0) ? 0 : (startIndex + 1));
834 public static int LastIndexOf<T>(T[] array, T value, int startIndex, int count)
838 throw new ArgumentNullException(nameof(array));
841 if (array.Length == 0)
844 // Special case for 0 length List
845 // accept -1 and 0 as valid startIndex for compablility reason.
847 if (startIndex != -1 && startIndex != 0)
849 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
852 // only 0 is a valid value for count if array is empty
855 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
860 // Make sure we're not out of range
861 if (startIndex < 0 || startIndex >= array.Length)
863 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
866 // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
867 if (count < 0 || startIndex - count + 1 < 0)
869 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
872 // See comment above Array.GetComparerForReferenceTypesOnly for details
873 EqualityComparer<T> comparer = GetComparerForReferenceTypesOnly<T>();
875 int endIndex = startIndex - count + 1;
876 if (comparer != null)
878 for (int i = startIndex; i >= endIndex; i--)
880 if (comparer.Equals(array[i], value))
886 for (int i = startIndex; i >= endIndex; i--)
888 if (StructOnlyEquals<T>(array[i], value))
896 // Reverses all elements of the given array. Following a call to this
897 // method, an element previously located at index i will now be
898 // located at index length - i - 1, where length is the
899 // length of the array.
901 public static void Reverse(Array array)
904 throw new ArgumentNullException(nameof(array));
906 Reverse(array, 0, array.Length);
909 // Reverses the elements in a range of an array. Following a call to this
910 // method, an element in the range given by index and count
911 // which was previously located at index i will now be located at
912 // index index + (index + count - i - 1).
913 // Reliability note: This may fail because it may have to box objects.
915 public static void Reverse(Array array, int index, int length)
918 throw new ArgumentNullException(nameof(array));
919 int lowerBound = array.GetLowerBound(0);
920 if (index < lowerBound || length < 0)
921 throw new ArgumentOutOfRangeException((index < lowerBound ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum);
922 if (array.Length - (index - lowerBound) < length)
923 throw new ArgumentException(SR.Argument_InvalidOffLen);
925 throw new RankException(SR.Rank_MultiDimNotSupported);
928 int j = index + length - 1;
929 Object[] objArray = array as Object[];
930 if (objArray != null)
934 Object temp = objArray[i];
935 objArray[i] = objArray[j];
945 Object temp = array.GetValue(i);
946 array.SetValue(array.GetValue(j), i);
947 array.SetValue(temp, j);
954 public static void Reverse<T>(T[] array)
957 throw new ArgumentNullException(nameof(array));
959 Reverse(array, 0, array.Length);
962 public static void Reverse<T>(T[] array, int index, int length)
965 throw new ArgumentNullException(nameof(array));
966 if (index < 0 || length < 0)
967 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum);
968 if (array.Length - index < length)
969 throw new ArgumentException(SR.Argument_InvalidOffLen);
972 int j = index + length - 1;
983 // Sorts the elements of an array. The sort compares the elements to each
984 // other using the IComparable interface, which must be implemented
985 // by all elements of the array.
987 public static void Sort(Array array)
990 throw new ArgumentNullException(nameof(array));
992 Sort(array, null, 0, array.Length, null);
995 // Sorts the elements in a section of an array. The sort compares the
996 // elements to each other using the IComparable interface, which
997 // must be implemented by all elements in the given section of the array.
999 public static void Sort(Array array, int index, int length)
1001 Sort(array, null, index, length, null);
1004 // Sorts the elements of an array. The sort compares the elements to each
1005 // other using the given IComparer interface. If comparer is
1006 // null, the elements are compared to each other using the
1007 // IComparable interface, which in that case must be implemented by
1008 // all elements of the array.
1010 public static void Sort(Array array, IComparer comparer)
1013 throw new ArgumentNullException(nameof(array));
1015 Sort(array, null, 0, array.Length, comparer);
1018 // Sorts the elements in a section of an array. The sort compares the
1019 // elements to each other using the given IComparer interface. If
1020 // comparer is null, the elements are compared to each other using
1021 // the IComparable interface, which in that case must be implemented
1022 // by all elements in the given section of the array.
1024 public static void Sort(Array array, int index, int length, IComparer comparer)
1026 Sort(array, null, index, length, comparer);
1029 public static void Sort(Array keys, Array items)
1033 throw new ArgumentNullException(nameof(keys));
1036 Sort(keys, items, keys.GetLowerBound(0), keys.Length, null);
1039 public static void Sort(Array keys, Array items, IComparer comparer)
1043 throw new ArgumentNullException(nameof(keys));
1046 Sort(keys, items, keys.GetLowerBound(0), keys.Length, comparer);
1049 public static void Sort(Array keys, Array items, int index, int length)
1051 Sort(keys, items, index, length, null);
1054 public static void Sort(Array keys, Array items, int index, int length, IComparer comparer)
1057 throw new ArgumentNullException(nameof(keys));
1058 if (keys.Rank != 1 || (items != null && items.Rank != 1))
1059 throw new RankException(SR.Rank_MultiDimNotSupported);
1060 int keysLowerBound = keys.GetLowerBound(0);
1061 if (items != null && keysLowerBound != items.GetLowerBound(0))
1062 throw new ArgumentException(SR.Arg_LowerBoundsMustMatch);
1063 if (index < keysLowerBound || length < 0)
1064 throw new ArgumentOutOfRangeException((length < 0 ? nameof(length) : nameof(index)), SR.ArgumentOutOfRange_NeedNonNegNum);
1065 if (keys.Length - (index - keysLowerBound) < length || (items != null && (index - keysLowerBound) > items.Length - length))
1066 throw new ArgumentException(SR.Argument_InvalidOffLen);
1071 IComparer<Object> comparerT = new ComparerAsComparerT(comparer);
1072 Object[] objKeys = keys as Object[];
1073 Object[] objItems = items as Object[];
1075 // Unfortunately, on Project N, we don't have the ability to specialize ArraySortHelper<> on demand
1076 // for value types. Rather than incur a boxing cost on every compare and every swap (and maintain a separate introsort algorithm
1077 // just for this), box them all, sort them as an Object[] array and unbox them back.
1079 // Check if either of the arrays need to be copied.
1080 if (objKeys == null)
1082 objKeys = new Object[index + length];
1083 Array.CopyImplValueTypeArrayToReferenceArray(keys, index, objKeys, index, length, reliable: false);
1085 if (objItems == null && items != null)
1087 objItems = new Object[index + length];
1088 Array.CopyImplValueTypeArrayToReferenceArray(items, index, objItems, index, length, reliable: false);
1091 Sort<Object, Object>(objKeys, objItems, index, length, comparerT);
1093 // If either array was copied, copy it back into the original
1094 if (objKeys != keys)
1096 Array.CopyImplReferenceArrayToValueTypeArray(objKeys, index, keys, index, length, reliable: false);
1098 if (objItems != items)
1100 Array.CopyImplReferenceArrayToValueTypeArray(objItems, index, items, index, length, reliable: false);
1103 Object[] objKeys = keys as Object[];
1104 Object[] objItems = null;
1105 if (objKeys != null)
1106 objItems = items as Object[];
1107 if (objKeys != null && (items == null || objItems != null))
1109 SorterObjectArray sorter = new SorterObjectArray(objKeys, objItems, comparer);
1110 sorter.Sort(index, length);
1114 SorterGenericArray sorter = new SorterGenericArray(keys, items, comparer);
1115 sorter.Sort(index, length);
1121 // Wraps an IComparer inside an IComparer<Object>.
1122 private sealed class ComparerAsComparerT : IComparer<Object>
1124 public ComparerAsComparerT(IComparer comparer)
1126 _comparer = (comparer == null) ? LowLevelComparer.Default : comparer;
1129 public int Compare(Object x, Object y)
1131 return _comparer.Compare(x, y);
1134 private IComparer _comparer;
1137 public static void Sort<T>(T[] array)
1140 throw new ArgumentNullException(nameof(array));
1142 Sort<T>(array, 0, array.Length, null);
1145 public static void Sort<T>(T[] array, int index, int length)
1147 Sort<T>(array, index, length, null);
1150 public static void Sort<T>(T[] array, System.Collections.Generic.IComparer<T> comparer)
1153 throw new ArgumentNullException(nameof(array));
1154 Sort<T>(array, 0, array.Length, comparer);
1157 public static void Sort<T>(T[] array, int index, int length, System.Collections.Generic.IComparer<T> comparer)
1160 throw new ArgumentNullException(nameof(array));
1161 if (index < 0 || length < 0)
1162 throw new ArgumentOutOfRangeException((length < 0 ? nameof(length) : nameof(index)), SR.ArgumentOutOfRange_NeedNonNegNum);
1163 if (array.Length - index < length)
1164 throw new ArgumentException(SR.Argument_InvalidOffLen);
1167 ArraySortHelper<T>.Sort(array, index, length, comparer);
1170 public static void Sort<T>(T[] array, Comparison<T> comparison)
1174 throw new ArgumentNullException(nameof(array));
1177 if (comparison == null)
1179 throw new ArgumentNullException(nameof(comparison));
1182 ArraySortHelper<T>.Sort(array, 0, array.Length, comparison);
1185 public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items)
1188 throw new ArgumentNullException(nameof(keys));
1189 Contract.EndContractBlock();
1190 Sort<TKey, TValue>(keys, items, 0, keys.Length, null);
1193 public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length)
1195 Sort<TKey, TValue>(keys, items, index, length, null);
1198 public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, IComparer<TKey> comparer)
1201 throw new ArgumentNullException(nameof(keys));
1202 Contract.EndContractBlock();
1203 Sort<TKey, TValue>(keys, items, 0, keys.Length, comparer);
1206 public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length, IComparer<TKey> comparer)
1209 throw new ArgumentNullException(nameof(keys));
1210 if (index < 0 || length < 0)
1211 throw new ArgumentOutOfRangeException((length < 0 ? nameof(length) : nameof(index)), SR.ArgumentOutOfRange_NeedNonNegNum);
1212 if (keys.Length - index < length || (items != null && index > items.Length - length))
1213 throw new ArgumentException(SR.Argument_InvalidOffLen);
1214 Contract.EndContractBlock();
1220 Sort<TKey>(keys, index, length, comparer);
1224 ArraySortHelper<TKey, TValue>.Default.Sort(keys, items, index, length, comparer);
1228 public static T[] Empty<T>()
1230 return EmptyArray<T>.Value;
1233 public static bool Exists<T>(T[] array, Predicate<T> match)
1235 return Array.FindIndex(array, match) != -1;
1238 public static void Fill<T>(T[] array, T value)
1242 throw new ArgumentNullException(nameof(array));
1245 for (int i = 0; i < array.Length; i++)
1251 public static void Fill<T>(T[] array, T value, int startIndex, int count)
1255 throw new ArgumentNullException(nameof(array));
1258 if (startIndex < 0 || startIndex > array.Length)
1260 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
1263 if (count < 0 || startIndex > array.Length - count)
1265 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
1268 for (int i = startIndex; i < startIndex + count; i++)
1274 public static T Find<T>(T[] array, Predicate<T> match)
1278 throw new ArgumentNullException(nameof(array));
1283 throw new ArgumentNullException(nameof(match));
1286 for (int i = 0; i < array.Length; i++)
1288 if (match(array[i]))
1296 public static int FindIndex<T>(T[] array, Predicate<T> match)
1300 throw new ArgumentNullException(nameof(array));
1303 return FindIndex(array, 0, array.Length, match);
1306 public static int FindIndex<T>(T[] array, int startIndex, Predicate<T> match)
1310 throw new ArgumentNullException(nameof(array));
1313 return FindIndex(array, startIndex, array.Length - startIndex, match);
1316 public static int FindIndex<T>(T[] array, int startIndex, int count, Predicate<T> match)
1320 throw new ArgumentNullException(nameof(array));
1323 if (startIndex < 0 || startIndex > array.Length)
1325 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
1328 if (count < 0 || startIndex > array.Length - count)
1330 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
1335 throw new ArgumentNullException(nameof(match));
1338 int endIndex = startIndex + count;
1339 for (int i = startIndex; i < endIndex; i++)
1341 if (match(array[i])) return i;
1346 public static T FindLast<T>(T[] array, Predicate<T> match)
1350 throw new ArgumentNullException(nameof(array));
1355 throw new ArgumentNullException(nameof(match));
1358 for (int i = array.Length - 1; i >= 0; i--)
1360 if (match(array[i]))
1368 public static int FindLastIndex<T>(T[] array, Predicate<T> match)
1372 throw new ArgumentNullException(nameof(array));
1375 return FindLastIndex(array, array.Length - 1, array.Length, match);
1378 public static int FindLastIndex<T>(T[] array, int startIndex, Predicate<T> match)
1382 throw new ArgumentNullException(nameof(array));
1385 return FindLastIndex(array, startIndex, startIndex + 1, match);
1388 public static int FindLastIndex<T>(T[] array, int startIndex, int count, Predicate<T> match)
1392 throw new ArgumentNullException(nameof(array));
1397 throw new ArgumentNullException(nameof(match));
1400 if (array.Length == 0)
1402 // Special case for 0 length List
1403 if (startIndex != -1)
1405 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
1410 // Make sure we're not out of range
1411 if (startIndex < 0 || startIndex >= array.Length)
1413 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
1417 // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
1418 if (count < 0 || startIndex - count + 1 < 0)
1420 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
1423 int endIndex = startIndex - count;
1424 for (int i = startIndex; i > endIndex; i--)
1426 if (match(array[i]))
1434 public static bool TrueForAll<T>(T[] array, Predicate<T> match)
1438 throw new ArgumentNullException(nameof(array));
1443 throw new ArgumentNullException(nameof(match));
1446 for (int i = 0; i < array.Length; i++)
1448 if (!match(array[i]))
1456 public IEnumerator GetEnumerator()
1458 return new ArrayEnumerator(this);
1461 // These functions look odd, as they are part of a complex series of compiler intrinsics
1462 // designed to produce very high quality code for equality comparison cases without utilizing
1463 // reflection like other platforms. The major complication is that the specification of
1464 // IndexOf is that it is supposed to use IEquatable<T> if possible, but that requirement
1465 // cannot be expressed in IL directly due to the lack of constraints.
1466 // Instead, specialization at call time is used within the compiler.
1469 // - Perform fancy redirection for Array.GetComparerForReferenceTypesOnly<T>(). If T is a reference
1470 // type or UniversalCanon, have this redirect to EqualityComparer<T>.get_Default, Otherwise, use
1471 // the function as is. (will return null in that case)
1472 // - Change the contents of the IndexOf functions to have a pair of loops. One for if
1473 // GetComparerForReferenceTypesOnly returns null, and one for when it does not.
1474 // - If it does not return null, call the EqualityComparer<T> code.
1475 // - If it does return null, use a special function StructOnlyEquals<T>().
1476 // - Calls to that function result in calls to a pair of helper function in
1477 // EqualityComparerHelpers (StructOnlyEqualsIEquatable, or StructOnlyEqualsNullable)
1478 // depending on whether or not they are the right function to call.
1479 // - The end result is that in optimized builds, we have the same single function compiled size
1480 // characteristics that the old EqualsOnlyComparer<T>.Equals function had, but we maintain
1481 // correctness as well.
1482 private static EqualityComparer<T> GetComparerForReferenceTypesOnly<T>()
1485 return System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences<T> () ? EqualityComparer<T>.Default : null;
1487 return EqualityComparer<T>.Default;
1491 private static bool StructOnlyEquals<T>(T left, T right)
1493 return left.Equals(right);
1496 private sealed class ArrayEnumerator : IEnumerator, ICloneable
1498 private Array _array;
1500 private int _endIndex; // cache array length, since it's a little slow.
1502 internal ArrayEnumerator(Array array)
1506 _endIndex = array.Length;
1509 public bool MoveNext()
1511 if (_index < _endIndex)
1514 return (_index < _endIndex);
1519 public Object Current
1523 if (_index < 0) throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted);
1524 if (_index >= _endIndex) throw new InvalidOperationException(SR.InvalidOperation_EnumEnded);
1525 return _array.GetValueWithFlattenedIndex_NoErrorCheck(_index);
1534 public object Clone()
1536 return MemberwiseClone();