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:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
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
;
45 public abstract partial class 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 ()
62 internal bool InternalArray__ICollection_get_IsReadOnly ()
67 // adapted to the Mono array layout
68 [StructLayout(LayoutKind
.Sequential
)]
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
> ()
85 return EmptyInternalEnumerator
<T
>.Value
;
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
)
108 throw new RankException ("Only single dimension arrays are supported.");
110 int length
= this.Length
;
111 for (int i
= 0; i
< length
; i
++) {
113 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
114 GetGenericValueImpl (i
, out value);
123 if (item
.Equals (value)) {
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");
142 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
143 GetGenericValueImpl (index
, out value);
147 internal int InternalArray__IReadOnlyCollection_get_Count ()
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
)
165 throw new RankException ("Only single dimension arrays are supported.");
167 int length
= this.Length
;
168 for (int i
= 0; i
< length
; i
++) {
170 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
171 GetGenericValueImpl (i
, out value);
174 return i
+ this.GetLowerBound (0);
178 if (value.Equals (item
))
179 // array index may not be zero-based.
181 return i
+ this.GetLowerBound (0);
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");
196 // Do not change this to call GetGenericValue_icall directly, due to special casing in the runtime.
197 GetGenericValueImpl (index
, out 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
;
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)
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)
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
;
248 internal InternalEnumerator (Array array
)
254 public void Dispose ()
258 public bool MoveNext ()
260 if (idx
== NOT_STARTED
)
263 return idx
!= FINISHED
&& -- idx
!= FINISHED
;
268 if (idx
== NOT_STARTED
)
269 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
271 throw new InvalidOperationException ("Enumeration already finished");
273 return array
.InternalArray__get_Item
<T
> (array
.Length
- 1 - idx
);
277 void IEnumerator
.Reset ()
282 object IEnumerator
.Current
{
291 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.Success
)]
293 int length
= this.GetLength (0);
295 for (int i
= 1; i
< this.Rank
; i
++) {
296 length
*= this.GetLength (i
);
303 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.Success
)]
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 ()
318 public bool MoveNext ()
325 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
329 object IEnumerator
.Current
{
335 void IEnumerator
.Reset ()
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
)
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
)
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");
473 throw new ArgumentNullException ("lengths");
475 if (lengths
.Length
> 255)
476 throw new TypeLoadException ();
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");
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
++) {
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
)
531 throw new ArgumentNullException ("array");
533 throw new IndexOutOfRangeException ("length < 0");
535 int low
= array
.GetLowerBound (0);
537 throw new IndexOutOfRangeException ("index < lower bound");
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");
575 throw new ArgumentOutOfRangeException ("length", "Value has to be >= 0.");
577 if (sourceArray
.Rank
!= destinationArray
.Rank
)
578 throw new RankException(SR
.Rank_MultiDimNotSupported
);
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
))
589 int source_pos
= sourceIndex
- sourceArray
.GetLowerBound (0);
590 int dest_pos
= destinationIndex
- destinationArray
.GetLowerBound (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 ();
615 destinationArray
.SetValueImpl (srcval
, dest_pos
+ i
);
616 } catch (ArgumentException
) {
617 throw CreateArrayTypeMismatchException ();
618 } catch (InvalidCastException
) {
619 if (CanAssignArrayElement (src_type
, dst_type
))
621 throw CreateArrayTypeMismatchException ();
626 for (int i
= length
- 1; i
>= 0; i
--) {
627 Object srcval
= sourceArray
.GetValueImpl (source_pos
+ i
);
630 destinationArray
.SetValueImpl (srcval
, dest_pos
+ i
);
631 } catch (ArgumentException
) {
632 throw CreateArrayTypeMismatchException ();
634 if (CanAssignArrayElement (src_type
, dst_type
))
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()
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;
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
);
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)
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:
736 // S and R must either:
738 // both be a scalar of size <= 4
740 internal static R UnsafeMov
<S
,R
> (S instance
) {
741 return (R
)(object) instance
;
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
{
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
);