[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mcs / class / corlib / System / Array.cs
blobb9415e980e0b00180e684d06316f7246ebbe6166
1 //
2 // System.Array.cs
3 //
4 // Authors:
5 // Joe Shaw (joe@ximian.com)
6 // Martin Baulig (martin@gnome.org)
7 // Dietmar Maurer (dietmar@ximian.com)
8 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 // Jeffrey Stedfast (fejj@novell.com)
10 // Marek Safar (marek.safar@gmail.com)
12 // (C) 2001-2003 Ximian, Inc. http://www.ximian.com
13 // Copyright (C) 2004-2011 Novell, Inc (http://www.novell.com)
14 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 //
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 //
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
39 using System.Collections.Generic;
40 using System.Collections.ObjectModel;
41 using System.Runtime.ConstrainedExecution;
43 namespace System
45 public abstract partial class Array
47 // Constructor
48 private Array ()
52 * These methods are used to implement the implicit generic interfaces
53 * implemented by arrays in NET 2.0.
54 * Only make those methods generic which really need it, to avoid
55 * creating useless instantiations.
57 internal int InternalArray__ICollection_get_Count ()
59 return Length;
62 internal bool InternalArray__ICollection_get_IsReadOnly ()
64 return true;
67 // adapted to the Mono array layout
68 [StructLayout(LayoutKind.Sequential)]
69 private class RawData
71 public IntPtr Bounds;
72 public IntPtr Count;
73 public byte Data;
76 [MethodImpl(MethodImplOptions.AggressiveInlining)]
77 internal ref byte GetRawSzArrayData()
79 return ref Unsafe.As<RawData>(this).Data;
82 internal IEnumerator<T> InternalArray__IEnumerable_GetEnumerator<T> ()
84 if (Length == 0)
85 return EmptyInternalEnumerator<T>.Value;
86 else
87 return new InternalEnumerator<T> (this);
90 internal void InternalArray__ICollection_Clear ()
92 throw new NotSupportedException ("Collection is read-only");
95 internal void InternalArray__ICollection_Add<T> (T item)
97 throw new NotSupportedException ("Collection is of a fixed size");
100 internal bool InternalArray__ICollection_Remove<T> (T item)
102 throw new NotSupportedException ("Collection is of a fixed size");
105 internal bool InternalArray__ICollection_Contains<T> (T item)
107 if (this.Rank > 1)
108 throw new RankException ("Only single dimension arrays are supported.");
110 int length = this.Length;
111 for (int i = 0; i < length; i++) {
112 T value;
113 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
114 GetGenericValueImpl (i, out value);
115 if (item == null){
116 if (value == null) {
117 return true;
120 continue;
123 if (item.Equals (value)) {
124 return true;
128 return false;
131 internal void InternalArray__ICollection_CopyTo<T> (T[] array, int arrayIndex)
133 Copy (this, GetLowerBound (0), array, arrayIndex, Length);
136 internal T InternalArray__IReadOnlyList_get_Item<T> (int index)
138 if (unchecked ((uint) index) >= unchecked ((uint) Length))
139 throw new ArgumentOutOfRangeException ("index");
141 T value;
142 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
143 GetGenericValueImpl (index, out value);
144 return value;
147 internal int InternalArray__IReadOnlyCollection_get_Count ()
149 return Length;
152 internal void InternalArray__Insert<T> (int index, T item)
154 throw new NotSupportedException ("Collection is of a fixed size");
157 internal void InternalArray__RemoveAt (int index)
159 throw new NotSupportedException ("Collection is of a fixed size");
162 internal int InternalArray__IndexOf<T> (T item)
164 if (this.Rank > 1)
165 throw new RankException ("Only single dimension arrays are supported.");
167 int length = this.Length;
168 for (int i = 0; i < length; i++) {
169 T value;
170 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
171 GetGenericValueImpl (i, out value);
172 if (item == null){
173 if (value == null)
174 return i + this.GetLowerBound (0);
176 continue;
178 if (value.Equals (item))
179 // array index may not be zero-based.
180 // use lower bound
181 return i + this.GetLowerBound (0);
184 unchecked {
185 // lower bound may be MinValue
186 return this.GetLowerBound (0) - 1;
190 internal T InternalArray__get_Item<T> (int index)
192 if (unchecked ((uint) index) >= unchecked ((uint) Length))
193 throw new ArgumentOutOfRangeException ("index");
195 T value;
196 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
197 GetGenericValueImpl (index, out value);
198 return value;
201 internal void InternalArray__set_Item<T> (int index, T item)
203 if (unchecked ((uint) index) >= unchecked ((uint) Length))
204 throw new ArgumentOutOfRangeException ("index");
206 object[] oarray = this as object [];
207 if (oarray != null) {
208 oarray [index] = (object)item;
209 return;
211 // Do not change this to call SetGenericValue_icall directly, due to special casing in the runtime.
212 SetGenericValueImpl (index, ref item);
215 // CAUTION! No bounds checking!
216 [MethodImplAttribute (MethodImplOptions.InternalCall)]
217 extern static void GetGenericValue_icall<T> (ref Array self, int pos, out T value);
219 // CAUTION! No bounds checking!
220 [MethodImplAttribute (MethodImplOptions.InternalCall)]
221 extern static void SetGenericValue_icall<T> (ref Array self, int pos, ref T value);
223 // This is a special case in the runtime.
224 internal void GetGenericValueImpl<T> (int pos, out T value)
226 var self = this;
227 GetGenericValue_icall (ref self, pos, out value);
230 // This is a special case in the runtime.
231 internal void SetGenericValueImpl<T> (int pos, ref T value)
233 var self = this;
234 SetGenericValue_icall (ref self, pos, ref value);
237 internal struct InternalEnumerator<T> : IEnumerator<T>
239 const int NOT_STARTED = -2;
241 // this MUST be -1, because we depend on it in move next.
242 // we just decr the size, so, 0 - 1 == FINISHED
243 const int FINISHED = -1;
245 readonly Array array;
246 int idx;
248 internal InternalEnumerator (Array array)
250 this.array = array;
251 idx = NOT_STARTED;
254 public void Dispose ()
258 public bool MoveNext ()
260 if (idx == NOT_STARTED)
261 idx = array.Length;
263 return idx != FINISHED && -- idx != FINISHED;
266 public T Current {
267 get {
268 if (idx == NOT_STARTED)
269 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
270 if (idx == FINISHED)
271 throw new InvalidOperationException ("Enumeration already finished");
273 return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
277 void IEnumerator.Reset ()
279 idx = NOT_STARTED;
282 object IEnumerator.Current {
283 get {
284 return Current;
289 // Properties
290 public int Length {
291 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
292 get {
293 int length = this.GetLength (0);
295 for (int i = 1; i < this.Rank; i++) {
296 length *= this.GetLength (i);
298 return length;
302 public int Rank {
303 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
304 get {
305 return this.GetRank ();
309 internal class EmptyInternalEnumerator<T> : IEnumerator<T>
311 public static readonly EmptyInternalEnumerator<T> Value = new EmptyInternalEnumerator<T> ();
313 public void Dispose ()
315 return;
318 public bool MoveNext ()
320 return false;
323 public T Current {
324 get {
325 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
329 object IEnumerator.Current {
330 get {
331 return Current;
335 void IEnumerator.Reset ()
337 return;
341 // InternalCall Methods
342 [MethodImplAttribute (MethodImplOptions.InternalCall)]
343 extern int GetRank ();
345 [MethodImplAttribute (MethodImplOptions.InternalCall)]
346 public extern int GetLength (int dimension);
348 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
349 [MethodImplAttribute (MethodImplOptions.InternalCall)]
350 public extern int GetLowerBound (int dimension);
352 [MethodImplAttribute (MethodImplOptions.InternalCall)]
353 public extern object GetValue (params int[] indices);
355 [MethodImplAttribute (MethodImplOptions.InternalCall)]
356 public extern void SetValue (object value, params int[] indices);
358 // CAUTION! No bounds checking!
359 [MethodImplAttribute (MethodImplOptions.InternalCall)]
360 internal extern object GetValueImpl (int pos);
362 // CAUTION! No bounds checking!
363 [MethodImplAttribute (MethodImplOptions.InternalCall)]
364 internal extern void SetValueImpl (object value, int pos);
366 [MethodImplAttribute (MethodImplOptions.InternalCall)]
367 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
369 [MethodImplAttribute (MethodImplOptions.InternalCall)]
370 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
372 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
373 public int GetUpperBound (int dimension)
375 return GetLowerBound (dimension) + GetLength (dimension) - 1;
378 public object GetValue (int index)
380 if (Rank != 1)
381 throw new ArgumentException (SR.Arg_RankMultiDimNotSupported);
383 var lb = GetLowerBound (0);
384 if (index < lb || index > GetUpperBound (0))
385 throw new IndexOutOfRangeException ("Index has to be between upper and lower bound of the array.");
387 if (GetType ().GetElementType ().IsPointer)
388 throw new NotSupportedException ("Type is not supported.");
390 return GetValueImpl (index - lb);
393 public object GetValue (int index1, int index2)
395 int[] ind = {index1, index2};
396 return GetValue (ind);
399 public object GetValue (int index1, int index2, int index3)
401 int[] ind = {index1, index2, index3};
402 return GetValue (ind);
405 public void SetValue (object value, int index)
407 if (Rank != 1)
408 throw new ArgumentException (SR.Arg_RankMultiDimNotSupported);
410 var lb = GetLowerBound (0);
411 if (index < lb || index > GetUpperBound (0))
412 throw new IndexOutOfRangeException ("Index has to be >= lower bound and <= upper bound of the array.");
414 if (GetType ().GetElementType ().IsPointer)
415 throw new NotSupportedException ("Type is not supported.");
417 SetValueImpl (value, index - lb);
420 public void SetValue (object value, int index1, int index2)
422 int[] ind = {index1, index2};
423 SetValue (value, ind);
426 public void SetValue (object value, int index1, int index2, int index3)
428 int[] ind = {index1, index2, index3};
429 SetValue (value, ind);
432 internal static Array UnsafeCreateInstance(Type elementType, int[] lengths, int[] lowerBounds)
434 return CreateInstance(elementType, lengths, lowerBounds);
437 internal static Array UnsafeCreateInstance (Type elementType, int length1, int length2)
439 return CreateInstance (elementType, length1, length2);
442 internal static Array UnsafeCreateInstance (Type elementType, params int[] lengths)
444 return CreateInstance(elementType, lengths);
447 public static Array CreateInstance (Type elementType, int length)
449 int[] lengths = {length};
451 return CreateInstance (elementType, lengths);
454 public static Array CreateInstance (Type elementType, int length1, int length2)
456 int[] lengths = {length1, length2};
458 return CreateInstance (elementType, lengths);
461 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
463 int[] lengths = {length1, length2, length3};
465 return CreateInstance (elementType, lengths);
468 public static Array CreateInstance (Type elementType, params int[] lengths)
470 if (elementType == null)
471 throw new ArgumentNullException ("elementType");
472 if (lengths == null)
473 throw new ArgumentNullException ("lengths");
475 if (lengths.Length > 255)
476 throw new TypeLoadException ();
478 int[] bounds = null;
480 elementType = elementType.UnderlyingSystemType as RuntimeType;
481 if (elementType == null)
482 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
483 if (elementType.Equals (typeof (void)))
484 throw new NotSupportedException ("Array type can not be void");
485 if (elementType.ContainsGenericParameters)
486 throw new NotSupportedException ("Array type can not be an open generic type");
488 return CreateInstanceImpl (elementType, lengths, bounds);
491 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
493 if (elementType == null)
494 throw new ArgumentNullException ("elementType");
495 if (lengths == null)
496 throw new ArgumentNullException ("lengths");
497 if (lowerBounds == null)
498 throw new ArgumentNullException ("lowerBounds");
500 elementType = elementType.UnderlyingSystemType as RuntimeType;
501 if (elementType == null)
502 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
503 if (elementType.Equals (typeof (void)))
504 throw new NotSupportedException ("Array type can not be void");
505 if (elementType.ContainsGenericParameters)
506 throw new NotSupportedException ("Array type can not be an open generic type");
508 if (lengths.Length < 1)
509 throw new ArgumentException ("Arrays must contain >= 1 elements.");
511 if (lengths.Length != lowerBounds.Length)
512 throw new ArgumentException ("Arrays must be of same size.");
514 for (int j = 0; j < lowerBounds.Length; j ++) {
515 if (lengths [j] < 0)
516 throw new ArgumentOutOfRangeException ("lengths", "Each value has to be >= 0.");
517 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
518 throw new ArgumentOutOfRangeException ("lengths", "Length + bound must not exceed Int32.MaxValue.");
521 if (lengths.Length > 255)
522 throw new TypeLoadException ();
524 return CreateInstanceImpl (elementType, lengths, lowerBounds);
527 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
528 public static void Clear (Array array, int index, int length)
530 if (array == null)
531 throw new ArgumentNullException ("array");
532 if (length < 0)
533 throw new IndexOutOfRangeException ("length < 0");
535 int low = array.GetLowerBound (0);
536 if (index < low)
537 throw new IndexOutOfRangeException ("index < lower bound");
538 index = index - low;
540 // re-ordered to avoid possible integer overflow
541 if (index > array.Length - length)
542 throw new IndexOutOfRangeException ("index + length > size");
544 ClearInternal (array, index, length);
547 [MethodImplAttribute (MethodImplOptions.InternalCall)]
548 static extern void ClearInternal (Array a, int index, int count);
550 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
551 public static void Copy (Array sourceArray, Array destinationArray, int length)
553 // need these checks here because we are going to use
554 // GetLowerBound() on source and dest.
555 if (sourceArray == null)
556 throw new ArgumentNullException ("sourceArray");
558 if (destinationArray == null)
559 throw new ArgumentNullException ("destinationArray");
561 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
562 destinationArray.GetLowerBound (0), length);
565 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
566 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
568 if (sourceArray == null)
569 throw new ArgumentNullException ("sourceArray");
571 if (destinationArray == null)
572 throw new ArgumentNullException ("destinationArray");
574 if (length < 0)
575 throw new ArgumentOutOfRangeException ("length", "Value has to be >= 0.");
577 if (sourceArray.Rank != destinationArray.Rank)
578 throw new RankException(SR.Rank_MultiDimNotSupported);
580 if (sourceIndex < 0)
581 throw new ArgumentOutOfRangeException ("sourceIndex", "Value has to be >= 0.");
583 if (destinationIndex < 0)
584 throw new ArgumentOutOfRangeException ("destinationIndex", "Value has to be >= 0.");
586 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
587 return;
589 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
590 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
592 if (dest_pos < 0)
593 throw new ArgumentOutOfRangeException ("destinationIndex", "Index was less than the array's lower bound in the first dimension.");
595 // re-ordered to avoid possible integer overflow
596 if (source_pos > sourceArray.Length - length)
597 throw new ArgumentException ("length");
599 if (dest_pos > destinationArray.Length - length) {
600 throw new ArgumentException ("Destination array was not long enough. Check destIndex and length, and the array's lower bounds", nameof (destinationArray));
603 Type src_type = sourceArray.GetType ().GetElementType ();
604 Type dst_type = destinationArray.GetType ().GetElementType ();
605 var dst_type_vt = dst_type.IsValueType;
607 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
608 for (int i = 0; i < length; i++) {
609 Object srcval = sourceArray.GetValueImpl (source_pos + i);
611 if (srcval == null && dst_type_vt)
612 throw new InvalidCastException ();
614 try {
615 destinationArray.SetValueImpl (srcval, dest_pos + i);
616 } catch (ArgumentException) {
617 throw CreateArrayTypeMismatchException ();
618 } catch (InvalidCastException) {
619 if (CanAssignArrayElement (src_type, dst_type))
620 throw;
621 throw CreateArrayTypeMismatchException ();
625 else {
626 for (int i = length - 1; i >= 0; i--) {
627 Object srcval = sourceArray.GetValueImpl (source_pos + i);
629 try {
630 destinationArray.SetValueImpl (srcval, dest_pos + i);
631 } catch (ArgumentException) {
632 throw CreateArrayTypeMismatchException ();
633 } catch {
634 if (CanAssignArrayElement (src_type, dst_type))
635 throw;
637 throw CreateArrayTypeMismatchException ();
643 static ArrayTypeMismatchException CreateArrayTypeMismatchException ()
645 return new ArrayTypeMismatchException ();
648 static bool CanAssignArrayElement (Type source, Type target)
650 if (source.IsValueType)
651 return source.IsAssignableFrom (target);
653 if (source.IsInterface)
654 return !target.IsValueType;
656 if (target.IsInterface)
657 return !source.IsValueType;
659 return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
662 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
664 // The constrained copy should guarantee that if there is an exception thrown
665 // during the copy, the destination array remains unchanged.
666 // This is related to System.Runtime.Reliability.CER
667 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
669 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
672 public static T[] Empty<T>()
674 return EmptyArray<T>.Value;
677 public void Initialize()
679 return;
682 static int IndexOfImpl<T>(T[] array, T value, int startIndex, int count)
684 return EqualityComparer<T>.Default.IndexOf (array, value, startIndex, count);
687 static int LastIndexOfImpl<T>(T[] array, T value, int startIndex, int count)
689 return EqualityComparer<T>.Default.LastIndexOf (array, value, startIndex, count);
692 static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
694 Object[] objKeys = keys as Object[];
695 Object[] objItems = null;
696 if (objKeys != null)
697 objItems = items as Object[];
699 if (objKeys != null && (items == null || objItems != null)) {
700 SorterObjectArray sorter = new SorterObjectArray(objKeys, objItems, comparer);
701 sorter.Sort(index, length);
702 } else {
703 SorterGenericArray sorter = new SorterGenericArray(keys, items, comparer);
704 sorter.Sort(index, length);
708 #region Unsafe array operations
711 // Loads array index with no safety checks (JIT intristics)
713 internal static T UnsafeLoad<T> (T[] array, int index) {
714 return array [index];
718 // Stores values at specified array index with no safety checks (JIT intristics)
720 internal static void UnsafeStore<T> (T[] array, int index, T value) {
721 array [index] = value;
725 // Moved value from instance into target of different type with no checks (JIT intristics)
727 // Restrictions:
729 // S and R must either:
730 // both be blitable valuetypes
731 // both be reference types (IOW, an unsafe cast)
732 // S and R cannot be float or double
733 // S and R must either:
734 // both be a struct
735 // both be a scalar
736 // S and R must either:
737 // be of same size
738 // both be a scalar of size <= 4
740 internal static R UnsafeMov<S,R> (S instance) {
741 return (R)(object) instance;
744 #endregion
746 internal sealed class FunctorComparer<T> : IComparer<T> {
747 Comparison<T> comparison;
749 public FunctorComparer(Comparison<T> comparison) {
750 this.comparison = comparison;
753 public int Compare(T x, T y) {
754 return comparison(x, y);
758 partial class ArrayEnumerator
760 public Object Current {
761 get {
762 if (_index < 0) throw new InvalidOperationException (SR.InvalidOperation_EnumNotStarted);
763 if (_index >= _endIndex) throw new InvalidOperationException (SR.InvalidOperation_EnumEnded);
764 if (_index == 0 && _array.GetType ().GetElementType ().IsPointer) throw new NotSupportedException ("Type is not supported.");
765 return _array.GetValueImpl(_index);