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;
40 using System.Collections.Generic;
41 using System.Collections.ObjectModel;
42 using System.Runtime.ConstrainedExecution;
44 using System.Reflection.Emit;
49 public abstract partial class Array
57 * These methods are used to implement the implicit generic interfaces
58 * implemented by arrays in NET 2.0.
59 * Only make those methods generic which really need it, to avoid
60 * creating useless instantiations.
62 internal int InternalArray__ICollection_get_Count ()
67 internal bool InternalArray__ICollection_get_IsReadOnly ()
72 internal IEnumerator<T> InternalArray__IEnumerable_GetEnumerator<T> ()
74 return new InternalEnumerator<T> (this);
77 internal void InternalArray__ICollection_Clear ()
79 throw new NotSupportedException ("Collection is read-only");
82 internal void InternalArray__ICollection_Add<T> (T item)
84 throw new NotSupportedException ("Collection is of a fixed size");
87 internal bool InternalArray__ICollection_Remove<T> (T item)
89 throw new NotSupportedException ("Collection is of a fixed size");
92 internal bool InternalArray__ICollection_Contains<T> (T item)
95 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
97 int length = this.Length;
98 for (int i = 0; i < length; i++) {
100 GetGenericValueImpl (i, out value);
109 if (item.Equals (value)) {
117 int IList.IndexOf (object value)
120 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
122 int length = this.Length;
123 for (int i = 0; i < length; i++) {
124 if (Object.Equals (this.GetValueImpl (i), value))
125 // array index may not be zero-based.
127 return i + this.GetLowerBound (0);
131 // lower bound may be MinValue
132 return this.GetLowerBound (0) - 1;
136 internal void InternalArray__ICollection_CopyTo<T> (T[] array, int index)
139 throw new ArgumentNullException ("array");
141 // The order of these exception checks may look strange,
142 // but that's how the microsoft runtime does it.
144 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
145 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
146 throw new ArgumentException ("Destination array was not long " +
147 "enough. Check destIndex and length, and the array's " +
150 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
152 throw new ArgumentOutOfRangeException (
153 "index", Locale.GetText ("Value has to be >= 0."));
155 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
158 internal T InternalArray__IReadOnlyList_get_Item<T> (int index)
160 if (unchecked ((uint) index) >= unchecked ((uint) Length))
161 throw new ArgumentOutOfRangeException ("index");
164 GetGenericValueImpl (index, out value);
168 internal int InternalArray__IReadOnlyCollection_get_Count ()
173 internal void InternalArray__Insert<T> (int index, T item)
175 throw new NotSupportedException ("Collection is of a fixed size");
178 internal void InternalArray__RemoveAt (int index)
180 throw new NotSupportedException ("Collection is of a fixed size");
183 internal int InternalArray__IndexOf<T> (T item)
186 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
188 int length = this.Length;
189 for (int i = 0; i < length; i++) {
191 GetGenericValueImpl (i, out value);
194 return i + this.GetLowerBound (0);
198 if (value.Equals (item))
199 // array index may not be zero-based.
201 return i + this.GetLowerBound (0);
205 // lower bound may be MinValue
206 return this.GetLowerBound (0) - 1;
210 internal T InternalArray__get_Item<T> (int index)
212 if (unchecked ((uint) index) >= unchecked ((uint) Length))
213 throw new ArgumentOutOfRangeException ("index");
216 GetGenericValueImpl (index, out value);
220 internal void InternalArray__set_Item<T> (int index, T item)
222 if (unchecked ((uint) index) >= unchecked ((uint) Length))
223 throw new ArgumentOutOfRangeException ("index");
225 object[] oarray = this as object [];
226 if (oarray != null) {
227 oarray [index] = (object)item;
230 SetGenericValueImpl (index, ref item);
233 // CAUTION! No bounds checking!
234 [MethodImplAttribute (MethodImplOptions.InternalCall)]
235 internal extern void GetGenericValueImpl<T> (int pos, out T value);
237 // CAUTION! No bounds checking!
238 [MethodImplAttribute (MethodImplOptions.InternalCall)]
239 internal extern void SetGenericValueImpl<T> (int pos, ref T value);
241 internal struct InternalEnumerator<T> : IEnumerator<T>
243 const int NOT_STARTED = -2;
245 // this MUST be -1, because we depend on it in move next.
246 // we just decr the size, so, 0 - 1 == FINISHED
247 const int FINISHED = -1;
252 internal InternalEnumerator (Array array)
258 public void Dispose ()
263 public bool MoveNext ()
265 if (idx == NOT_STARTED)
268 return idx != FINISHED && -- idx != FINISHED;
273 if (idx == NOT_STARTED)
274 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
276 throw new InvalidOperationException ("Enumeration already finished");
278 return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
282 void IEnumerator.Reset ()
287 object IEnumerator.Current {
296 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
298 int length = this.GetLength (0);
300 for (int i = 1; i < this.Rank; i++) {
301 length *= this.GetLength (i);
308 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
310 return this.GetRank ();
314 // InternalCall Methods
315 [MethodImplAttribute (MethodImplOptions.InternalCall)]
316 extern int GetRank ();
318 [MethodImplAttribute (MethodImplOptions.InternalCall)]
319 public extern int GetLength (int dimension);
321 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
322 [MethodImplAttribute (MethodImplOptions.InternalCall)]
323 public extern int GetLowerBound (int dimension);
325 [MethodImplAttribute (MethodImplOptions.InternalCall)]
326 public extern object GetValue (params int[] indices);
328 [MethodImplAttribute (MethodImplOptions.InternalCall)]
329 public extern void SetValue (object value, params int[] indices);
331 // CAUTION! No bounds checking!
332 [MethodImplAttribute (MethodImplOptions.InternalCall)]
333 internal extern object GetValueImpl (int pos);
335 // CAUTION! No bounds checking!
336 [MethodImplAttribute (MethodImplOptions.InternalCall)]
337 internal extern void SetValueImpl (object value, int pos);
339 [MethodImplAttribute (MethodImplOptions.InternalCall)]
340 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
342 [MethodImplAttribute (MethodImplOptions.InternalCall)]
343 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
345 public bool IsReadOnly {
351 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
352 public int GetUpperBound (int dimension)
354 return GetLowerBound (dimension) + GetLength (dimension) - 1;
357 public object GetValue (int index)
360 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
361 if (index < GetLowerBound (0) || index > GetUpperBound (0))
362 throw new IndexOutOfRangeException (Locale.GetText (
363 "Index has to be between upper and lower bound of the array."));
365 return GetValueImpl (index - GetLowerBound (0));
368 public object GetValue (int index1, int index2)
370 int[] ind = {index1, index2};
371 return GetValue (ind);
374 public object GetValue (int index1, int index2, int index3)
376 int[] ind = {index1, index2, index3};
377 return GetValue (ind);
381 public void SetValue (object value, long index)
383 if (index < 0 || index > Int32.MaxValue)
384 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
385 "Value must be >= 0 and <= Int32.MaxValue."));
387 SetValue (value, (int) index);
391 public void SetValue (object value, long index1, long index2)
393 if (index1 < 0 || index1 > Int32.MaxValue)
394 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
395 "Value must be >= 0 and <= Int32.MaxValue."));
397 if (index2 < 0 || index2 > Int32.MaxValue)
398 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
399 "Value must be >= 0 and <= Int32.MaxValue."));
401 int[] ind = {(int) index1, (int) index2};
402 SetValue (value, ind);
406 public void SetValue (object value, long index1, long index2, long index3)
408 if (index1 < 0 || index1 > Int32.MaxValue)
409 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
410 "Value must be >= 0 and <= Int32.MaxValue."));
412 if (index2 < 0 || index2 > Int32.MaxValue)
413 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
414 "Value must be >= 0 and <= Int32.MaxValue."));
416 if (index3 < 0 || index3 > Int32.MaxValue)
417 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
418 "Value must be >= 0 and <= Int32.MaxValue."));
420 int[] ind = {(int) index1, (int) index2, (int) index3};
421 SetValue (value, ind);
424 public void SetValue (object value, int index)
427 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
428 if (index < GetLowerBound (0) || index > GetUpperBound (0))
429 throw new IndexOutOfRangeException (Locale.GetText (
430 "Index has to be >= lower bound and <= upper bound of the array."));
432 SetValueImpl (value, index - GetLowerBound (0));
435 public void SetValue (object value, int index1, int index2)
437 int[] ind = {index1, index2};
438 SetValue (value, ind);
441 public void SetValue (object value, int index1, int index2, int index3)
443 int[] ind = {index1, index2, index3};
444 SetValue (value, ind);
447 internal static Array UnsafeCreateInstance(Type elementType, int[] lengths, int[] lowerBounds)
449 return CreateInstance(elementType, lengths, lowerBounds);
452 internal static Array UnsafeCreateInstance (Type elementType, int length1, int length2)
454 return CreateInstance (elementType, length1, length2);
457 internal static Array UnsafeCreateInstance (Type elementType, params int[] lengths)
459 return CreateInstance(elementType, lengths);
462 public static Array CreateInstance (Type elementType, int length)
464 int[] lengths = {length};
466 return CreateInstance (elementType, lengths);
469 public static Array CreateInstance (Type elementType, int length1, int length2)
471 int[] lengths = {length1, length2};
473 return CreateInstance (elementType, lengths);
476 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
478 int[] lengths = {length1, length2, length3};
480 return CreateInstance (elementType, lengths);
483 public static Array CreateInstance (Type elementType, params int[] lengths)
485 if (elementType == null)
486 throw new ArgumentNullException ("elementType");
488 throw new ArgumentNullException ("lengths");
490 if (lengths.Length > 255)
491 throw new TypeLoadException ();
495 elementType = elementType.UnderlyingSystemType as RuntimeType;
496 if (elementType == null)
497 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
498 if (elementType.Equals (typeof (void)))
499 throw new NotSupportedException ("Array type can not be void");
500 if (elementType.ContainsGenericParameters)
501 throw new NotSupportedException ("Array type can not be an open generic type");
502 #if !FULL_AOT_RUNTIME
503 if ((elementType is TypeBuilder) && !(elementType as TypeBuilder).IsCreated ())
504 throw new NotSupportedException ("Can't create an array of the unfinished type '" + elementType + "'.");
507 return CreateInstanceImpl (elementType, lengths, bounds);
510 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
512 if (elementType == null)
513 throw new ArgumentNullException ("elementType");
515 throw new ArgumentNullException ("lengths");
516 if (lowerBounds == null)
517 throw new ArgumentNullException ("lowerBounds");
519 elementType = elementType.UnderlyingSystemType as RuntimeType;
520 if (elementType == null)
521 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
522 if (elementType.Equals (typeof (void)))
523 throw new NotSupportedException ("Array type can not be void");
524 if (elementType.ContainsGenericParameters)
525 throw new NotSupportedException ("Array type can not be an open generic type");
527 if (lengths.Length < 1)
528 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
530 if (lengths.Length != lowerBounds.Length)
531 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
533 for (int j = 0; j < lowerBounds.Length; j ++) {
535 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
536 "Each value has to be >= 0."));
537 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
538 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
539 "Length + bound must not exceed Int32.MaxValue."));
542 if (lengths.Length > 255)
543 throw new TypeLoadException ();
545 return CreateInstanceImpl (elementType, lengths, lowerBounds);
548 static int [] GetIntArray (long [] values)
550 int len = values.Length;
551 int [] ints = new int [len];
552 for (int i = 0; i < len; i++) {
553 long current = values [i];
554 if (current < 0 || current > (long) Int32.MaxValue)
555 throw new ArgumentOutOfRangeException ("values", Locale.GetText (
556 "Each value has to be >= 0 and <= Int32.MaxValue."));
558 ints [i] = (int) current;
563 public static Array CreateInstance (Type elementType, params long [] lengths)
566 throw new ArgumentNullException ("lengths");
567 return CreateInstance (elementType, GetIntArray (lengths));
571 public void SetValue (object value, params long [] indices)
574 throw new ArgumentNullException ("indices");
575 SetValue (value, GetIntArray (indices));
578 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
579 public static void Clear (Array array, int index, int length)
582 throw new ArgumentNullException ("array");
584 throw new IndexOutOfRangeException ("length < 0");
586 int low = array.GetLowerBound (0);
588 throw new IndexOutOfRangeException ("index < lower bound");
591 // re-ordered to avoid possible integer overflow
592 if (index > array.Length - length)
593 throw new IndexOutOfRangeException ("index + length > size");
595 ClearInternal (array, index, length);
598 [MethodImplAttribute (MethodImplOptions.InternalCall)]
599 static extern void ClearInternal (Array a, int index, int count);
601 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
602 public static void Copy (Array sourceArray, Array destinationArray, int length)
604 // need these checks here because we are going to use
605 // GetLowerBound() on source and dest.
606 if (sourceArray == null)
607 throw new ArgumentNullException ("sourceArray");
609 if (destinationArray == null)
610 throw new ArgumentNullException ("destinationArray");
612 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
613 destinationArray.GetLowerBound (0), length);
616 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
617 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
619 if (sourceArray == null)
620 throw new ArgumentNullException ("sourceArray");
622 if (destinationArray == null)
623 throw new ArgumentNullException ("destinationArray");
626 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
627 "Value has to be >= 0."));;
629 if (sourceArray.Rank != destinationArray.Rank)
630 throw new RankException(SR.Rank_MultiDimNotSupported);
633 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
634 "Value has to be >= 0."));;
636 if (destinationIndex < 0)
637 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
638 "Value has to be >= 0."));;
640 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
643 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
644 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
647 throw new ArgumentOutOfRangeException ("destinationIndex", "Index was less than the array's lower bound in the first dimension.");
649 // re-ordered to avoid possible integer overflow
650 if (source_pos > sourceArray.Length - length)
651 throw new ArgumentException ("length");
653 if (dest_pos > destinationArray.Length - length) {
654 string msg = "Destination array was not long enough. Check " +
655 "destIndex and length, and the array's lower bounds";
656 throw new ArgumentException (msg, string.Empty);
659 Type src_type = sourceArray.GetType ().GetElementType ();
660 Type dst_type = destinationArray.GetType ().GetElementType ();
662 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
663 for (int i = 0; i < length; i++) {
664 Object srcval = sourceArray.GetValueImpl (source_pos + i);
667 destinationArray.SetValueImpl (srcval, dest_pos + i);
668 } catch (ArgumentException) {
669 throw CreateArrayTypeMismatchException ();
671 if (CanAssignArrayElement (src_type, dst_type))
674 throw CreateArrayTypeMismatchException ();
679 for (int i = length - 1; i >= 0; i--) {
680 Object srcval = sourceArray.GetValueImpl (source_pos + i);
683 destinationArray.SetValueImpl (srcval, dest_pos + i);
684 } catch (ArgumentException) {
685 throw CreateArrayTypeMismatchException ();
687 if (CanAssignArrayElement (src_type, dst_type))
690 throw CreateArrayTypeMismatchException ();
696 static Exception CreateArrayTypeMismatchException ()
698 return new ArrayTypeMismatchException ();
701 static bool CanAssignArrayElement (Type source, Type target)
703 if (source.IsValueType)
704 return source.IsAssignableFrom (target);
706 if (source.IsInterface)
707 return !target.IsValueType;
709 if (target.IsInterface)
710 return !source.IsValueType;
712 return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
715 public static T [] FindAll<T> (T [] array, Predicate <T> match)
718 throw new ArgumentNullException ("array");
721 throw new ArgumentNullException ("match");
724 T [] d = new T [array.Length];
725 foreach (T t in array)
729 Resize <T> (ref d, pos);
733 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
735 // The constrained copy should guarantee that if there is an exception thrown
736 // during the copy, the destination array remains unchanged.
737 // This is related to System.Runtime.Reliability.CER
738 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
740 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
743 object GetValueWithFlattenedIndex_NoErrorCheck (int flattenedIndex)
745 return GetValueImpl (flattenedIndex);
748 #region Unsafe array operations
751 // Loads array index with no safety checks (JIT intristics)
753 internal static T UnsafeLoad<T> (T[] array, int index) {
754 return array [index];
758 // Stores values at specified array index with no safety checks (JIT intristics)
760 internal static void UnsafeStore<T> (T[] array, int index, T value) {
761 array [index] = value;
765 // Moved value from instance into target of different type with no checks (JIT intristics)
769 // S and R must either:
770 // both be blitable valuetypes
771 // both be reference types (IOW, an unsafe cast)
772 // S and R cannot be float or double
773 // S and R must either:
776 // S and R must either:
778 // both be a scalar of size <= 4
780 internal static R UnsafeMov<S,R> (S instance) {
781 return (R)(object) instance;
786 internal sealed class FunctorComparer<T> : IComparer<T> {
787 Comparison<T> comparison;
789 public FunctorComparer(Comparison<T> comparison) {
790 this.comparison = comparison;
793 public int Compare(T x, T y) {
794 return comparison(x, y);