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.
5 using System
.Collections
;
6 using System
.Collections
.Generic
;
7 using System
.Collections
.ObjectModel
;
8 using System
.Diagnostics
;
9 using System
.Diagnostics
.CodeAnalysis
;
10 using System
.Runtime
.CompilerServices
;
11 using Internal
.Runtime
.CompilerServices
;
16 [System
.Runtime
.CompilerServices
.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
17 public abstract partial class Array
: ICloneable
, IList
, IStructuralComparable
, IStructuralEquatable
19 // We impose limits on maximum array length in each dimension to allow efficient
20 // implementation of advanced range check elimination in future.
21 // Keep in sync with vm\gcscan.cpp and HashHelpers.MaxPrimeArrayLength.
22 // The constants are defined in this method: inline SIZE_T MaxArrayLength(SIZE_T componentSize) from gcscan
23 // We have different max sizes for arrays with elements of size 1 for backwards compatibility
24 internal const int MaxArrayLength
= 0X7FEFFFFF;
25 internal const int MaxByteArrayLength
= 0x7FFFFFC7;
27 // This ctor exists solely to prevent C# from generating a protected .ctor that violates the surface area.
28 private protected Array() { }
30 public static ReadOnlyCollection
<T
> AsReadOnly
<T
>(T
[] array
)
34 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
37 // T[] implements IList<T>.
38 return new ReadOnlyCollection
<T
>(array
);
41 public static void Resize
<T
>([NotNull
] ref T
[]? array
, int newSize
)
44 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.newSize
, ExceptionResource
.ArgumentOutOfRange_NeedNonNegNum
);
49 array
= new T
[newSize
];
53 if (larray
.Length
!= newSize
)
55 T
[] newArray
= new T
[newSize
];
56 Copy(larray
, 0, newArray
, 0, larray
.Length
> newSize
? newSize
: larray
.Length
);
61 public static Array
CreateInstance(Type elementType
, params long[] lengths
)
65 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.lengths
);
67 if (lengths
.Length
== 0)
68 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Arg_NeedAtLeast1Rank
);
70 int[] intLengths
= new int[lengths
.Length
];
72 for (int i
= 0; i
< lengths
.Length
; ++i
)
74 long len
= lengths
[i
];
77 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.len
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
81 return Array
.CreateInstance(elementType
, intLengths
);
84 public static void Copy(Array sourceArray
, Array destinationArray
, long length
)
86 int ilength
= (int)length
;
87 if (length
!= ilength
)
88 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.length
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
90 Copy(sourceArray
, destinationArray
, ilength
);
93 public static void Copy(Array sourceArray
, long sourceIndex
, Array destinationArray
, long destinationIndex
, long length
)
95 int isourceIndex
= (int)sourceIndex
;
96 int idestinationIndex
= (int)destinationIndex
;
97 int ilength
= (int)length
;
99 if (sourceIndex
!= isourceIndex
)
100 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.sourceIndex
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
101 if (destinationIndex
!= idestinationIndex
)
102 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.destinationIndex
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
103 if (length
!= ilength
)
104 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.length
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
106 Copy(sourceArray
, isourceIndex
, destinationArray
, idestinationIndex
, ilength
);
109 public object? GetValue(long index
)
111 int iindex
= (int)index
;
113 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
115 return this.GetValue(iindex
);
118 public object? GetValue(long index1
, long index2
)
120 int iindex1
= (int)index1
;
121 int iindex2
= (int)index2
;
123 if (index1
!= iindex1
)
124 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index1
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
125 if (index2
!= iindex2
)
126 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index2
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
128 return this.GetValue(iindex1
, iindex2
);
131 public object? GetValue(long index1
, long index2
, long index3
)
133 int iindex1
= (int)index1
;
134 int iindex2
= (int)index2
;
135 int iindex3
= (int)index3
;
137 if (index1
!= iindex1
)
138 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index1
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
139 if (index2
!= iindex2
)
140 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index2
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
141 if (index3
!= iindex3
)
142 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index3
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
144 return this.GetValue(iindex1
, iindex2
, iindex3
);
147 public object? GetValue(params long[] indices
)
150 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.indices
);
151 if (Rank
!= indices
.Length
)
152 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Arg_RankIndices
);
154 int[] intIndices
= new int[indices
.Length
];
156 for (int i
= 0; i
< indices
.Length
; ++i
)
158 long index
= indices
[i
];
159 int iindex
= (int)index
;
161 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
162 intIndices
[i
] = iindex
;
165 return this.GetValue(intIndices
);
168 public void SetValue(object? value, long index
)
170 int iindex
= (int)index
;
173 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
175 this.SetValue(value, iindex
);
178 public void SetValue(object? value, long index1
, long index2
)
180 int iindex1
= (int)index1
;
181 int iindex2
= (int)index2
;
183 if (index1
!= iindex1
)
184 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index1
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
185 if (index2
!= iindex2
)
186 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index2
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
188 this.SetValue(value, iindex1
, iindex2
);
191 public void SetValue(object? value, long index1
, long index2
, long index3
)
193 int iindex1
= (int)index1
;
194 int iindex2
= (int)index2
;
195 int iindex3
= (int)index3
;
197 if (index1
!= iindex1
)
198 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index1
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
199 if (index2
!= iindex2
)
200 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index2
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
201 if (index3
!= iindex3
)
202 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index3
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
204 this.SetValue(value, iindex1
, iindex2
, iindex3
);
207 public void SetValue(object? value, params long[] indices
)
210 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.indices
);
211 if (Rank
!= indices
.Length
)
212 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Arg_RankIndices
);
214 int[] intIndices
= new int[indices
.Length
];
216 for (int i
= 0; i
< indices
.Length
; ++i
)
218 long index
= indices
[i
];
219 int iindex
= (int)index
;
221 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
222 intIndices
[i
] = iindex
;
225 this.SetValue(value, intIndices
);
228 private static int GetMedian(int low
, int hi
)
230 // Note both may be negative, if we are dealing with arrays w/ negative lower bounds.
231 Debug
.Assert(low
<= hi
);
232 Debug
.Assert(hi
- low
>= 0, "Length overflow!");
233 return low
+ ((hi
- low
) >> 1);
236 public long GetLongLength(int dimension
)
238 // This method should throw an IndexOufOfRangeException for compat if dimension < 0 or >= Rank
239 return GetLength(dimension
);
242 // Number of elements in the Array.
243 int ICollection
.Count
=> Length
;
245 // Returns an object appropriate for synchronizing access to this
247 public object SyncRoot
=> this;
249 // Is this Array read-only?
250 public bool IsReadOnly
=> false;
252 public bool IsFixedSize
=> true;
254 // Is this Array synchronized (i.e., thread-safe)? If you want a synchronized
255 // collection, you can use SyncRoot as an object to synchronize your
256 // collection with. You could also call GetSynchronized()
257 // to get a synchronized wrapper around the Array.
258 public bool IsSynchronized
=> false;
260 object? IList
.this[int index
]
262 get => GetValue(index
);
263 set => SetValue(value, index
);
266 int IList
.Add(object? value)
268 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_FixedSizeCollection
);
272 bool IList
.Contains(object? value)
274 return Array
.IndexOf(this, value) >= this.GetLowerBound(0);
279 Array
.Clear(this, this.GetLowerBound(0), this.Length
);
282 int IList
.IndexOf(object? value)
284 return Array
.IndexOf(this, value);
287 void IList
.Insert(int index
, object? value)
289 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_FixedSizeCollection
);
292 void IList
.Remove(object? value)
294 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_FixedSizeCollection
);
297 void IList
.RemoveAt(int index
)
299 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_FixedSizeCollection
);
302 // Make a new array which is a shallow copy of the original array.
304 public object Clone()
306 return MemberwiseClone();
309 int IStructuralComparable
.CompareTo(object? other
, IComparer comparer
)
316 Array
? o
= other
as Array
;
318 if (o
== null || this.Length
!= o
.Length
)
320 ThrowHelper
.ThrowArgumentException(ExceptionResource
.ArgumentException_OtherNotArrayOfCorrectLength
, ExceptionArgument
.other
);
326 while (i
< o
.Length
&& c
== 0)
328 object? left
= GetValue(i
);
329 object? right
= o
.GetValue(i
);
331 c
= comparer
.Compare(left
, right
);
338 bool IStructuralEquatable
.Equals(object? other
, IEqualityComparer comparer
)
345 if (object.ReferenceEquals(this, other
))
350 if (!(other
is Array o
) || o
.Length
!= this.Length
)
358 object? left
= GetValue(i
);
359 object? right
= o
.GetValue(i
);
361 if (!comparer
.Equals(left
, right
))
371 int IStructuralEquatable
.GetHashCode(IEqualityComparer comparer
)
373 if (comparer
== null)
374 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.comparer
);
378 for (int i
= (this.Length
>= 8 ? this.Length
- 8 : 0); i
< this.Length
; i
++)
380 ret
= HashCode
.Combine(ret
, comparer
.GetHashCode(GetValue(i
)!));
386 // Searches an array for a given element using a binary search algorithm.
387 // Elements of the array are compared to the search value using the
388 // IComparable interface, which must be implemented by all elements
389 // of the array and the given search value. This method assumes that the
390 // array is already sorted according to the IComparable interface;
391 // if this is not the case, the result will be incorrect.
393 // The method returns the index of the given value in the array. If the
394 // array does not contain the given value, the method returns a negative
395 // integer. The bitwise complement operator (~) can be applied to a
396 // negative result to produce the index of the first element (if any) that
397 // is larger than the given search value.
399 public static int BinarySearch(Array array
, object? value)
402 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
403 return BinarySearch(array
, array
.GetLowerBound(0), array
.Length
, value, null);
406 // Searches a section of an array for a given element using a binary search
407 // algorithm. Elements of the array are compared to the search value using
408 // the IComparable interface, which must be implemented by all
409 // elements of the array and the given search value. This method assumes
410 // that the array is already sorted according to the IComparable
411 // interface; if this is not the case, the result will be incorrect.
413 // The method returns the index of the given value in the array. If the
414 // array does not contain the given value, the method returns a negative
415 // integer. The bitwise complement operator (~) can be applied to a
416 // negative result to produce the index of the first element (if any) that
417 // is larger than the given search value.
419 public static int BinarySearch(Array array
, int index
, int length
, object? value)
421 return BinarySearch(array
, index
, length
, value, null);
424 // Searches an array for a given element using a binary search algorithm.
425 // Elements of the array are compared to the search value using the given
426 // IComparer interface. If comparer is null, elements of the
427 // array are compared to the search value using the IComparable
428 // interface, which in that case must be implemented by all elements of the
429 // array and the given search value. This method assumes that the array is
430 // already sorted; if this is not the case, the result will be incorrect.
432 // The method returns the index of the given value in the array. If the
433 // array does not contain the given value, the method returns a negative
434 // integer. The bitwise complement operator (~) can be applied to a
435 // negative result to produce the index of the first element (if any) that
436 // is larger than the given search value.
438 public static int BinarySearch(Array array
, object? value, IComparer
? comparer
)
441 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
442 return BinarySearch(array
, array
.GetLowerBound(0), array
.Length
, value, comparer
);
445 // Searches a section of an array for a given element using a binary search
446 // algorithm. Elements of the array are compared to the search value using
447 // the given IComparer interface. If comparer is null,
448 // elements of the array are compared to the search value using the
449 // IComparable interface, which in that case must be implemented by
450 // all elements of the array and the given search value. This method
451 // assumes that the array is already sorted; if this is not the case, the
452 // result will be incorrect.
454 // The method returns the index of the given value in the array. If the
455 // array does not contain the given value, the method returns a negative
456 // integer. The bitwise complement operator (~) can be applied to a
457 // negative result to produce the index of the first element (if any) that
458 // is larger than the given search value.
460 public static int BinarySearch(Array array
, int index
, int length
, object? value, IComparer
? comparer
)
463 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
464 int lb
= array
.GetLowerBound(0);
466 ThrowHelper
.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
468 ThrowHelper
.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
469 if (array
.Length
- (index
- lb
) < length
)
470 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Argument_InvalidOffLen
);
472 ThrowHelper
.ThrowRankException(ExceptionResource
.Rank_MultiDimNotSupported
);
474 comparer
??= Comparer
.Default
;
476 if (comparer
== Comparer
.Default
)
479 bool r
= TrySZBinarySearch(array
, index
, length
, value, out retval
);
486 int hi
= index
+ length
- 1;
487 if (array
is object[] objArray
)
491 // i might overflow if lo and hi are both large positive numbers.
492 int i
= GetMedian(lo
, hi
);
497 c
= comparer
.Compare(objArray
[i
], value);
501 ThrowHelper
.ThrowInvalidOperationException(ExceptionResource
.InvalidOperation_IComparerFailed
, e
);
504 if (c
== 0) return i
;
519 int i
= GetMedian(lo
, hi
);
524 c
= comparer
.Compare(array
.GetValue(i
), value);
528 ThrowHelper
.ThrowInvalidOperationException(ExceptionResource
.InvalidOperation_IComparerFailed
, e
);
531 if (c
== 0) return i
;
545 public static int BinarySearch
<T
>(T
[] array
, T
value)
548 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
549 return BinarySearch
<T
>(array
, 0, array
.Length
, value, null);
552 public static int BinarySearch
<T
>(T
[] array
, T
value, System
.Collections
.Generic
.IComparer
<T
>? comparer
)
555 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
556 return BinarySearch
<T
>(array
, 0, array
.Length
, value, comparer
);
559 public static int BinarySearch
<T
>(T
[] array
, int index
, int length
, T
value)
561 return BinarySearch
<T
>(array
, index
, length
, value, null);
564 public static int BinarySearch
<T
>(T
[] array
, int index
, int length
, T
value, System
.Collections
.Generic
.IComparer
<T
>? comparer
)
567 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
569 ThrowHelper
.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
571 ThrowHelper
.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
573 if (array
.Length
- index
< length
)
574 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Argument_InvalidOffLen
);
576 return ArraySortHelper
<T
>.Default
.BinarySearch(array
, index
, length
, value, comparer
);
579 public static TOutput
[] ConvertAll
<TInput
, TOutput
>(TInput
[] array
, Converter
<TInput
, TOutput
> converter
)
583 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
586 if (converter
== null)
588 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.converter
);
591 TOutput
[] newArray
= new TOutput
[array
.Length
];
592 for (int i
= 0; i
< array
.Length
; i
++)
594 newArray
[i
] = converter(array
[i
]);
599 // CopyTo copies a collection into an Array, starting at a particular
600 // index into the array.
602 // This method is to support the ICollection interface, and calls
603 // Array.Copy internally. If you aren't using ICollection explicitly,
604 // call Array.Copy to avoid an extra indirection.
606 public void CopyTo(Array array
, int index
)
608 if (array
!= null && array
.Rank
!= 1)
609 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Arg_RankMultiDimNotSupported
);
610 // Note: Array.Copy throws a RankException and we want a consistent ArgumentException for all the IList CopyTo methods.
611 Array
.Copy(this, GetLowerBound(0), array
!, index
, Length
);
614 public void CopyTo(Array array
, long index
)
616 int iindex
= (int)index
;
618 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.index
, ExceptionResource
.ArgumentOutOfRange_HugeArrayNotSupported
);
620 this.CopyTo(array
, iindex
);
623 private static class EmptyArray
<T
>
625 #pragma warning disable CA1825 // this is the implementation of Array.Empty<T>()
626 internal static readonly T
[] Value
= new T
[0];
627 #pragma warning restore CA1825
630 public static T
[] Empty
<T
>()
632 return EmptyArray
<T
>.Value
;
635 public static bool Exists
<T
>(T
[] array
, Predicate
<T
> match
)
637 return Array
.FindIndex(array
, match
) != -1;
640 public static void Fill
<T
>(T
[] array
, T
value)
644 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
647 for (int i
= 0; i
< array
.Length
; i
++)
653 public static void Fill
<T
>(T
[] array
, T
value, int startIndex
, int count
)
657 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
660 if (startIndex
< 0 || startIndex
> array
.Length
)
662 ThrowHelper
.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
665 if (count
< 0 || startIndex
> array
.Length
- count
)
667 ThrowHelper
.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
670 for (int i
= startIndex
; i
< startIndex
+ count
; i
++)
677 public static T Find
<T
>(T
[] array
, Predicate
<T
> match
)
681 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
686 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.match
);
689 for (int i
= 0; i
< array
.Length
; i
++)
699 public static T
[] FindAll
<T
>(T
[] array
, Predicate
<T
> match
)
703 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
708 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.match
);
711 List
<T
> list
= new List
<T
>();
712 for (int i
= 0; i
< array
.Length
; i
++)
719 return list
.ToArray();
722 public static int FindIndex
<T
>(T
[] array
, Predicate
<T
> match
)
726 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
729 return FindIndex(array
, 0, array
.Length
, match
);
732 public static int FindIndex
<T
>(T
[] array
, int startIndex
, Predicate
<T
> match
)
736 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
739 return FindIndex(array
, startIndex
, array
.Length
- startIndex
, match
);
742 public static int FindIndex
<T
>(T
[] array
, int startIndex
, int count
, Predicate
<T
> match
)
746 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
749 if (startIndex
< 0 || startIndex
> array
.Length
)
751 ThrowHelper
.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
754 if (count
< 0 || startIndex
> array
.Length
- count
)
756 ThrowHelper
.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
761 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.match
);
764 int endIndex
= startIndex
+ count
;
765 for (int i
= startIndex
; i
< endIndex
; i
++)
774 public static T FindLast
<T
>(T
[] array
, Predicate
<T
> match
)
778 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
783 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.match
);
786 for (int i
= array
.Length
- 1; i
>= 0; i
--)
796 public static int FindLastIndex
<T
>(T
[] array
, Predicate
<T
> match
)
800 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
803 return FindLastIndex(array
, array
.Length
- 1, array
.Length
, match
);
806 public static int FindLastIndex
<T
>(T
[] array
, int startIndex
, Predicate
<T
> match
)
810 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
813 return FindLastIndex(array
, startIndex
, startIndex
+ 1, match
);
816 public static int FindLastIndex
<T
>(T
[] array
, int startIndex
, int count
, Predicate
<T
> match
)
820 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
825 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.match
);
828 if (array
.Length
== 0)
830 // Special case for 0 length List
831 if (startIndex
!= -1)
833 ThrowHelper
.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
838 // Make sure we're not out of range
839 if (startIndex
< 0 || startIndex
>= array
.Length
)
841 ThrowHelper
.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
845 // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
846 if (count
< 0 || startIndex
- count
+ 1 < 0)
848 ThrowHelper
.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
851 int endIndex
= startIndex
- count
;
852 for (int i
= startIndex
; i
> endIndex
; i
--)
862 public static void ForEach
<T
>(T
[] array
, Action
<T
> action
)
866 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
871 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.action
);
874 for (int i
= 0; i
< array
.Length
; i
++)
880 // Returns the index of the first occurrence of a given value in an array.
881 // The array is searched forwards, and the elements of the array are
882 // compared to the given value using the Object.Equals method.
884 public static int IndexOf(Array array
, object? value)
887 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
888 return IndexOf(array
, value, array
.GetLowerBound(0), array
.Length
);
891 // Returns the index of the first occurrence of a given value in a range of
892 // an array. The array is searched forwards, starting at index
893 // startIndex and ending at the last element of the array. The
894 // elements of the array are compared to the given value using the
895 // Object.Equals method.
897 public static int IndexOf(Array array
, object? value, int startIndex
)
900 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
901 int lb
= array
.GetLowerBound(0);
902 return IndexOf(array
, value, startIndex
, array
.Length
- startIndex
+ lb
);
905 // Returns the index of the first occurrence of a given value in a range of
906 // an array. The array is searched forwards, starting at index
907 // startIndex and upto count elements. The
908 // elements of the array are compared to the given value using the
909 // Object.Equals method.
911 public static int IndexOf(Array array
, object? value, int startIndex
, int count
)
914 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
916 ThrowHelper
.ThrowRankException(ExceptionResource
.Rank_MultiDimNotSupported
);
918 int lb
= array
.GetLowerBound(0);
919 if (startIndex
< lb
|| startIndex
> array
.Length
+ lb
)
920 ThrowHelper
.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
921 if (count
< 0 || count
> array
.Length
- startIndex
+ lb
)
922 ThrowHelper
.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
925 // Try calling a quick native method to handle primitive types.
927 bool r
= TrySZIndexOf(array
, startIndex
, count
, value, out retVal
);
932 int endIndex
= startIndex
+ count
;
933 if (array
is object[] objArray
)
937 for (int i
= startIndex
; i
< endIndex
; i
++)
939 if (objArray
[i
] == null)
945 for (int i
= startIndex
; i
< endIndex
; i
++)
947 object obj
= objArray
[i
];
948 if (obj
!= null && obj
.Equals(value))
955 for (int i
= startIndex
; i
< endIndex
; i
++)
957 object? obj
= array
.GetValue(i
);
965 if (obj
.Equals(value))
970 // Return one less than the lower bound of the array. This way,
971 // for arrays with a lower bound of -1 we will not return -1 when the
972 // item was not found. And for SZArrays (the vast majority), -1 still
977 public static int IndexOf
<T
>(T
[] array
, T
value)
981 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
984 return IndexOf(array
, value, 0, array
.Length
);
987 public static int IndexOf
<T
>(T
[] array
, T
value, int startIndex
)
991 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
994 return IndexOf(array
, value, startIndex
, array
.Length
- startIndex
);
997 public static int IndexOf
<T
>(T
[] array
, T
value, int startIndex
, int count
)
1001 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1004 if ((uint)startIndex
> (uint)array
.Length
)
1006 ThrowHelper
.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
1009 if ((uint)count
> (uint)(array
.Length
- startIndex
))
1011 ThrowHelper
.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
1014 if (RuntimeHelpers
.IsBitwiseEquatable
<T
>())
1016 if (Unsafe
.SizeOf
<T
>() == sizeof(byte))
1018 int result
= SpanHelpers
.IndexOf(
1019 ref Unsafe
.Add(ref array
.GetRawSzArrayData(), startIndex
),
1020 Unsafe
.As
<T
, byte>(ref value),
1022 return (result
>= 0 ? startIndex
: 0) + result
;
1024 else if (Unsafe
.SizeOf
<T
>() == sizeof(char))
1026 int result
= SpanHelpers
.IndexOf(
1027 ref Unsafe
.Add(ref Unsafe
.As
<byte, char>(ref array
.GetRawSzArrayData()), startIndex
),
1028 Unsafe
.As
<T
, char>(ref value),
1030 return (result
>= 0 ? startIndex
: 0) + result
;
1032 else if (Unsafe
.SizeOf
<T
>() == sizeof(int))
1034 int result
= SpanHelpers
.IndexOf(
1035 ref Unsafe
.Add(ref Unsafe
.As
<byte, int>(ref array
.GetRawSzArrayData()), startIndex
),
1036 Unsafe
.As
<T
, int>(ref value),
1038 return (result
>= 0 ? startIndex
: 0) + result
;
1040 else if (Unsafe
.SizeOf
<T
>() == sizeof(long))
1042 int result
= SpanHelpers
.IndexOf(
1043 ref Unsafe
.Add(ref Unsafe
.As
<byte, long>(ref array
.GetRawSzArrayData()), startIndex
),
1044 Unsafe
.As
<T
, long>(ref value),
1046 return (result
>= 0 ? startIndex
: 0) + result
;
1051 return EqualityComparer
<T
>.Default
.IndexOf(array
, value, startIndex
, count
);
1053 return IndexOfImpl(array
, value, startIndex
, count
);
1057 // Returns the index of the last occurrence of a given value in an array.
1058 // The array is searched backwards, and the elements of the array are
1059 // compared to the given value using the Object.Equals method.
1061 public static int LastIndexOf(Array array
, object? value)
1064 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1065 int lb
= array
.GetLowerBound(0);
1066 return LastIndexOf(array
, value, array
.Length
- 1 + lb
, array
.Length
);
1069 // Returns the index of the last occurrence of a given value in a range of
1070 // an array. The array is searched backwards, starting at index
1071 // startIndex and ending at index 0. The elements of the array are
1072 // compared to the given value using the Object.Equals method.
1074 public static int LastIndexOf(Array array
, object? value, int startIndex
)
1077 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1078 int lb
= array
.GetLowerBound(0);
1079 return LastIndexOf(array
, value, startIndex
, startIndex
+ 1 - lb
);
1082 // Returns the index of the last occurrence of a given value in a range of
1083 // an array. The array is searched backwards, starting at index
1084 // startIndex and counting uptocount elements. The elements of
1085 // the array are compared to the given value using the Object.Equals
1088 public static int LastIndexOf(Array array
, object? value, int startIndex
, int count
)
1091 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1092 int lb
= array
.GetLowerBound(0);
1093 if (array
.Length
== 0)
1098 if (startIndex
< lb
|| startIndex
>= array
.Length
+ lb
)
1099 ThrowHelper
.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
1101 ThrowHelper
.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
1102 if (count
> startIndex
- lb
+ 1)
1103 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.endIndex
, ExceptionResource
.ArgumentOutOfRange_EndIndexStartIndex
);
1104 if (array
.Rank
!= 1)
1105 ThrowHelper
.ThrowRankException(ExceptionResource
.Rank_MultiDimNotSupported
);
1108 // Try calling a quick native method to handle primitive types.
1110 bool r
= TrySZLastIndexOf(array
, startIndex
, count
, value, out retVal
);
1115 int endIndex
= startIndex
- count
+ 1;
1116 if (array
is object[] objArray
)
1120 for (int i
= startIndex
; i
>= endIndex
; i
--)
1122 if (objArray
[i
] == null)
1128 for (int i
= startIndex
; i
>= endIndex
; i
--)
1130 object obj
= objArray
[i
];
1131 if (obj
!= null && obj
.Equals(value))
1138 for (int i
= startIndex
; i
>= endIndex
; i
--)
1140 object? obj
= array
.GetValue(i
);
1148 if (obj
.Equals(value))
1153 return lb
- 1; // Return lb-1 for arrays with negative lower bounds.
1156 public static int LastIndexOf
<T
>(T
[] array
, T
value)
1160 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1163 return LastIndexOf(array
, value, array
.Length
- 1, array
.Length
);
1166 public static int LastIndexOf
<T
>(T
[] array
, T
value, int startIndex
)
1170 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1172 // if array is empty and startIndex is 0, we need to pass 0 as count
1173 return LastIndexOf(array
, value, startIndex
, (array
.Length
== 0) ? 0 : (startIndex
+ 1));
1176 public static int LastIndexOf
<T
>(T
[] array
, T
value, int startIndex
, int count
)
1180 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1183 if (array
.Length
== 0)
1186 // Special case for 0 length List
1187 // accept -1 and 0 as valid startIndex for compablility reason.
1189 if (startIndex
!= -1 && startIndex
!= 0)
1191 ThrowHelper
.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
1194 // only 0 is a valid value for count if array is empty
1197 ThrowHelper
.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
1202 // Make sure we're not out of range
1203 if ((uint)startIndex
>= (uint)array
.Length
)
1205 ThrowHelper
.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
1208 // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
1209 if (count
< 0 || startIndex
- count
+ 1 < 0)
1211 ThrowHelper
.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count();
1214 if (RuntimeHelpers
.IsBitwiseEquatable
<T
>())
1216 if (Unsafe
.SizeOf
<T
>() == sizeof(byte))
1218 int endIndex
= startIndex
- count
+ 1;
1219 int result
= SpanHelpers
.LastIndexOf(
1220 ref Unsafe
.Add(ref array
.GetRawSzArrayData(), endIndex
),
1221 Unsafe
.As
<T
, byte>(ref value),
1224 return (result
>= 0 ? endIndex
: 0) + result
;
1226 else if (Unsafe
.SizeOf
<T
>() == sizeof(char))
1228 int endIndex
= startIndex
- count
+ 1;
1229 int result
= SpanHelpers
.LastIndexOf(
1230 ref Unsafe
.Add(ref Unsafe
.As
<byte, char>(ref array
.GetRawSzArrayData()), endIndex
),
1231 Unsafe
.As
<T
, char>(ref value),
1234 return (result
>= 0 ? endIndex
: 0) + result
;
1236 else if (Unsafe
.SizeOf
<T
>() == sizeof(int))
1238 int endIndex
= startIndex
- count
+ 1;
1239 int result
= SpanHelpers
.LastIndexOf(
1240 ref Unsafe
.Add(ref Unsafe
.As
<byte, int>(ref array
.GetRawSzArrayData()), endIndex
),
1241 Unsafe
.As
<T
, int>(ref value),
1244 return (result
>= 0 ? endIndex
: 0) + result
;
1246 else if (Unsafe
.SizeOf
<T
>() == sizeof(long))
1248 int endIndex
= startIndex
- count
+ 1;
1249 int result
= SpanHelpers
.LastIndexOf(
1250 ref Unsafe
.Add(ref Unsafe
.As
<byte, long>(ref array
.GetRawSzArrayData()), endIndex
),
1251 Unsafe
.As
<T
, long>(ref value),
1254 return (result
>= 0 ? endIndex
: 0) + result
;
1259 return EqualityComparer
<T
>.Default
.LastIndexOf(array
, value, startIndex
, count
);
1261 return LastIndexOfImpl(array
, value, startIndex
, count
);
1265 // Reverses all elements of the given array. Following a call to this
1266 // method, an element previously located at index i will now be
1267 // located at index length - i - 1, where length is the
1268 // length of the array.
1270 public static void Reverse(Array array
)
1273 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1274 Reverse(array
, array
.GetLowerBound(0), array
.Length
);
1277 // Reverses the elements in a range of an array. Following a call to this
1278 // method, an element in the range given by index and count
1279 // which was previously located at index i will now be located at
1280 // index index + (index + count - i - 1).
1281 // Reliability note: This may fail because it may have to box objects.
1283 public static void Reverse(Array array
, int index
, int length
)
1286 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1287 int lowerBound
= array
.GetLowerBound(0);
1288 if (index
< lowerBound
)
1289 ThrowHelper
.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
1291 ThrowHelper
.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
1293 if (array
.Length
- (index
- lowerBound
) < length
)
1294 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Argument_InvalidOffLen
);
1295 if (array
.Rank
!= 1)
1296 ThrowHelper
.ThrowRankException(ExceptionResource
.Rank_MultiDimNotSupported
);
1302 bool r
= TrySZReverse(array
, index
, length
);
1307 if (array
is object[] objArray
)
1309 Array
.Reverse
<object>(objArray
, index
, length
);
1314 int j
= index
+ length
- 1;
1317 object? temp
= array
.GetValue(i
);
1318 array
.SetValue(array
.GetValue(j
), i
);
1319 array
.SetValue(temp
, j
);
1326 public static void Reverse
<T
>(T
[] array
)
1329 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1330 Reverse(array
, 0, array
.Length
);
1333 public static void Reverse
<T
>(T
[] array
, int index
, int length
)
1336 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1338 ThrowHelper
.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
1340 ThrowHelper
.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
1341 if (array
.Length
- index
< length
)
1342 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Argument_InvalidOffLen
);
1347 ref T first
= ref Unsafe
.Add(ref Unsafe
.As
<byte, T
>(ref array
.GetRawSzArrayData()), index
);
1348 ref T last
= ref Unsafe
.Add(ref Unsafe
.Add(ref first
, length
), -1);
1354 first
= ref Unsafe
.Add(ref first
, 1);
1355 last
= ref Unsafe
.Add(ref last
, -1);
1356 } while (Unsafe
.IsAddressLessThan(ref first
, ref last
));
1359 // Sorts the elements of an array. The sort compares the elements to each
1360 // other using the IComparable interface, which must be implemented
1361 // by all elements of the array.
1363 public static void Sort(Array array
)
1366 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1367 Sort(array
, null, array
.GetLowerBound(0), array
.Length
, null);
1370 // Sorts the elements of two arrays based on the keys in the first array.
1371 // Elements in the keys array specify the sort keys for
1372 // corresponding elements in the items array. The sort compares the
1373 // keys to each other using the IComparable interface, which must be
1374 // implemented by all elements of the keys array.
1376 public static void Sort(Array keys
, Array
? items
)
1379 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.keys
);
1380 Sort(keys
, items
, keys
.GetLowerBound(0), keys
.Length
, null);
1383 // Sorts the elements in a section of an array. The sort compares the
1384 // elements to each other using the IComparable interface, which
1385 // must be implemented by all elements in the given section of the array.
1387 public static void Sort(Array array
, int index
, int length
)
1389 Sort(array
, null, index
, length
, null);
1392 // Sorts the elements in a section of two arrays based on the keys in the
1393 // first array. Elements in the keys array specify the sort keys for
1394 // corresponding elements in the items array. The sort compares the
1395 // keys to each other using the IComparable interface, which must be
1396 // implemented by all elements of the keys array.
1398 public static void Sort(Array keys
, Array
? items
, int index
, int length
)
1400 Sort(keys
, items
, index
, length
, null);
1403 // Sorts the elements of an array. The sort compares the elements to each
1404 // other using the given IComparer interface. If comparer is
1405 // null, the elements are compared to each other using the
1406 // IComparable interface, which in that case must be implemented by
1407 // all elements of the array.
1409 public static void Sort(Array array
, IComparer
? comparer
)
1412 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1413 Sort(array
, null, array
.GetLowerBound(0), array
.Length
, comparer
);
1416 // Sorts the elements of two arrays based on the keys in the first array.
1417 // Elements in the keys array specify the sort keys for
1418 // corresponding elements in the items array. The sort compares the
1419 // keys to each other using the given IComparer interface. If
1420 // comparer is null, the elements are compared to each other using
1421 // the IComparable interface, which in that case must be implemented
1422 // by all elements of the keys array.
1424 public static void Sort(Array keys
, Array
? items
, IComparer
? comparer
)
1427 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.keys
);
1428 Sort(keys
, items
, keys
.GetLowerBound(0), keys
.Length
, comparer
);
1431 // Sorts the elements in a section of an array. The sort compares the
1432 // elements to each other using the given IComparer interface. If
1433 // comparer is null, the elements are compared to each other using
1434 // the IComparable interface, which in that case must be implemented
1435 // by all elements in the given section of the array.
1437 public static void Sort(Array array
, int index
, int length
, IComparer
? comparer
)
1439 Sort(array
, null, index
, length
, comparer
);
1442 // Sorts the elements in a section of two arrays based on the keys in the
1443 // first array. Elements in the keys array specify the sort keys for
1444 // corresponding elements in the items array. The sort compares the
1445 // keys to each other using the given IComparer interface. If
1446 // comparer is null, the elements are compared to each other using
1447 // the IComparable interface, which in that case must be implemented
1448 // by all elements of the given section of the keys array.
1450 public static void Sort(Array keys
, Array
? items
, int index
, int length
, IComparer
? comparer
)
1453 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.keys
);
1454 if (keys
.Rank
!= 1 || (items
!= null && items
.Rank
!= 1))
1455 ThrowHelper
.ThrowRankException(ExceptionResource
.Rank_MultiDimNotSupported
);
1456 int keysLowerBound
= keys
.GetLowerBound(0);
1457 if (items
!= null && keysLowerBound
!= items
.GetLowerBound(0))
1458 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Arg_LowerBoundsMustMatch
);
1459 if (index
< keysLowerBound
)
1460 ThrowHelper
.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
1462 ThrowHelper
.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
1464 if (keys
.Length
- (index
- keysLowerBound
) < length
|| (items
!= null && (index
- keysLowerBound
) > items
.Length
- length
))
1465 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Argument_InvalidOffLen
);
1469 SortImpl(keys
, items
, index
, length
, comparer
?? Comparer
.Default
);
1473 public static void Sort
<T
>(T
[] array
)
1476 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1477 Sort
<T
>(array
, 0, array
.Length
, null);
1480 public static void Sort
<TKey
, TValue
>(TKey
[] keys
, TValue
[]? items
)
1483 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.keys
);
1484 Sort
<TKey
, TValue
>(keys
, items
, 0, keys
.Length
, null);
1487 public static void Sort
<T
>(T
[] array
, int index
, int length
)
1489 Sort
<T
>(array
, index
, length
, null);
1492 public static void Sort
<TKey
, TValue
>(TKey
[] keys
, TValue
[]? items
, int index
, int length
)
1494 Sort
<TKey
, TValue
>(keys
, items
, index
, length
, null);
1497 public static void Sort
<T
>(T
[] array
, System
.Collections
.Generic
.IComparer
<T
>? comparer
)
1500 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1501 Sort
<T
>(array
, 0, array
.Length
, comparer
);
1504 public static void Sort
<TKey
, TValue
>(TKey
[] keys
, TValue
[]? items
, System
.Collections
.Generic
.IComparer
<TKey
>? comparer
)
1507 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.keys
);
1508 Sort
<TKey
, TValue
>(keys
, items
, 0, keys
.Length
, comparer
);
1511 public static void Sort
<T
>(T
[] array
, int index
, int length
, System
.Collections
.Generic
.IComparer
<T
>? comparer
)
1514 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1516 ThrowHelper
.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
1518 ThrowHelper
.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
1519 if (array
.Length
- index
< length
)
1520 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Argument_InvalidOffLen
);
1525 if (comparer
== null || comparer
== Comparer
<T
>.Default
)
1527 if (TrySZSort(array
, null, index
, index
+ length
- 1))
1534 ArraySortHelper
<T
>.Default
.Sort(array
, index
, length
, comparer
);
1538 public static void Sort
<TKey
, TValue
>(TKey
[] keys
, TValue
[]? items
, int index
, int length
, System
.Collections
.Generic
.IComparer
<TKey
>? comparer
)
1541 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.keys
);
1543 ThrowHelper
.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
1545 ThrowHelper
.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
1546 if (keys
.Length
- index
< length
|| (items
!= null && index
> items
.Length
- length
))
1547 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Argument_InvalidOffLen
);
1552 if (comparer
== null || comparer
== Comparer
<TKey
>.Default
)
1554 if (TrySZSort(keys
, items
, index
, index
+ length
- 1))
1563 Sort
<TKey
>(keys
, index
, length
, comparer
);
1567 ArraySortHelper
<TKey
, TValue
>.Default
.Sort(keys
, items
, index
, length
, comparer
);
1571 public static void Sort
<T
>(T
[] array
, Comparison
<T
> comparison
)
1575 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1578 if (comparison
== null)
1580 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.comparison
);
1583 ArraySortHelper
<T
>.Sort(array
, 0, array
.Length
, comparison
!);
1586 public static bool TrueForAll
<T
>(T
[] array
, Predicate
<T
> match
)
1590 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
1595 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.match
);
1598 for (int i
= 0; i
< array
.Length
; i
++)
1600 if (!match(array
[i
]))
1609 // Private value type used by the Sort methods.
1610 private readonly struct SorterObjectArray
1612 private readonly object[] keys
;
1613 private readonly object?[]? items
;
1614 private readonly IComparer comparer
;
1616 internal SorterObjectArray(object[] keys
, object?[]? items
, IComparer comparer
)
1620 this.comparer
= comparer
;
1623 internal void SwapIfGreaterWithItems(int a
, int b
)
1627 if (comparer
.Compare(keys
[a
], keys
[b
]) > 0)
1629 object temp
= keys
[a
];
1634 object? item
= items
[a
];
1635 items
[a
] = items
[b
];
1642 private void Swap(int i
, int j
)
1650 object? item
= items
[i
];
1651 items
[i
] = items
[j
];
1656 internal void Sort(int left
, int length
)
1658 IntrospectiveSort(left
, length
);
1661 private void IntrospectiveSort(int left
, int length
)
1668 IntroSort(left
, length
+ left
- 1, 2 * IntrospectiveSortUtilities
.FloorLog2PlusOne(length
));
1670 catch (IndexOutOfRangeException
)
1672 IntrospectiveSortUtilities
.ThrowOrIgnoreBadComparer(comparer
);
1676 ThrowHelper
.ThrowInvalidOperationException(ExceptionResource
.InvalidOperation_IComparerFailed
, e
);
1680 private void IntroSort(int lo
, int hi
, int depthLimit
)
1684 int partitionSize
= hi
- lo
+ 1;
1685 if (partitionSize
<= IntrospectiveSortUtilities
.IntrosortSizeThreshold
)
1687 if (partitionSize
== 1)
1691 if (partitionSize
== 2)
1693 SwapIfGreaterWithItems(lo
, hi
);
1696 if (partitionSize
== 3)
1698 SwapIfGreaterWithItems(lo
, hi
- 1);
1699 SwapIfGreaterWithItems(lo
, hi
);
1700 SwapIfGreaterWithItems(hi
- 1, hi
);
1704 InsertionSort(lo
, hi
);
1708 if (depthLimit
== 0)
1715 int p
= PickPivotAndPartition(lo
, hi
);
1716 IntroSort(p
+ 1, hi
, depthLimit
);
1721 private int PickPivotAndPartition(int lo
, int hi
)
1723 // Compute median-of-three. But also partition them, since we've done the comparison.
1724 int mid
= lo
+ (hi
- lo
) / 2;
1725 // Sort lo, mid and hi appropriately, then pick mid as the pivot.
1726 SwapIfGreaterWithItems(lo
, mid
);
1727 SwapIfGreaterWithItems(lo
, hi
);
1728 SwapIfGreaterWithItems(mid
, hi
);
1730 object pivot
= keys
[mid
];
1732 int left
= lo
, right
= hi
- 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
1734 while (left
< right
)
1736 while (comparer
.Compare(keys
[++left
], pivot
) < 0) ;
1737 while (comparer
.Compare(pivot
, keys
[--right
]) < 0) ;
1745 // Put pivot in the right location.
1750 private void Heapsort(int lo
, int hi
)
1752 int n
= hi
- lo
+ 1;
1753 for (int i
= n
/ 2; i
>= 1; i
--)
1757 for (int i
= n
; i
> 1; i
--)
1759 Swap(lo
, lo
+ i
- 1);
1761 DownHeap(1, i
- 1, lo
);
1765 private void DownHeap(int i
, int n
, int lo
)
1767 object d
= keys
[lo
+ i
- 1];
1768 object? dt
= items
?[lo
+ i
- 1];
1773 if (child
< n
&& comparer
.Compare(keys
[lo
+ child
- 1], keys
[lo
+ child
]) < 0)
1777 if (!(comparer
.Compare(d
, keys
[lo
+ child
- 1]) < 0))
1779 keys
[lo
+ i
- 1] = keys
[lo
+ child
- 1];
1781 items
[lo
+ i
- 1] = items
[lo
+ child
- 1];
1784 keys
[lo
+ i
- 1] = d
;
1786 items
[lo
+ i
- 1] = dt
;
1789 private void InsertionSort(int lo
, int hi
)
1794 for (i
= lo
; i
< hi
; i
++)
1799 while (j
>= lo
&& comparer
.Compare(t
, keys
[j
]) < 0)
1801 keys
[j
+ 1] = keys
[j
];
1803 items
[j
+ 1] = items
[j
];
1813 // Private value used by the Sort methods for instances of Array.
1814 // This is slower than the one for Object[], since we can't use the JIT helpers
1815 // to access the elements. We must use GetValue & SetValue.
1816 private readonly struct SorterGenericArray
1818 private readonly Array keys
;
1819 private readonly Array
? items
;
1820 private readonly IComparer comparer
;
1822 internal SorterGenericArray(Array keys
, Array
? items
, IComparer comparer
)
1826 this.comparer
= comparer
;
1829 internal void SwapIfGreaterWithItems(int a
, int b
)
1833 if (comparer
.Compare(keys
.GetValue(a
), keys
.GetValue(b
)) > 0)
1835 object? key
= keys
.GetValue(a
);
1836 keys
.SetValue(keys
.GetValue(b
), a
);
1837 keys
.SetValue(key
, b
);
1840 object? item
= items
.GetValue(a
);
1841 items
.SetValue(items
.GetValue(b
), a
);
1842 items
.SetValue(item
, b
);
1848 private void Swap(int i
, int j
)
1850 object? t1
= keys
.GetValue(i
);
1851 keys
.SetValue(keys
.GetValue(j
), i
);
1852 keys
.SetValue(t1
, j
);
1856 object? t2
= items
.GetValue(i
);
1857 items
.SetValue(items
.GetValue(j
), i
);
1858 items
.SetValue(t2
, j
);
1862 internal void Sort(int left
, int length
)
1864 IntrospectiveSort(left
, length
);
1867 private void IntrospectiveSort(int left
, int length
)
1874 IntroSort(left
, length
+ left
- 1, 2 * IntrospectiveSortUtilities
.FloorLog2PlusOne(length
));
1876 catch (IndexOutOfRangeException
)
1878 IntrospectiveSortUtilities
.ThrowOrIgnoreBadComparer(comparer
);
1882 ThrowHelper
.ThrowInvalidOperationException(ExceptionResource
.InvalidOperation_IComparerFailed
, e
);
1886 private void IntroSort(int lo
, int hi
, int depthLimit
)
1890 int partitionSize
= hi
- lo
+ 1;
1891 if (partitionSize
<= IntrospectiveSortUtilities
.IntrosortSizeThreshold
)
1893 if (partitionSize
== 1)
1897 if (partitionSize
== 2)
1899 SwapIfGreaterWithItems(lo
, hi
);
1902 if (partitionSize
== 3)
1904 SwapIfGreaterWithItems(lo
, hi
- 1);
1905 SwapIfGreaterWithItems(lo
, hi
);
1906 SwapIfGreaterWithItems(hi
- 1, hi
);
1910 InsertionSort(lo
, hi
);
1914 if (depthLimit
== 0)
1921 int p
= PickPivotAndPartition(lo
, hi
);
1922 IntroSort(p
+ 1, hi
, depthLimit
);
1927 private int PickPivotAndPartition(int lo
, int hi
)
1929 // Compute median-of-three. But also partition them, since we've done the comparison.
1930 int mid
= lo
+ (hi
- lo
) / 2;
1932 SwapIfGreaterWithItems(lo
, mid
);
1933 SwapIfGreaterWithItems(lo
, hi
);
1934 SwapIfGreaterWithItems(mid
, hi
);
1936 object? pivot
= keys
.GetValue(mid
);
1938 int left
= lo
, right
= hi
- 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
1940 while (left
< right
)
1942 while (comparer
.Compare(keys
.GetValue(++left
), pivot
) < 0) ;
1943 while (comparer
.Compare(pivot
, keys
.GetValue(--right
)) < 0) ;
1951 // Put pivot in the right location.
1956 private void Heapsort(int lo
, int hi
)
1958 int n
= hi
- lo
+ 1;
1959 for (int i
= n
/ 2; i
>= 1; i
--)
1963 for (int i
= n
; i
> 1; i
--)
1965 Swap(lo
, lo
+ i
- 1);
1967 DownHeap(1, i
- 1, lo
);
1971 private void DownHeap(int i
, int n
, int lo
)
1973 object? d
= keys
.GetValue(lo
+ i
- 1);
1974 object? dt
= items
?.GetValue(lo
+ i
- 1);
1979 if (child
< n
&& comparer
.Compare(keys
.GetValue(lo
+ child
- 1), keys
.GetValue(lo
+ child
)) < 0)
1984 if (!(comparer
.Compare(d
, keys
.GetValue(lo
+ child
- 1)) < 0))
1987 keys
.SetValue(keys
.GetValue(lo
+ child
- 1), lo
+ i
- 1);
1989 items
.SetValue(items
.GetValue(lo
+ child
- 1), lo
+ i
- 1);
1992 keys
.SetValue(d
, lo
+ i
- 1);
1994 items
.SetValue(dt
, lo
+ i
- 1);
1997 private void InsertionSort(int lo
, int hi
)
2002 for (i
= lo
; i
< hi
; i
++)
2005 t
= keys
.GetValue(i
+ 1);
2006 dt
= items
?.GetValue(i
+ 1);
2008 while (j
>= lo
&& comparer
.Compare(t
, keys
.GetValue(j
)) < 0)
2010 keys
.SetValue(keys
.GetValue(j
), j
+ 1);
2012 items
.SetValue(items
.GetValue(j
), j
+ 1);
2016 keys
.SetValue(t
, j
+ 1);
2018 items
.SetValue(dt
, j
+ 1);
2023 public IEnumerator
GetEnumerator()
2025 int lowerBound
= GetLowerBound(0);
2026 if (Rank
== 1 && lowerBound
== 0)
2027 return new SZArrayEnumerator(this);
2029 return new ArrayEnumerator(this, lowerBound
, Length
);