Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / corlib / System / Array.cs
index ef253f49dc4d5ca2a1ef16d44f9afbde4a7a6199..bc22c019faa2219f4c357766d8f2ebecc9a10f28 100644 (file)
@@ -40,7 +40,9 @@ using System.Runtime.InteropServices;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Runtime.ConstrainedExecution;
+#if !FULL_AOT_RUNTIME
 using System.Reflection.Emit;
+#endif
 
 namespace System
 {
@@ -48,7 +50,7 @@ namespace System
        [ComVisible (true)]
        // FIXME: We are doing way to many double/triple exception checks for the overloaded functions"
        public abstract class Array : ICloneable, ICollection, IList, IEnumerable
-#if NET_4_0 || MOONLIGHT || MOBILE
+#if NET_4_0
                , IStructuralComparable, IStructuralEquatable
 #endif
        {
@@ -103,14 +105,16 @@ namespace System
                                T value;
                                GetGenericValueImpl (i, out value);
                                if (item == null){
-                                       if (value == null)
+                                       if (value == null) {
                                                return true;
+                                       }
 
                                        continue;
                                }
-                               
-                               if (item.Equals (value))
+
+                               if (item.Equals (value)) {
                                        return true;
+                               }
                        }
 
                        return false;
@@ -138,6 +142,23 @@ namespace System
                        Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
                }
 
+#if NET_4_5
+               internal T InternalArray__IReadOnlyList_get_Item<T> (int index)
+               {
+                       if (unchecked ((uint) index) >= unchecked ((uint) Length))
+                               throw new ArgumentOutOfRangeException ("index");
+
+                       T value;
+                       GetGenericValueImpl (index, out value);
+                       return value;
+               }
+
+               internal int InternalArray__IReadOnlyCollection_get_Count ()
+               {
+                       return Length;
+               }
+#endif
+
                internal void InternalArray__Insert<T> (int index, T item)
                {
                        throw new NotSupportedException ("Collection is of a fixed size");
@@ -434,7 +455,7 @@ namespace System
                        return new SimpleEnumerator (this);
                }
 
-#if NET_4_0 || MOONLIGHT || MOBILE
+#if NET_4_0
                int IStructuralComparable.CompareTo (object other, IComparer comparer)
                {
                        if (other == null)
@@ -490,7 +511,7 @@ namespace System
 
                        int hash = 0;
                        for (int i = 0; i < Length; i++)
-                               hash = ((hash << 7) + hash) ^ GetValue (i).GetHashCode ();
+                               hash = ((hash << 7) + hash) ^ comparer.GetHashCode (GetValueImpl (i));
                        return hash;
                }
 #endif
@@ -673,8 +694,10 @@ namespace System
                                throw new NotSupportedException ("Array type can not be void");
                        if (elementType.ContainsGenericParameters)
                                throw new NotSupportedException ("Array type can not be an open generic type");
+#if !FULL_AOT_RUNTIME
                        if ((elementType is TypeBuilder) && !(elementType as TypeBuilder).IsCreated ())
                                throw new NotSupportedException ("Can't create an array of the unfinished type '" + elementType + "'.");
+#endif
                        
                        return CreateInstanceImpl (elementType, lengths, bounds);
                }
@@ -758,22 +781,7 @@ namespace System
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
                public static int BinarySearch (Array array, object value)
                {
-                       if (array == null)
-                               throw new ArgumentNullException ("array");
-
-                       if (value == null)
-                               return -1;
-
-                       if (array.Rank > 1)
-                               throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
-
-                       if (array.Length == 0)
-                               return -1;
-
-                       if (!(value is IComparable))
-                               throw new ArgumentException (Locale.GetText ("value does not support IComparable."));
-
-                       return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, null);
+                       return BinarySearch (array, value, null);
                }
 
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
@@ -788,41 +796,13 @@ namespace System
                        if (array.Length == 0)
                                return -1;
 
-                       if ((comparer == null) && (value != null) && !(value is IComparable))
-                               throw new ArgumentException (Locale.GetText (
-                                       "comparer is null and value does not support IComparable."));
-
                        return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
                }
 
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
                public static int BinarySearch (Array array, int index, int length, object value)
                {
-                       if (array == null)
-                               throw new ArgumentNullException ("array");
-
-                       if (array.Rank > 1)
-                               throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
-
-                       if (index < array.GetLowerBound (0))
-                               throw new ArgumentOutOfRangeException ("index", Locale.GetText (
-                                       "index is less than the lower bound of array."));
-                       if (length < 0)
-                               throw new ArgumentOutOfRangeException ("length", Locale.GetText (
-                                       "Value has to be >= 0."));
-                       // re-ordered to avoid possible integer overflow
-                       if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
-                               throw new ArgumentException (Locale.GetText (
-                                       "index and length do not specify a valid range in array."));
-
-                       if (array.Length == 0)
-                               return -1;
-
-                       if ((value != null) && (!(value is IComparable)))
-                               throw new ArgumentException (Locale.GetText (
-                                       "value does not support IComparable"));
-
-                       return DoBinarySearch (array, index, length, value, null);
+                       return BinarySearch (array, index, length, value, null);
                }
 
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
@@ -848,10 +828,6 @@ namespace System
                        if (array.Length == 0)
                                return -1;
 
-                       if ((comparer == null) && (value != null) && !(value is IComparable))
-                               throw new ArgumentException (Locale.GetText (
-                                       "comparer is null and value does not support IComparable."));
-
                        return DoBinarySearch (array, index, length, value, comparer);
                }
 
@@ -980,12 +956,13 @@ namespace System
 
                                        try {
                                                destinationArray.SetValueImpl (srcval, dest_pos + i);
+                                       } catch (ArgumentException) {
+                                               throw CreateArrayTypeMismatchException ();
                                        } catch {
-                                               if (src_type.Equals (typeof (Object)))
-                                                       throw new InvalidCastException ();
-                                               else
-                                                       throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
-                                                               "(Types: source={0};  target={1})"), src_type.FullName, dst_type.FullName));
+                                               if (CanAssignArrayElement (src_type, dst_type))
+                                                       throw;
+
+                                               throw CreateArrayTypeMismatchException ();
                                        }
                                }
                        }
@@ -995,17 +972,37 @@ namespace System
 
                                        try {
                                                destinationArray.SetValueImpl (srcval, dest_pos + i);
+                                       } catch (ArgumentException) {
+                                               throw CreateArrayTypeMismatchException ();
                                        } catch {
-                                               if (src_type.Equals (typeof (Object)))
-                                                       throw new InvalidCastException ();
-                                               else
-                                                       throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
-                                                               "(Types: source={0};  target={1})"), src_type.FullName, dst_type.FullName));
+                                               if (CanAssignArrayElement (src_type, dst_type))
+                                                       throw;
+
+                                               throw CreateArrayTypeMismatchException ();
                                        }
                                }
                        }
                }
 
+               static Exception CreateArrayTypeMismatchException ()
+               {
+                       return new ArrayTypeMismatchException ();
+               }
+
+               static bool CanAssignArrayElement (Type source, Type target)
+               {
+                       if (source.IsValueType)
+                               return source.IsAssignableFrom (target);
+
+                       if (source.IsInterface)
+                               return !target.IsValueType;
+
+                       if (target.IsInterface)
+                               return !source.IsValueType;
+
+                       return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
+               }
+
                [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
                                         long destinationIndex, long length)
@@ -1134,28 +1131,13 @@ namespace System
                        return lb - 1;
                }
 
-               /* delegate used to swap array elements */
-               delegate void Swapper (int i, int j);
-
-               static Swapper get_swapper (Array array)
-               {
-                       if (array is int[])
-                               return new Swapper (array.int_swapper);
-                       if (array is double[])
-                               return new Swapper (array.double_swapper);
-                       if (array is object[]) {
-                               return new Swapper (array.obj_swapper);
-                       }
-                       return new Swapper (array.slow_swapper);
-               }
-
                [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Reverse (Array array)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
 
-                       Reverse (array, array.GetLowerBound (0), array.GetLength (0));
+                       Reverse (array, array.GetLowerBound (0), array.Length);
                }
 
                [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
@@ -1175,45 +1157,119 @@ namespace System
                                throw new ArgumentException ();
 
                        int end = index + length - 1;
-                       object[] oarray = array as object[];
-                       if (oarray != null) {
+                       var et = array.GetType ().GetElementType ();
+                       switch (Type.GetTypeCode (et)) {
+                       case TypeCode.Boolean:
                                while (index < end) {
-                                       object tmp = oarray [index];
-                                       oarray [index] = oarray [end];
-                                       oarray [end] = tmp;
+                                       bool a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
                                        ++index;
                                        --end;
                                }
                                return;
-                       }
-                       int[] iarray = array as int[];
-                       if (iarray != null) {
+
+                       case TypeCode.Byte:
+                       case TypeCode.SByte:
                                while (index < end) {
-                                       int tmp = iarray [index];
-                                       iarray [index] = iarray [end];
-                                       iarray [end] = tmp;
+                                       byte a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
                                        ++index;
                                        --end;
                                }
                                return;
-                       }
-                       double[] darray = array as double[];
-                       if (darray != null) {
+
+                       case TypeCode.Int16:
+                       case TypeCode.UInt16:
+                       case TypeCode.Char:
                                while (index < end) {
-                                       double tmp = darray [index];
-                                       darray [index] = darray [end];
-                                       darray [end] = tmp;
+                                       short a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
                                        ++index;
                                        --end;
                                }
                                return;
-                       }
-                       // fallback
-                       Swapper swapper = get_swapper (array);
-                       while (index < end) {
-                               swapper (index, end);
-                               ++index;
-                               --end;
+
+                       case TypeCode.Int32:
+                       case TypeCode.UInt32:
+                       case TypeCode.Single:
+                               while (index < end) {
+                                       int a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
+                                       ++index;
+                                       --end;
+                               }
+                               return;
+
+                       case TypeCode.Int64:
+                       case TypeCode.UInt64:
+                       case TypeCode.Double:
+                               while (index < end) {
+                                       long a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
+                                       ++index;
+                                       --end;
+                               }
+                               return;
+
+                       case TypeCode.Decimal:
+                               while (index < end) {
+                                       decimal a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
+                                       ++index;
+                                       --end;
+                               }
+                               return;
+
+                       case TypeCode.String:
+                               while (index < end) {
+                                       object a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
+                                       ++index;
+                                       --end;
+                               }
+                               return;
+                       default:
+                               if (array is object[])
+                                       goto case TypeCode.String;
+
+                               // Very slow fallback
+                               while (index < end) {
+                                       object val = array.GetValueImpl (index);
+                                       array.SetValueImpl (array.GetValueImpl (end), index);
+                                       array.SetValueImpl (val, end);
+                                       ++index;
+                                       --end;
+                               }
+
+                               return;
                        }
                }
 
@@ -1388,34 +1444,6 @@ namespace System
                                throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
                        }
                }
-
-               /* note, these are instance methods */
-               void int_swapper (int i, int j) {
-                       int[] array = this as int[];
-                       int val = array [i];
-                       array [i] = array [j];
-                       array [j] = val;
-               }
-
-               void obj_swapper (int i, int j) {
-                       object[] array = this as object[];
-                       object val = array [i];
-                       array [i] = array [j];
-                       array [j] = val;
-               }
-
-               void slow_swapper (int i, int j) {
-                       object val = GetValueImpl (i);
-                       SetValueImpl (GetValue (j), i);
-                       SetValueImpl (val, j);
-               }
-
-               void double_swapper (int i, int j) {
-                       double[] array = this as double[];
-                       double val = array [i];
-                       array [i] = array [j];
-                       array [j] = val;
-               }
                
                struct QSortStack {
                        public int high;
@@ -1679,7 +1707,7 @@ namespace System
                        if (index + length > array.Length)
                                throw new ArgumentException ();
                                
-                       SortImpl<T, T> (array, null, index, length, comparer);
+                       SortImpl<T> (array, index, length, comparer);
                }
 
                [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
@@ -1717,6 +1745,8 @@ namespace System
                        // Check for value types which can be sorted without Compare () method
                        //
                        if (comparer == null) {
+                               /* Avoid this when using full-aot to prevent the generation of many unused qsort<K,T> instantiations */
+#if FULL_AOT_RUNTIME
 #if !BOOTSTRAP_BASIC
                                switch (Type.GetTypeCode (typeof (TKey))) {
                                case TypeCode.Int32:
@@ -1759,6 +1789,7 @@ namespace System
                                        qsort (keys as UInt64[], items, low, high);
                                        return;
                                }
+#endif
 #endif
                                // Using Comparer<TKey> adds a small overload, but with value types it
                                // helps us to not box them.
@@ -2526,11 +2557,7 @@ namespace System
                                        // switch to insertion sort
                                        for (i = low + 1; i <= high; i++) {
                                                for (k = i; k > low; k--) {
-                                                       // if keys[k] >= keys[k-1], break
-                                                       if (array[k-1] == null)
-                                                               break;
-                                                       
-                                                       if (array[k] != null && compare (array[k], array[k-1]) >= 0)
+                                                       if (compare (array[k], array[k-1]) >= 0)
                                                                break;
                                                        
                                                        swap<T> (array, k - 1, k);
@@ -2628,6 +2655,7 @@ namespace System
                        }
                }
 
+               [MethodImpl ((MethodImplOptions)256)]
                private static void swap<K, V> (K [] keys, V [] items, int i, int j)
                {
                        K tmp;
@@ -2644,6 +2672,7 @@ namespace System
                        }
                }
 
+               [MethodImpl ((MethodImplOptions)256)]
                private static void swap<T> (T [] array, int i, int j)
                {
                        T tmp = array [i];
@@ -2738,20 +2767,27 @@ namespace System
                public static void Resize<T> (ref T [] array, int newSize)
                {
                        if (newSize < 0)
-                               throw new ArgumentOutOfRangeException ();
+                               throw new ArgumentOutOfRangeException ("newSize");
                        
                        if (array == null) {
                                array = new T [newSize];
                                return;
                        }
 
-                       int length = array.Length;
+                       var arr = array;
+                       int length = arr.Length;
                        if (length == newSize)
                                return;
                        
                        T [] a = new T [newSize];
-                       if (length != 0)
-                               FastCopy (array, 0, a, 0, Math.Min (newSize, length));
+                       int tocopy = Math.Min (newSize, length);
+
+                       if (tocopy < 9) {
+                               for (int i = 0; i < tocopy; ++i)
+                                       UnsafeStore (a, i, UnsafeLoad (arr, i));
+                       } else {
+                               FastCopy (arr, 0, a, 0, tocopy);
+                       }
                        array = a;
                }
                
@@ -2798,32 +2834,54 @@ namespace System
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
-                       return FindLastIndex<T> (array, 0, array.Length, match);
+                       return GetLastIndex (array, 0, array.Length, match);
                }
                
                public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
                {
                        if (array == null)
                                throw new ArgumentNullException ();
+
+                       if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
-                       return FindLastIndex<T> (array, startIndex, array.Length - startIndex, match);
+                       return GetLastIndex (array, 0, startIndex + 1, match);
                }
                
                public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
+
                        if (match == null)
                                throw new ArgumentNullException ("match");
+
+                       if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
+                               throw new ArgumentOutOfRangeException ("startIndex");
                        
-                       if (startIndex > array.Length || startIndex + count > array.Length)
-                               throw new ArgumentOutOfRangeException ();
-                       
-                       for (int i = startIndex + count - 1; i >= startIndex; i--)
-                               if (match (array [i]))
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count");
+
+                       if (startIndex - count + 1 < 0)
+                               throw new ArgumentOutOfRangeException ("count must refer to a location within the array");
+
+                       return GetLastIndex (array, startIndex - count + 1, count, match);
+               }
+
+               internal static int GetLastIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
+               {
+                       // unlike FindLastIndex, takes regular params for search range
+                       for (int i = startIndex + count; i != startIndex;)
+                               if (match (array [--i]))
                                        return i;
-                               
+
                        return -1;
                }
                
@@ -2831,16 +2889,25 @@ namespace System
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
-                       return FindIndex<T> (array, 0, array.Length, match);
+                       return GetIndex (array, 0, array.Length, match);
                }
                
                public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
-                       
-                       return FindIndex<T> (array, startIndex, array.Length - startIndex, match);
+
+                       if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
+
+                       return GetIndex (array, startIndex, array.Length - startIndex, match);
                }
                
                public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
@@ -2848,13 +2915,22 @@ namespace System
                        if (array == null)
                                throw new ArgumentNullException ("array");
                        
-                       if (match == null)
-                               throw new ArgumentNullException ("match");
-                       
-                       if (startIndex > array.Length || startIndex + count > array.Length)
-                               throw new ArgumentOutOfRangeException ();
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex");
                        
-                       for (int i = startIndex; i < startIndex + count; i ++)
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count");
+
+                       if ((uint) startIndex + (uint) count > (uint) array.Length)
+                               throw new ArgumentOutOfRangeException ("index and count exceed length of list");
+
+                       return GetIndex (array, startIndex, count, match);
+               }
+
+               internal static int GetIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
+               {
+                       int end = startIndex + count;
+                       for (int i = startIndex; i < end; i ++)
                                if (match (array [i]))
                                        return i;
                                
@@ -3077,5 +3153,13 @@ namespace System
                {
                        Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
                }
+
+               internal static T UnsafeLoad<T> (T[] array, int index) {
+                       return array [index];
+               }
+
+               internal static void UnsafeStore<T> (T[] array, int index, T value) {
+                       array [index] = value;
+               }
        }
 }