Make TypeNameParser consistently use tabs
[mono-project.git] / netcore / System.Private.CoreLib / src / System / Array.cs
blob05207607e6cbeaa05136dde16eb2005a914ecb87
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;
11 namespace System
13 partial class Array
15 [StructLayout(LayoutKind.Sequential)]
16 private class RawData
18 public IntPtr Bounds;
19 public IntPtr Count;
20 public byte Data;
23 public int Length {
24 get {
25 int length = GetLength (0);
27 for (int i = 1; i < Rank; i++) {
28 length *= GetLength (i);
30 return length;
34 public long LongLength {
35 get {
36 long length = GetLength (0);
38 for (int i = 1; i < Rank; i++) {
39 length *= GetLength (i);
41 return length;
45 public int Rank {
46 get {
47 return GetRank ();
51 public static void Clear (Array array, int index, int length)
53 if (array == null)
54 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
55 if (length < 0)
56 ThrowHelper.ThrowIndexOutOfRangeException();
58 int low = array!.GetLowerBound (0);
59 if (index < low)
60 ThrowHelper.ThrowIndexOutOfRangeException();
62 index = index - low;
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));
101 if (length < 0)
102 throw new ArgumentOutOfRangeException (nameof (length), "Value has to be >= 0.");
104 if (sourceArray.Rank != destinationArray.Rank)
105 throw new RankException(SR.Rank_MultiDimNotSupported);
107 if (sourceIndex < 0)
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))
114 return;
116 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
117 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
119 if (source_pos < 0)
120 throw new ArgumentOutOfRangeException (nameof (sourceIndex), "Index was less than the array's lower bound in the first dimension.");
122 if (dest_pos < 0)
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;
140 if (src_is_enum)
141 src_type = Enum.GetUnderlyingType (src_type);
142 if (dst_is_enum)
143 dst_type = Enum.GetUnderlyingType (dst_type);
145 if (reliable) {
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);
150 } else {
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 ();
166 try {
167 destinationArray.SetValueRelaxedImpl (srcval, dest_pos + i);
168 } catch (ArgumentException) {
169 throw CreateArrayTypeMismatchException ();
172 } else {
173 for (int i = length - 1; i >= 0; i--) {
174 Object srcval = sourceArray.GetValueImpl (source_pos + i);
176 try {
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
195 return
196 source.IsInterface || target.IsInterface ||
197 source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
198 } else {
199 // Value to reference copy
200 if (source.IsPointer)
201 return false;
202 return target.IsAssignableFrom (source);
204 } else {
205 if (source.IsEquivalentTo (target)) {
206 return true;
207 } else if (source.IsPointer && target.IsPointer) {
208 return true;
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)
216 return false;
217 return source.IsAssignableFrom (target);
221 return false;
224 public static Array CreateInstance (Type elementType, int length)
226 if (length < 0)
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)
236 if (length1 < 0)
237 throw new ArgumentOutOfRangeException (nameof (length1));
238 if (length2 < 0)
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)
248 if (length1 < 0)
249 throw new ArgumentOutOfRangeException (nameof (length1));
250 if (length2 < 0)
251 throw new ArgumentOutOfRangeException (nameof (length2));
252 if (length3 < 0)
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");
264 if (lengths == null)
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) {
271 if (lengths [i] < 0)
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");
281 if (et.IsByRef)
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");
291 if (lengths == null)
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");
302 if (rt.IsByRef)
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 ++) {
312 if (lengths [j] < 0)
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)
326 if (Rank != 1)
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)
341 if (Rank != 2)
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)
350 if (Rank != 3)
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)
373 if (Rank != 1)
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)
388 if (Rank != 2)
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)
397 if (Rank != 3)
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);
410 if (r)
411 return;
414 object[]? objKeys = keys as object[];
415 object[]? objItems = null;
416 if (objKeys != 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);
421 } else {
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;
432 [Intrinsic]
433 [MethodImpl (MethodImplOptions.AggressiveInlining)]
434 internal ref byte GetRawSzArrayData ()
436 return ref Unsafe.As<RawData>(this).Data;
439 [Intrinsic]
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)
454 // Restrictions:
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:
461 // both be a struct
462 // both be a scalar
463 // S and R must either:
464 // be of same size
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)
514 var self = this;
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)
521 var self = this;
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 ()
541 return Length;
544 internal bool InternalArray__ICollection_get_IsReadOnly ()
546 return true;
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);
567 return default;
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 ();
585 T value;
586 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
587 GetGenericValueImpl (index, out value);
588 return value;
591 internal int InternalArray__IReadOnlyCollection_get_Count ()
593 return Length;
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 ();
616 T value;
617 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
618 GetGenericValueImpl (index, out value);
619 return 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;
629 return;
632 // Do not change this to call SetGenericValue_icall directly, due to special casing in the runtime.
633 SetGenericValueImpl (index, ref item);