2007-10-27 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / class / corlib / System / Array.cs
index 2c69e40eb303c43e13cfdd157b6ba909a4f20392..b0653b0169a5da70c7b59b05bbeca7238b9ac337 100644 (file)
@@ -43,6 +43,9 @@ using System.Runtime.ConstrainedExecution;
 namespace System
 {
        [Serializable]
+#if NET_2_0
+       [ComVisible (true)]
+#endif
        // FIXME: We are doing way to many double/triple exception checks for the overloaded functions"
        // FIXME: Sort overloads parameter checks are VERY inconsistent"
        public abstract class Array : ICloneable, ICollection, IList, IEnumerable
@@ -53,6 +56,8 @@ namespace System
                }
 
 #if NET_2_0
+               // FIXME: they should not be exposed, but there are some
+               // dependent code in the runtime.
                protected int InternalArray__ICollection_get_Count<T> ()
                {
                        return Length;
@@ -87,6 +92,13 @@ namespace System
                        for (int i = 0; i < length; i++) {
                                T value;
                                GetGenericValueImpl (i, out value);
+                               if (item == null){
+                                       if (value == null)
+                                               return true;
+                                       else
+                                               return false;
+                               }
+                               
                                if (item.Equals (value))
                                        return true;
                        }
@@ -104,7 +116,9 @@ namespace System
                        if (this.Rank > 1)
                                throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
                        if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
-                               throw new ArgumentException ();
+                               throw new ArgumentException ("Destination array was not long " +
+                                       "enough. Check destIndex and length, and the array's " +
+                                       "lower bounds.");
                        if (array.Rank > 1)
                                throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
                        if (index < 0)
@@ -133,6 +147,15 @@ namespace System
                        for (int i = 0; i < length; i++) {
                                T value;
                                GetGenericValueImpl (i, out value);
+                               if (item == null){
+                                       if (value == null)
+                                               return i + this.GetLowerBound (0);
+                                       else {
+                                               unchecked {
+                                                       return this.GetLowerBound (0) - 1;
+                                               }
+                                       }
+                               }
                                if (item.Equals (value))
                                        // array index may not be zero-based.
                                        // use lower bound
@@ -160,13 +183,20 @@ namespace System
 
                protected void InternalArray__set_Item<T> (int index, T item)
                {
-                       throw new NotSupportedException ("Collection is read-only");
+                       if (unchecked ((uint) index) >= unchecked ((uint) Length))
+                               throw new ArgumentOutOfRangeException ("index");
+
+                       SetGenericValueImpl (index, ref item);
                }
 
                // CAUTION! No bounds checking!
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                internal extern void GetGenericValueImpl<T> (int pos, out T value);
 
+               // CAUTION! No bounds checking!
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               internal extern void SetGenericValueImpl<T> (int pos, ref T value);
+
                internal struct InternalEnumerator<T> : IEnumerator<T>
                {
                        const int NOT_STARTED = -2;
@@ -332,7 +362,7 @@ namespace System
 
                // InternalCall Methods
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               protected extern int GetRank ();
+               extern int GetRank ();
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                public extern int GetLength (int dimension);
@@ -590,7 +620,7 @@ namespace System
                        return CreateInstance (elementType, lengths);
                }
 
-               public static Array CreateInstance (Type elementType, int[] lengths)
+               public static Array CreateInstance (Type elementType, params int[] lengths)
                {
                        if (elementType == null)
                                throw new ArgumentNullException ("elementType");
@@ -810,7 +840,9 @@ namespace System
                        int iCmp = 0;
                        try {
                                while (iMin <= iMax) {
-                                       int iMid = (iMin + iMax) / 2;
+                                       // Be careful with overflow
+                                       // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
+                                       int iMid = iMin + ((iMax - iMin) / 2);
                                        object elt = array.GetValueImpl (iMid);
 
                                        iCmp = comparer.Compare (elt, value);
@@ -909,9 +941,19 @@ namespace System
                        int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
 
                        // re-ordered to avoid possible integer overflow
-                       if (source_pos > sourceArray.Length - length || dest_pos > destinationArray.Length - length)
+                       if (source_pos > sourceArray.Length - length)
                                throw new ArgumentException ("length");
 
+                       if (dest_pos > destinationArray.Length - length) {
+                               string msg = "Destination array was not long enough. Check " +
+                                       "destIndex and length, and the array's lower bounds";
+#if NET_2_0
+                               throw new ArgumentException (msg, string.Empty);
+#else
+                               throw new ArgumentException (msg);
+#endif
+                       }
+
                        if (sourceArray.Rank != destinationArray.Rank)
                                throw new RankException (Locale.GetText ("Arrays must be of same size."));
 
@@ -1039,7 +1081,6 @@ namespace System
                        return array.GetLowerBound (0) - 1;
                }
 
-               [MonoTODO]
                public void Initialize()
                {
                        //FIXME: We would like to find a compiler that uses
@@ -1117,7 +1158,9 @@ namespace System
                        if (array is double[])
                                return new Swapper (array.double_swapper);
 
-                       return new Swapper (array.obj_swapper);
+                       // gmcs refuses to compile this
+                       //return new Swapper (array.generic_swapper<T>);
+                       return new Swapper (array.slow_swapper);
                }
 #endif
 
@@ -1346,6 +1389,15 @@ namespace System
                        array [j] = val;
                }
 
+#if NET_2_0
+               void generic_swapper<T> (int i, int j) {
+                       T[] array = this as T[];
+                       T val = array [i];
+                       array [i] = array [j];
+                       array [j] = val;
+               }
+#endif
+
                static int new_gap (int gap)
                {
                        gap = (gap * 10) / 13;
@@ -1436,7 +1488,9 @@ namespace System
                        int low = low0;
                        int high = high0;
 
-                       object objPivot = keys.GetValueImpl ((low + high) / 2);
+                       // Be careful with overflows
+                       int mid = low + ((high - low) / 2);
+                       object objPivot = keys.GetValueImpl (mid);
 
                        while (low <= high) {
                                // Move the walls in
@@ -1486,7 +1540,7 @@ namespace System
                }
        
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Sort<T> (T [] array)
                {
                        if (array == null)
@@ -1495,7 +1549,7 @@ namespace System
                        Sort<T, T> (array, null, 0, array.Length, null);
                }
 
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items)
                {
                        if (keys == null)
@@ -1504,7 +1558,7 @@ namespace System
                        Sort<TKey, TValue> (keys, items, 0, keys.Length, null);
                }
 
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Sort<T> (T [] array, IComparer<T> comparer)
                {
                        if (array == null)
@@ -1513,7 +1567,7 @@ namespace System
                        Sort<T, T> (array, null, 0, array.Length, comparer);
                }
 
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, IComparer<TKey> comparer)
                {
                        if (keys == null)
@@ -1522,7 +1576,7 @@ namespace System
                        Sort<TKey, TValue> (keys, items, 0, keys.Length, comparer);
                }
 
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Sort<T> (T [] array, int index, int length)
                {
                        if (array == null)
@@ -1531,13 +1585,13 @@ namespace System
                        Sort<T, T> (array, null, index, length, null);
                }
 
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length)
                {
                        Sort<TKey, TValue> (keys, items, index, length, null);
                }
 
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Sort<T> (T [] array, int index, int length, IComparer<T> comparer)
                {
                        if (array == null)
@@ -1546,7 +1600,7 @@ namespace System
                        Sort<T, T> (array, null, index, length, comparer);
                }
 
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
                {
                        if (keys == null)
@@ -1634,7 +1688,9 @@ namespace System
                        int low = low0;
                        int high = high0;
 
-                       K keyPivot = keys [(low + high) / 2];
+                       // Be careful with overflows
+                       int mid = low + ((high - low) / 2);
+                       K keyPivot = keys [mid];
 
                        while (low <= high) {
                                // Move the walls in
@@ -1660,7 +1716,9 @@ namespace System
 
                private static int compare<T> (T value1, T value2, IComparer<T> comparer)
                {
-                       if (value1 == null)
+                       if (comparer != null)
+                               return comparer.Compare (value1, value2);
+                       else if (value1 == null)
                                return value2 == null ? 0 : -1;
                        else if (value2 == null)
                                return 1;
@@ -1668,8 +1726,6 @@ namespace System
                                return ((IComparable<T>) value1).CompareTo (value2);
                        else if (value1 is IComparable)
                                return ((IComparable) value1).CompareTo (value2);
-                       else if (comparer != null)
-                               return comparer.Compare (value1, value2);
 
                        string msg = Locale.GetText ("No IComparable or IComparable<T> interface found for type '{0}'.");
                        throw new InvalidOperationException (String.Format (msg, typeof (T)));
@@ -1683,7 +1739,9 @@ namespace System
                        int low = low0;
                        int high = high0;
 
-                       T keyPivot = array [(low + high) / 2];
+                       // Be careful with overflows
+                       int mid = low + ((high - low) / 2);
+                       T keyPivot = array [mid];
 
                        while (low <= high) {
                                // Move the walls in
@@ -1743,7 +1801,9 @@ namespace System
                        if (this.Rank > 1)
                                throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
                        if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
-                               throw new ArgumentException ();
+                               throw new ArgumentException ("Destination array was not long " +
+                                       "enough. Check destIndex and length, and the array's " +
+                                       "lower bounds.");
                        if (array.Rank > 1)
                                throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
                        if (index < 0)
@@ -1998,7 +2058,8 @@ namespace System
                        int iCmp = 0;
                        try {
                                while (iMin <= iMax) {
-                                       int iMid = (iMin + iMax) / 2;
+                                       // Be careful with overflows
+                                       int iMid = iMin + ((iMax - iMin) / 2);
                                        iCmp = comparer.Compare (value, array [iMid]);
 
                                        if (iCmp == 0)