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 Internal
.Runtime
.CompilerServices
;
6 using System
.Collections
;
7 using System
.Collections
.Generic
;
8 using System
.Runtime
.CompilerServices
;
9 using System
.Runtime
.InteropServices
;
15 [StructLayout(LayoutKind
.Sequential
)]
25 int length
= GetLength (0);
27 for (int i
= 1; i
< Rank
; i
++) {
28 length
*= GetLength (i
);
34 public long LongLength
{
36 long length
= GetLength (0);
38 for (int i
= 1; i
< Rank
; i
++) {
39 length
*= GetLength (i
);
51 public static void Clear (Array array
, int index
, int length
)
54 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
56 ThrowHelper
.ThrowIndexOutOfRangeException();
58 int low
= array
!.GetLowerBound (0);
60 ThrowHelper
.ThrowIndexOutOfRangeException();
64 // re-ordered to avoid possible integer overflow
65 if (index
> array
.Length
- length
)
66 ThrowHelper
.ThrowIndexOutOfRangeException();
68 ClearInternal (array
, index
, length
);
71 public static void ConstrainedCopy (Array sourceArray
, int sourceIndex
, Array destinationArray
, int destinationIndex
, int length
)
73 Copy (sourceArray
, sourceIndex
, destinationArray
, destinationIndex
, length
, true);
76 public static void Copy (Array sourceArray
, Array destinationArray
, int length
)
78 if (sourceArray
== null)
79 throw new ArgumentNullException ("sourceArray");
81 if (destinationArray
== null)
82 throw new ArgumentNullException ("destinationArray");
84 Copy (sourceArray
, sourceArray
.GetLowerBound (0), destinationArray
,
85 destinationArray
.GetLowerBound (0), length
);
88 public static void Copy (Array sourceArray
, int sourceIndex
, Array destinationArray
, int destinationIndex
, int length
)
90 Copy (sourceArray
, sourceIndex
, destinationArray
, destinationIndex
, length
, false);
93 private static void Copy (Array sourceArray
, int sourceIndex
, Array destinationArray
, int destinationIndex
, int length
, bool reliable
)
95 if (sourceArray
== null)
96 throw new ArgumentNullException (nameof (sourceArray
));
98 if (destinationArray
== null)
99 throw new ArgumentNullException (nameof (destinationArray
));
102 throw new ArgumentOutOfRangeException (nameof (length
), "Value has to be >= 0.");
104 if (sourceArray
.Rank
!= destinationArray
.Rank
)
105 throw new RankException(SR
.Rank_MultiDimNotSupported
);
108 throw new ArgumentOutOfRangeException (nameof (sourceIndex
), "Value has to be >= 0.");
110 if (destinationIndex
< 0)
111 throw new ArgumentOutOfRangeException (nameof (destinationIndex
), "Value has to be >= 0.");
113 if (FastCopy (sourceArray
, sourceIndex
, destinationArray
, destinationIndex
, length
))
116 int source_pos
= sourceIndex
- sourceArray
.GetLowerBound (0);
117 int dest_pos
= destinationIndex
- destinationArray
.GetLowerBound (0);
120 throw new ArgumentOutOfRangeException (nameof (sourceIndex
), "Index was less than the array's lower bound in the first dimension.");
123 throw new ArgumentOutOfRangeException (nameof (destinationIndex
), "Index was less than the array's lower bound in the first dimension.");
125 // re-ordered to avoid possible integer overflow
126 if (source_pos
> sourceArray
.Length
- length
)
127 throw new ArgumentException (SR
.Arg_LongerThanSrcArray
, nameof (sourceArray
));
129 if (dest_pos
> destinationArray
.Length
- length
) {
130 throw new ArgumentException ("Destination array was not long enough. Check destIndex and length, and the array's lower bounds", nameof (destinationArray
));
133 Type src_type
= sourceArray
.GetType ().GetElementType ()!;
134 Type dst_type
= destinationArray
.GetType ().GetElementType ()!;
135 var dst_type_vt
= dst_type
.IsValueType
&& Nullable
.GetUnderlyingType (dst_type
) == null;
137 bool src_is_enum
= src_type
.IsEnum
;
138 bool dst_is_enum
= dst_type
.IsEnum
;
141 src_type
= Enum
.GetUnderlyingType (src_type
);
143 dst_type
= Enum
.GetUnderlyingType (dst_type
);
146 if (!dst_type
.Equals (src_type
) &&
147 !(dst_type
.IsPrimitive
&& src_type
.IsPrimitive
&& CanChangePrimitive(dst_type
, src_type
, true))) {
148 throw new ArrayTypeMismatchException (SR
.ArrayTypeMismatch_CantAssignType
);
151 if (!CanAssignArrayElement (src_type
, dst_type
)) {
152 throw new ArrayTypeMismatchException (SR
.ArrayTypeMismatch_CantAssignType
);
156 if (!Object
.ReferenceEquals (sourceArray
, destinationArray
) || source_pos
> dest_pos
) {
157 for (int i
= 0; i
< length
; i
++) {
158 Object srcval
= sourceArray
.GetValueImpl (source_pos
+ i
);
160 if (!src_type
.IsValueType
&& dst_is_enum
)
161 throw new InvalidCastException (SR
.InvalidCast_DownCastArrayElement
);
163 if (dst_type_vt
&& (srcval
== null || (src_type
== typeof (object) && srcval
.GetType () != dst_type
)))
164 throw new InvalidCastException ();
167 destinationArray
.SetValueRelaxedImpl (srcval
, dest_pos
+ i
);
168 } catch (ArgumentException
) {
169 throw CreateArrayTypeMismatchException ();
173 for (int i
= length
- 1; i
>= 0; i
--) {
174 Object srcval
= sourceArray
.GetValueImpl (source_pos
+ i
);
177 destinationArray
.SetValueRelaxedImpl (srcval
, dest_pos
+ i
);
178 } catch (ArgumentException
) {
179 throw CreateArrayTypeMismatchException ();
185 static ArrayTypeMismatchException
CreateArrayTypeMismatchException ()
187 return new ArrayTypeMismatchException ();
190 static bool CanAssignArrayElement (Type source
, Type target
)
192 if (!target
.IsValueType
&& !target
.IsPointer
) {
193 if (!source
.IsValueType
&& !source
.IsPointer
) {
194 // Reference to reference copy
196 source
.IsInterface
|| target
.IsInterface
||
197 source
.IsAssignableFrom (target
) || target
.IsAssignableFrom (source
);
199 // Value to reference copy
200 if (source
.IsPointer
)
202 return target
.IsAssignableFrom (source
);
205 if (source
.IsEquivalentTo (target
)) {
207 } else if (source
.IsPointer
&& target
.IsPointer
) {
209 } else if (source
.IsPrimitive
&& target
.IsPrimitive
) {
211 // Allow primitive type widening
212 return CanChangePrimitive (source
, target
, false);
213 } else if (!source
.IsValueType
&& !source
.IsPointer
) {
214 // Source is base class or interface of destination type
215 if (target
.IsPointer
)
217 return source
.IsAssignableFrom (target
);
224 public static Array
CreateInstance (Type elementType
, int length
)
227 throw new ArgumentOutOfRangeException (nameof (length
));
229 int[] lengths
= {length}
;
231 return CreateInstance (elementType
, lengths
);
234 public static Array
CreateInstance (Type elementType
, int length1
, int length2
)
237 throw new ArgumentOutOfRangeException (nameof (length1
));
239 throw new ArgumentOutOfRangeException (nameof (length2
));
241 int[] lengths
= {length1, length2}
;
243 return CreateInstance (elementType
, lengths
);
246 public static Array
CreateInstance (Type elementType
, int length1
, int length2
, int length3
)
249 throw new ArgumentOutOfRangeException (nameof (length1
));
251 throw new ArgumentOutOfRangeException (nameof (length2
));
253 throw new ArgumentOutOfRangeException (nameof (length3
));
255 int[] lengths
= {length1, length2, length3}
;
257 return CreateInstance (elementType
, lengths
);
260 public static Array
CreateInstance (Type elementType
, params int[] lengths
)
262 if (elementType
== null)
263 throw new ArgumentNullException ("elementType");
265 throw new ArgumentNullException ("lengths");
266 if (lengths
.Length
== 0)
267 throw new ArgumentException (nameof (lengths
));
268 if (lengths
.Length
> 255)
269 throw new TypeLoadException ();
270 for (int i
= 0; i
< lengths
.Length
; ++i
) {
272 throw new ArgumentOutOfRangeException ($"lengths[{i}]", SR
.ArgumentOutOfRange_NeedNonNegNum
);
275 if (!(elementType
.UnderlyingSystemType
is RuntimeType et
))
276 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
277 if (et
.Equals (typeof (void)))
278 throw new NotSupportedException ("Array type can not be void");
279 if (et
.ContainsGenericParameters
)
280 throw new NotSupportedException ("Array type can not be an open generic type");
282 throw new NotSupportedException (SR
.NotSupported_Type
);
284 return CreateInstanceImpl (et
, lengths
, null);
287 public static Array
CreateInstance (Type elementType
, int[] lengths
, int [] lowerBounds
)
289 if (elementType
== null)
290 throw new ArgumentNullException ("elementType");
292 throw new ArgumentNullException ("lengths");
293 if (lowerBounds
== null)
294 throw new ArgumentNullException ("lowerBounds");
296 if (!(elementType
.UnderlyingSystemType
is RuntimeType rt
))
297 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
298 if (rt
.Equals (typeof (void)))
299 throw new NotSupportedException ("Array type can not be void");
300 if (rt
.ContainsGenericParameters
)
301 throw new NotSupportedException ("Array type can not be an open generic type");
303 throw new NotSupportedException (SR
.NotSupported_Type
);
305 if (lengths
.Length
< 1)
306 throw new ArgumentException ("Arrays must contain >= 1 elements.");
308 if (lengths
.Length
!= lowerBounds
.Length
)
309 throw new ArgumentException ("Arrays must be of same size.");
311 for (int j
= 0; j
< lowerBounds
.Length
; j
++) {
313 throw new ArgumentOutOfRangeException ($"lengths[{j}]", "Each value has to be >= 0.");
314 if ((long)lowerBounds
[j
] + (long)lengths
[j
] > (long)Int32
.MaxValue
)
315 throw new ArgumentOutOfRangeException (null, "Length + bound must not exceed Int32.MaxValue.");
318 if (lengths
.Length
> 255)
319 throw new TypeLoadException ();
321 return CreateInstanceImpl (elementType
, lengths
, lowerBounds
);
324 public object GetValue (int index
)
327 ThrowHelper
.ThrowArgumentException (ExceptionResource
.Arg_Need1DArray
);
329 var lb
= GetLowerBound (0);
330 if (index
< lb
|| index
> GetUpperBound (0))
331 throw new IndexOutOfRangeException ("Index has to be between upper and lower bound of the array.");
333 if (GetType ().GetElementType ()!.IsPointer
)
334 throw new NotSupportedException (SR
.NotSupported_Type
);
336 return GetValueImpl (index
- lb
);
339 public object GetValue (int index1
, int index2
)
342 ThrowHelper
.ThrowArgumentException (ExceptionResource
.Arg_Need2DArray
);
344 int[] ind
= {index1, index2}
;
345 return GetValue (ind
);
348 public object GetValue (int index1
, int index2
, int index3
)
351 ThrowHelper
.ThrowArgumentException (ExceptionResource
.Arg_Need3DArray
);
353 int[] ind
= {index1, index2, index3}
;
354 return GetValue (ind
);
357 public void Initialize ()
361 static int IndexOfImpl
<T
>(T
[] array
, T
value, int startIndex
, int count
)
363 return EqualityComparer
<T
>.Default
.IndexOf (array
, value, startIndex
, count
);
366 static int LastIndexOfImpl
<T
>(T
[] array
, T
value, int startIndex
, int count
)
368 return EqualityComparer
<T
>.Default
.LastIndexOf (array
, value, startIndex
, count
);
371 public void SetValue (object? value, int index
)
374 ThrowHelper
.ThrowArgumentException (ExceptionResource
.Arg_Need1DArray
);
376 var lb
= GetLowerBound (0);
377 if (index
< lb
|| index
> GetUpperBound (0))
378 throw new IndexOutOfRangeException ("Index has to be >= lower bound and <= upper bound of the array.");
380 if (GetType ().GetElementType ()!.IsPointer
)
381 throw new NotSupportedException (SR
.NotSupported_Type
);
383 SetValueImpl (value, index
- lb
);
386 public void SetValue (object? value, int index1
, int index2
)
389 ThrowHelper
.ThrowArgumentException (ExceptionResource
.Arg_Need2DArray
);
391 int[] ind
= {index1, index2}
;
392 SetValue (value, ind
);
395 public void SetValue (object? value, int index1
, int index2
, int index3
)
398 ThrowHelper
.ThrowArgumentException (ExceptionResource
.Arg_Need3DArray
);
400 int[] ind
= {index1, index2, index3}
;
401 SetValue (value, ind
);
404 static void SortImpl (Array keys
, Array
? items
, int index
, int length
, IComparer comparer
)
406 /* TODO: CoreCLR optimizes this case via an internal call
407 if (comparer == Comparer.Default)
409 bool r = TrySZSort(keys, items, index, index + length - 1);
414 object[]? objKeys
= keys
as object[];
415 object[]? objItems
= null;
417 objItems
= items
as object[];
418 if (objKeys
!= null && (items
== null || objItems
!= null)) {
419 SorterObjectArray sorter
= new SorterObjectArray (objKeys
, objItems
, comparer
);
420 sorter
.Sort(index
, length
);
422 SorterGenericArray sorter
= new SorterGenericArray (keys
, items
, comparer
);
423 sorter
.Sort(index
, length
);
427 public int GetUpperBound (int dimension
)
429 return GetLowerBound (dimension
) + GetLength (dimension
) - 1;
433 [MethodImpl (MethodImplOptions
.AggressiveInlining
)]
434 internal ref byte GetRawSzArrayData ()
436 return ref Unsafe
.As
<RawData
>(this).Data
;
440 [MethodImpl (MethodImplOptions
.AggressiveInlining
)]
441 internal ref byte GetRawArrayData ()
443 return ref Unsafe
.As
<RawData
>(this).Data
;
446 internal int GetElementSize ()
448 return Marshal
.GetArrayElementSize (GetType ());
452 // Moved value from instance into target of different type with no checks (JIT intristics)
456 // S and R must either:
457 // both be blitable valuetypes
458 // both be reference types (IOW, an unsafe cast)
459 // S and R cannot be float or double
460 // S and R must either:
463 // S and R must either:
465 // both be a scalar of size <= 4
467 internal static R UnsafeMov
<S
,R
> (S instance
)
469 return (R
)(object) instance
;
472 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
473 extern static void ClearInternal (Array a
, int index
, int count
);
475 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
476 extern static Array
CreateInstanceImpl (Type elementType
, int[] lengths
, int[]? bounds
);
478 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
479 extern static bool CanChangePrimitive (Type srcType
, Type dstType
, bool reliable
);
481 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
482 internal extern static bool FastCopy (Array source
, int source_idx
, Array dest
, int dest_idx
, int length
);
484 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
485 extern int GetRank ();
487 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
488 public extern int GetLength (int dimension
);
490 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
491 public extern int GetLowerBound (int dimension
);
493 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
494 public extern object GetValue (params int[] indices
);
496 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
497 public extern void SetValue (object? value, params int[] indices
);
499 // CAUTION! No bounds checking!
500 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
501 extern static void GetGenericValue_icall
<T
> (ref Array self
, int pos
, out T
value);
503 // CAUTION! No bounds checking!
504 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
505 extern object GetValueImpl (int pos
);
507 // CAUTION! No bounds checking!
508 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
509 extern static void SetGenericValue_icall
<T
> (ref Array self
, int pos
, ref T
value);
511 // This is a special case in the runtime.
512 void GetGenericValueImpl
<T
> (int pos
, out T
value)
515 GetGenericValue_icall (ref self
, pos
, out value);
518 // This is a special case in the runtime.
519 void SetGenericValueImpl
<T
> (int pos
, ref T
value)
522 SetGenericValue_icall (ref self
, pos
, ref value);
525 // CAUTION! No bounds checking!
526 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
527 extern void SetValueImpl (object? value, int pos
);
529 // CAUTION! No bounds checking!
530 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
531 extern void SetValueRelaxedImpl (object? value, int pos
);
534 * These methods are used to implement the implicit generic interfaces
535 * implemented by arrays in NET 2.0.
536 * Only make those methods generic which really need it, to avoid
537 * creating useless instantiations.
539 internal int InternalArray__ICollection_get_Count ()
544 internal bool InternalArray__ICollection_get_IsReadOnly ()
549 internal IEnumerator
<T
> InternalArray__IEnumerable_GetEnumerator
<T
> ()
551 return Length
== 0 ? SZGenericArrayEnumerator
<T
>.Empty
: new SZGenericArrayEnumerator
<T
> (Unsafe
.As
<T
[]> (this));
554 internal void InternalArray__ICollection_Clear ()
556 ThrowHelper
.ThrowNotSupportedException (ExceptionResource
.NotSupported_ReadOnlyCollection
);
559 internal void InternalArray__ICollection_Add
<T
> (T item
)
561 ThrowHelper
.ThrowNotSupportedException (ExceptionResource
.NotSupported_FixedSizeCollection
);
564 internal bool InternalArray__ICollection_Remove
<T
> (T item
)
566 ThrowHelper
.ThrowNotSupportedException (ExceptionResource
.NotSupported_FixedSizeCollection
);
570 internal bool InternalArray__ICollection_Contains
<T
> (T item
)
572 return IndexOf ((T
[])this, item
, 0, Length
) >= 0;
575 internal void InternalArray__ICollection_CopyTo
<T
> (T
[] array
, int arrayIndex
)
577 Copy (this, GetLowerBound (0), array
, arrayIndex
, Length
);
580 internal T InternalArray__IReadOnlyList_get_Item
<T
> (int index
)
582 if ((uint)index
>= (uint)Length
)
583 ThrowHelper
.ThrowArgumentOutOfRange_IndexException ();
586 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
587 GetGenericValueImpl (index
, out value);
591 internal int InternalArray__IReadOnlyCollection_get_Count ()
596 internal void InternalArray__Insert
<T
> (int index
, T item
)
598 ThrowHelper
.ThrowNotSupportedException (ExceptionResource
.NotSupported_FixedSizeCollection
);
601 internal void InternalArray__RemoveAt (int index
)
603 ThrowHelper
.ThrowNotSupportedException (ExceptionResource
.NotSupported_FixedSizeCollection
);
606 internal int InternalArray__IndexOf
<T
> (T item
)
608 return IndexOf ((T
[])this, item
, 0, Length
);
611 internal T InternalArray__get_Item
<T
> (int index
)
613 if ((uint)index
>= (uint)Length
)
614 ThrowHelper
.ThrowArgumentOutOfRange_IndexException ();
617 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
618 GetGenericValueImpl (index
, out value);
622 internal void InternalArray__set_Item
<T
> (int index
, T item
)
624 if ((uint)index
>= (uint)Length
)
625 ThrowHelper
.ThrowArgumentOutOfRange_IndexException();
627 if (this is object[] oarray
) {
628 oarray
! [index
] = (object)item
;
632 // Do not change this to call SetGenericValue_icall directly, due to special casing in the runtime.
633 SetGenericValueImpl (index
, ref item
);