2007-10-27 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / class / corlib / System / Array.cs
index 52c05e9d5ffd70d35462b789cf05f4782f5f4c1a..b0653b0169a5da70c7b59b05bbeca7238b9ac337 100644 (file)
@@ -8,10 +8,7 @@
 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
 //
 // (C) 2001-2003 Ximian, Inc.  http://www.ximian.com
-//
-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 using System.Collections;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
+
 #if NET_2_0
 using System.Collections.Generic;
+using System.Collections.ObjectModel;
 using System.Runtime.ConstrainedExecution;
 #endif
+
 namespace System
 {
-
        [Serializable]
-       [MonoTODO ("We are doing way to many double/triple exception checks for the overloaded functions")]
-       [MonoTODO ("Sort overloads parameter checks are VERY inconsistent")]
+#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
        {
                // Constructor
@@ -53,10 +55,204 @@ 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;
+               }
+
+               protected IEnumerator<T> InternalArray__IEnumerable_GetEnumerator<T> ()
+               {
+                       return new InternalEnumerator<T> (this);
+               }
+
+               protected void InternalArray__ICollection_Clear<T> ()
+               {
+                       throw new NotSupportedException ("Collection is read-only");
+               }
+
+               protected void InternalArray__ICollection_Add<T> (T item)
+               {
+                       throw new NotSupportedException ("Collection is read-only");
+               }
+
+               protected bool InternalArray__ICollection_Remove<T> (T item)
+               {
+                       throw new NotSupportedException ("Collection is read-only");
+               }
+
+               protected bool InternalArray__ICollection_Contains<T> (T item)
+               {
+                       if (this.Rank > 1)
+                               throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
+
+                       int length = this.Length;
+                       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;
+                       }
+
+                       return false;
+               }
+
+               protected void InternalArray__ICollection_CopyTo<T> (T[] array, int index)
+               {
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+
+                       // The order of these exception checks may look strange,
+                       // but that's how the microsoft runtime does it.
+                       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 ("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)
+                               throw new ArgumentOutOfRangeException (
+                                       "index", Locale.GetText ("Value has to be >= 0."));
+
+                       Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
+               }
+
+               protected void InternalArray__Insert<T> (int index, T item)
+               {
+                       throw new NotSupportedException ("Collection is read-only");
+               }
+
+               protected void InternalArray__RemoveAt<T> (int index)
+               {
+                       throw new NotSupportedException ("Collection is read-only");
+               }
+
+               protected int InternalArray__IndexOf<T> (T item)
+               {
+                       if (this.Rank > 1)
+                               throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
+
+                       int length = this.Length;
+                       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
+                                       return i + this.GetLowerBound (0);
+                       }
+
+                       int retVal;
+                       unchecked {
+                               // lower bound may be MinValue
+                               retVal = this.GetLowerBound (0) - 1;
+                       }
+
+                       return retVal;
+               }
+
+               protected T InternalArray__get_Item<T> (int index)
+               {
+                       if (unchecked ((uint) index) >= unchecked ((uint) Length))
+                               throw new ArgumentOutOfRangeException ("index");
+
+                       T value;
+                       GetGenericValueImpl (index, out value);
+                       return value;
+               }
+
+               protected void InternalArray__set_Item<T> (int index, T item)
+               {
+                       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;
+                       
+                       // this MUST be -1, because we depend on it in move next.
+                       // we just decr the size, so, 0 - 1 == FINISHED
+                       const int FINISHED = -1;
+                       
+                       Array array;
+                       int idx;
+
+                       internal InternalEnumerator (Array array)
+                       {
+                               this.array = array;
+                               idx = NOT_STARTED;
+                       }
+
+                       public void Dispose ()
+                       {
+                               idx = NOT_STARTED;
+                       }
+
+                       public bool MoveNext ()
+                       {
+                               if (idx == NOT_STARTED)
+                                       idx = array.Length;
+
+                               return idx != FINISHED && -- idx != FINISHED;
+                       }
+
+                       public T Current {
+                               get {
+                                       if (idx < 0)
+                                               throw new InvalidOperationException ();
+
+                                       return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
+                               }
+                       }
+
+                       void IEnumerator.Reset ()
+                       {
+                               throw new NotImplementedException ();
+                       }
+
+                       object IEnumerator.Current {
+                               get {
+                                       return Current;
+                               }
+                       }
+               }
+#endif
+
                // Properties
                public int Length {
 #if NET_2_0
-                       [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.Success)]
+                       [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
 #endif
                        get {
                                int length = this.GetLength (0);
@@ -72,7 +268,7 @@ namespace System
                [ComVisible (false)]
                public long LongLength {
 #if NET_2_0
-                       [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.Success)]
+                       [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
 #endif
                        get { return Length; }
                }
@@ -80,7 +276,7 @@ namespace System
 
                public int Rank {
 #if NET_2_0
-                       [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.Success)]
+                       [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
 #endif
                        get {
                                return this.GetRank ();
@@ -125,7 +321,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
                int IList.IndexOf (object value)
                {
@@ -166,7 +362,7 @@ namespace System
 
                // InternalCall Methods
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern int GetRank ();
+               extern int GetRank ();
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                public extern int GetLength (int dimension);
@@ -180,16 +376,16 @@ namespace System
 #endif
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.Success)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
 #endif
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                public extern int GetLowerBound (int dimension);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               public extern object GetValue (int[] indices);
+               public extern object GetValue (params int[] indices);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               public extern void SetValue (object value, int[] indices);
+               public extern void SetValue (object value, params int[] indices);
 
                // CAUTION! No bounds checking!
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
@@ -212,37 +408,57 @@ namespace System
                        }
                }
 
-               public virtual bool IsSynchronized {
+               public
+#if !NET_2_0
+               virtual
+#endif
+               bool IsSynchronized {
                        get {
                                return false;
                        }
                }
 
-               public virtual object SyncRoot {
+               public
+#if !NET_2_0
+               virtual
+#endif
+               object SyncRoot {
                        get {
                                return this;
                        }
                }
 
-               public virtual bool IsFixedSize {
+               public
+#if !NET_2_0
+               virtual
+#endif
+               bool IsFixedSize {
                        get {
                                return true;
                        }
                }
 
-               public virtual bool IsReadOnly {
+               public
+#if !NET_2_0
+               virtual
+#endif
+               bool IsReadOnly {
                        get {
                                return false;
                        }
                }
 
-               public virtual IEnumerator GetEnumerator ()
+               public
+#if !NET_2_0
+               virtual
+#endif
+               IEnumerator GetEnumerator ()
                {
                        return new SimpleEnumerator (this);
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.Success)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
 #endif
                public int GetUpperBound (int dimension)
                {
@@ -360,30 +576,6 @@ namespace System
                }
 #endif
 
-//             // This function is currently unused, but just in case we need it later on ... */
-//             internal int IndexToPos (int[] idxs)
-//             {
-//                     if (idxs == null)
-//                             throw new ArgumentNullException ("idxs");
-//
-//                     if ((idxs.Rank != 1) || (idxs.Length != Rank))
-//                             throw new ArgumentException ();
-//
-//                     if ((idxs [0] < GetLowerBound (0)) || (idxs [0] > GetUpperBound (0)))
-//                             throw new IndexOutOfRangeException();
-//
-//                     int pos = idxs [0] - GetLowerBound (0);
-//                     for (int i = 1; i < Rank; i++) {
-//                             if ((idxs [i] < GetLowerBound (i)) || (idxs [i] > GetUpperBound (i)))
-//                                     throw new IndexOutOfRangeException();
-//
-//                             pos *= GetLength (i);
-//                             pos += idxs [i] - GetLowerBound (i);
-//                     }
-//
-//                     return pos;
-//             }
-
                public void SetValue (object value, int index)
                {
                        if (Rank != 1)
@@ -410,28 +602,25 @@ namespace System
                public static Array CreateInstance (Type elementType, int length)
                {
                        int[] lengths = {length};
-                       int[] bounds = null;
 
-                       return CreateInstanceImpl (elementType, lengths, bounds);
+                       return CreateInstance (elementType, lengths);
                }
 
                public static Array CreateInstance (Type elementType, int length1, int length2)
                {
                        int[] lengths = {length1, length2};
-                       int[] bounds = null;
 
-                       return CreateInstanceImpl (elementType, lengths, bounds);
+                       return CreateInstance (elementType, lengths);
                }
 
                public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
                {
                        int[] lengths = {length1, length2, length3};
-                       int[] bounds = null;
 
-                       return CreateInstanceImpl (elementType, lengths, bounds);
+                       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");
@@ -442,6 +631,10 @@ namespace System
                                throw new TypeLoadException ();
 
                        int[] bounds = null;
+
+                       elementType = elementType.UnderlyingSystemType;
+                       if (!elementType.IsSystemType)
+                               throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
                        
                        return CreateInstanceImpl (elementType, lengths, bounds);
                }
@@ -455,6 +648,10 @@ namespace System
                        if (bounds == null)
                                throw new ArgumentNullException ("bounds");
 
+                       elementType = elementType.UnderlyingSystemType;
+                       if (!elementType.IsSystemType)
+                               throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
+
                        if (lengths.Length < 1)
                                throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
 
@@ -494,40 +691,37 @@ namespace System
 
                public static Array CreateInstance (Type elementType, params long [] lengths)
                {
-                       if (lengths == null) {
-                               // LAMESPEC: Docs say we should throw a ArgumentNull, but .NET
-                               // 1.1 actually throws a NullReference.
-                               throw new NullReferenceException (Locale.GetText ("'lengths' cannot be null."));
-                       }
+#if NET_2_0
+                       if (lengths == null)
+                               throw new ArgumentNullException ("lengths");
+#endif
                        return CreateInstance (elementType, GetIntArray (lengths));
                }
 
                [ComVisible (false)]
-               public object GetValue (long [] indices)
+               public object GetValue (params long [] indices)
                {
-                       if (indices == null) {
-                               // LAMESPEC: Docs say we should throw a ArgumentNull, but .NET
-                               // 1.1 actually throws a NullReference.
-                               throw new NullReferenceException (Locale.GetText ("'indices' cannot be null."));
-                       }
+#if NET_2_0
+                       if (indices == null)
+                               throw new ArgumentNullException ("indices");
+#endif
                        return GetValue (GetIntArray (indices));
                }
 
                [ComVisible (false)]
-               public void SetValue (object value, long [] indices)
+               public void SetValue (object value, params long [] indices)
                {
-                       if (indices == null) {
-                               // LAMESPEC: Docs say we should throw a ArgumentNull, but .NET
-                               // 1.1 actually throws a NullReference.
-                               throw new NullReferenceException (Locale.GetText ("'indices' cannot be null."));
-                       }
+#if NET_2_0
+                       if (indices == null)
+                               throw new ArgumentNullException ("indices");
+#endif
                        SetValue (value, GetIntArray (indices));
                }
 #endif
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
-#endif
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+#endif 
                public static int BinarySearch (Array array, object value)
                {
                        if (array == null)
@@ -539,6 +733,9 @@ namespace System
                        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."));
 
@@ -546,7 +743,7 @@ namespace System
                }
 
 #if NET_2_0
-       [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
                public static int BinarySearch (Array array, object value, IComparer comparer)
                {
@@ -556,6 +753,9 @@ namespace System
                        if (array.Rank > 1)
                                throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
 
+                       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."));
@@ -564,7 +764,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
                public static int BinarySearch (Array array, int index, int length, object value)
                {
@@ -584,6 +784,10 @@ namespace System
                        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"));
@@ -592,7 +796,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
                public static int BinarySearch (Array array, int index, int length, object value, IComparer comparer)
                {
@@ -613,6 +817,9 @@ namespace System
                                throw new ArgumentException (Locale.GetText (
                                        "index and length do not specify a valid range in array."));
 
+                       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."));
@@ -633,14 +840,16 @@ 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 (value, elt);
+                                       iCmp = comparer.Compare (elt, value);
 
                                        if (iCmp == 0)
                                                return iMid;
-                                       else if (iCmp < 0)
+                                       else if (iCmp > 0)
                                                iMax = iMid - 1;
                                        else
                                                iMin = iMid + 1; // compensate for the rounding down
@@ -654,7 +863,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.Success)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
 #endif
                public static void Clear (Array array, int index, int length)
                {
@@ -679,10 +888,14 @@ namespace System
                static extern void ClearInternal (Array a, int index, int count);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               public virtual extern object Clone ();
+               public
+#if !NET_2_0
+               virtual
+#endif
+               extern object Clone ();
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Copy (Array sourceArray, Array destinationArray, int length)
                {
@@ -699,7 +912,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
                {
@@ -728,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."));
 
@@ -773,7 +996,7 @@ namespace System
 
 #if NET_1_1
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
                                         long destinationIndex, long length)
@@ -800,7 +1023,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Copy (Array sourceArray, Array destinationArray, long length)
                {
@@ -813,7 +1036,7 @@ namespace System
 #endif
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
                public static int IndexOf (Array array, object value)
                {
@@ -824,7 +1047,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
                public static int IndexOf (Array array, object value, int startIndex)
                {
@@ -835,7 +1058,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
                public static int IndexOf (Array array, object value, int startIndex, int count)
                {
@@ -858,7 +1081,6 @@ namespace System
                        return array.GetLowerBound (0) - 1;
                }
 
-               [MonoTODO]
                public void Initialize()
                {
                        //FIXME: We would like to find a compiler that uses
@@ -867,7 +1089,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
                public static int LastIndexOf (Array array, object value)
                {
@@ -878,7 +1100,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
                public static int LastIndexOf (Array array, object value, int startIndex)
                {
@@ -889,7 +1111,7 @@ namespace System
                }
                
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
                public static int LastIndexOf (Array array, object value, int startIndex, int count)
                {
@@ -911,7 +1133,7 @@ namespace System
                        return array.GetLowerBound (0) - 1;
                }
 
-#if !BOOTSTRAP_WITH_OLDLIB && !NET_2_0
+#if !BOOTSTRAP_WITH_OLDLIB
                /* delegate used to swap array elements */
                delegate void Swapper (int i, int j);
 #endif
@@ -929,7 +1151,21 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               static Swapper get_swapper<T> (T [] array)
+               {
+                       if (array is int[])
+                               return new Swapper (array.int_swapper);
+                       if (array is double[])
+                               return new Swapper (array.double_swapper);
+
+                       // gmcs refuses to compile this
+                       //return new Swapper (array.generic_swapper<T>);
+                       return new Swapper (array.slow_swapper);
+               }
+#endif
+
+#if NET_2_0
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Reverse (Array array)
                {
@@ -940,7 +1176,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Reverse (Array array, int index, int length)
                {
@@ -1001,7 +1237,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Sort (Array array)
                {
@@ -1012,7 +1248,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Sort (Array keys, Array items)
                {
@@ -1023,7 +1259,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Sort (Array array, IComparer comparer)
                {
@@ -1034,7 +1270,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Sort (Array array, int index, int length)
                {
@@ -1042,7 +1278,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Sort (Array keys, Array items, IComparer comparer)
                {
@@ -1053,7 +1289,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Sort (Array keys, Array items, int index, int length)
                {
@@ -1061,7 +1297,7 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
                public static void Sort (Array array, int index, int length, IComparer comparer)
                {
@@ -1069,8 +1305,9 @@ namespace System
                }
 
 #if NET_2_0
-               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, CER.MayFail)]
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
 #endif
+
                public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
                {
                        if (keys == null)
@@ -1089,8 +1326,7 @@ namespace System
                                throw new ArgumentOutOfRangeException ("length", Locale.GetText (
                                        "Value has to be >= 0."));
 
-                       if (keys.Length - (index + keys.GetLowerBound (0)) < length
-                               || (items != null && index > items.Length - length))
+                       if (keys.Length - (index + keys.GetLowerBound (0)) < length || (items != null && index > items.Length - length))
                                throw new ArgumentException ();
 
                        if (length <= 1)
@@ -1153,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;
@@ -1243,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
@@ -1292,7 +1539,259 @@ namespace System
                                return comparer.Compare (value1, value2);
                }
        
-               public virtual void CopyTo (Array array, int index)
+#if NET_2_0
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
+               public static void Sort<T> (T [] array)
+               {
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+
+                       Sort<T, T> (array, null, 0, array.Length, null);
+               }
+
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
+               public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items)
+               {
+                       if (keys == null)
+                               throw new ArgumentNullException ("keys");
+                       
+                       Sort<TKey, TValue> (keys, items, 0, keys.Length, null);
+               }
+
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
+               public static void Sort<T> (T [] array, IComparer<T> comparer)
+               {
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+
+                       Sort<T, T> (array, null, 0, array.Length, comparer);
+               }
+
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
+               public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, IComparer<TKey> comparer)
+               {
+                       if (keys == null)
+                               throw new ArgumentNullException ("keys");
+                       
+                       Sort<TKey, TValue> (keys, items, 0, keys.Length, comparer);
+               }
+
+               [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
+               public static void Sort<T> (T [] array, int index, int length)
+               {
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+                       
+                       Sort<T, T> (array, null, index, length, null);
+               }
+
+               [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.MayCorruptInstance, Cer.MayFail)]
+               public static void Sort<T> (T [] array, int index, int length, IComparer<T> comparer)
+               {
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+
+                       Sort<T, T> (array, null, index, length, comparer);
+               }
+
+               [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)
+                               throw new ArgumentNullException ("keys");
+
+                       if (index < 0)
+                               throw new ArgumentOutOfRangeException ("index");
+
+                       if (length < 0)
+                               throw new ArgumentOutOfRangeException ("length");
+
+                       if (keys.Length - index < length
+                               || (items != null && index > items.Length - length))
+                               throw new ArgumentException ();
+
+                       if (length <= 1)
+                               return;
+                       
+                       //
+                       // Check for value types which can be sorted without Compare () method
+                       //
+                       if (comparer == null) {
+                               Swapper iswapper;
+                               if (items == null)
+                                       iswapper = null;
+                               else 
+                                       iswapper = get_swapper<TValue> (items);
+                               if (keys is double[]) {
+                                       combsort (keys as double[], index, length, iswapper);
+                                       return;
+                               }
+                               if (keys is int[]) {
+                                       combsort (keys as int[], index, length, iswapper);
+                                       return;
+                               }
+                               if (keys is char[]) {
+                                       combsort (keys as char[], index, length, iswapper);
+                                       return;
+                               }
+
+                               // Use Comparer<T>.Default instead
+                               // comparer = Comparer<K>.Default;
+                       }
+                       
+                       try {
+                               int low0 = index;
+                               int high0 = index + length - 1;
+                               qsort<TKey, TValue> (keys, items, low0, high0, comparer);
+                       }
+                       catch (Exception e) {
+                               throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
+                       }
+               }
+
+               public static void Sort<T> (T [] array, Comparison<T> comparison)
+               {
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+                       Sort<T> (array, array.Length, comparison);
+               }
+
+               internal static void Sort<T> (T [] array, int length, Comparison<T> comparison)
+               {
+                       if (comparison == null)
+                               throw new ArgumentNullException ("comparison");
+
+                       if (length <= 1 || array.Length <= 1)
+                               return;
+                       
+                       try {
+                               int low0 = 0;
+                               int high0 = length - 1;
+                               qsort<T> (array, low0, high0, comparison);
+                       }
+                       catch (Exception e) {
+                               throw new InvalidOperationException (Locale.GetText ("Comparison threw an exception."), e);
+                       }
+               }
+
+               private static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
+               {
+                       if (low0 >= high0)
+                               return;
+
+                       int low = low0;
+                       int high = high0;
+
+                       // Be careful with overflows
+                       int mid = low + ((high - low) / 2);
+                       K keyPivot = keys [mid];
+
+                       while (low <= high) {
+                               // Move the walls in
+                               //while (low < high0 && comparer.Compare (keys [low], keyPivot) < 0)
+                               while (low < high0 && compare (keys [low], keyPivot, comparer) < 0)
+                                       ++low;
+                               //while (high > low0 && comparer.Compare (keyPivot, keys [high]) < 0)
+                               while (high > low0 && compare (keyPivot, keys [high], comparer) < 0)
+                                       --high;
+
+                               if (low <= high) {
+                                       swap<K, V> (keys, items, low, high);
+                                       ++low;
+                                       --high;
+                               }
+                       }
+
+                       if (low0 < high)
+                               qsort<K, V> (keys, items, low0, high, comparer);
+                       if (low < high0)
+                               qsort<K, V> (keys, items, low, high0, comparer);
+               }
+
+               private static int compare<T> (T value1, T value2, IComparer<T> comparer)
+               {
+                       if (comparer != null)
+                               return comparer.Compare (value1, value2);
+                       else if (value1 == null)
+                               return value2 == null ? 0 : -1;
+                       else if (value2 == null)
+                               return 1;
+                       else if (value1 is IComparable<T>)
+                               return ((IComparable<T>) value1).CompareTo (value2);
+                       else if (value1 is IComparable)
+                               return ((IComparable) value1).CompareTo (value2);
+
+                       string msg = Locale.GetText ("No IComparable or IComparable<T> interface found for type '{0}'.");
+                       throw new InvalidOperationException (String.Format (msg, typeof (T)));
+               }
+
+               private static void qsort<T> (T [] array, int low0, int high0, Comparison<T> comparison)
+               {
+                       if (low0 >= high0)
+                               return;
+
+                       int low = low0;
+                       int high = high0;
+
+                       // Be careful with overflows
+                       int mid = low + ((high - low) / 2);
+                       T keyPivot = array [mid];
+
+                       while (low <= high) {
+                               // Move the walls in
+                               while (low < high0 && comparison (array [low], keyPivot) < 0)
+                                       ++low;
+                               while (high > low0 && comparison (keyPivot, array [high]) < 0)
+                                       --high;
+
+                               if (low <= high) {
+                                       swap<T> (array, low, high);
+                                       ++low;
+                                       --high;
+                               }
+                       }
+
+                       if (low0 < high)
+                               qsort<T> (array, low0, high, comparison);
+                       if (low < high0)
+                               qsort<T> (array, low, high0, comparison);
+               }
+
+               private static void swap<K, V> (K [] keys, V [] items, int i, int j)
+               {
+                       K tmp;
+
+                       tmp = keys [i];
+                       keys [i] = keys [j];
+                       keys [j] = tmp;
+
+                       if (items != null) {
+                               V itmp;
+                               itmp = items [i];
+                               items [i] = items [j];
+                               items [j] = itmp;
+                       }
+               }
+
+               private static void swap<T> (T [] array, int i, int j)
+               {
+                       T tmp = array [i];
+                       array [i] = array [j];
+                       array [j] = tmp;
+               }
+#endif
+               
+               public
+#if !NET_2_0
+               virtual
+#endif
+               void CopyTo (Array array, int index)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
@@ -1302,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)
@@ -1314,7 +1815,11 @@ namespace System
 
 #if NET_1_1
                [ComVisible (false)]
-               public virtual void CopyTo (Array array, long index)
+               public
+#if !NET_2_0
+               virtual
+#endif
+               void CopyTo (Array array, long index)
                {
                        if (index < 0 || index > Int32.MaxValue)
                                throw new ArgumentOutOfRangeException ("index", Locale.GetText (
@@ -1374,158 +1879,164 @@ namespace System
                                return MemberwiseClone ();
                        }
                }
+
 #if NET_2_0
-               [CLSCompliant (false)]
-               public static void Resize <T> (ref T [] arr, int sz) {
-                       if (sz < 0)
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               public static void Resize<T> (ref T [] array, int newSize)
+               {
+                       Resize<T> (ref array, array == null ? 0 : array.Length, newSize);
+               }
+
+               internal static void Resize<T> (ref T[] array, int length, int newSize)
+               {
+                       if (newSize < 0)
                                throw new ArgumentOutOfRangeException ();
                        
-                       if (arr == null) {
-                               arr = new T [sz];
+                       if (array == null) {
+                               array = new T [newSize];
                                return;
                        }
                        
-                       if (arr.Length == sz)
+                       if (array.Length == newSize)
                                return;
                        
-                       T [] a = new T [sz];
-                       Array.Copy (arr, a, Math.Min (sz, arr.Length));
-                       arr = a;
+                       T [] a = new T [newSize];
+                       Array.Copy (array, a, Math.Min (newSize, length));
+                       array = a;
                }
                
-               [CLSCompliant (false)]
-               public static bool TrueForAll <T> (T [] array, Predicate <T> p)
+               public static bool TrueForAll <T> (T [] array, Predicate <T> match)
                {
-                       if (array == null || p == null)
-                               throw new ArgumentNullException ();
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
                        foreach (T t in array)
-                               if (! p (t))
+                               if (! match (t))
                                        return false;
                                
                        return true;
                }
-               [CLSCompliant (false)]
-               public static void ForEach <T> (T [] array, Action <T> a)
+               
+               public static void ForEach<T> (T [] array, Action <T> action)
                {
-                       if (array == null || a == null)
-                               throw new ArgumentNullException ();
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+                       if (action == null)
+                               throw new ArgumentNullException ("action");
                        
                        foreach (T t in array)
-                               a (t);
+                               action (t);
                }
                
-               [CLSCompliant (false)]
-               public static U [] ConvertAll <T, U> (T [] s, Converter <T, U> c)
+               public static TOutput[] ConvertAll<TInput, TOutput> (TInput [] array, Converter<TInput, TOutput> converter)
                {
-                       if (s == null || c == null)
-                               throw new ArgumentNullException ();
-                       
-                       U [] r = new U [s.Length];
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+                       if (converter == null)
+                               throw new ArgumentNullException ("converter");
                        
-                       for (int i = 0; i < s.Length; i ++)
-                               r [i] = c (s [i]);
+                       TOutput [] output = new TOutput [array.Length];
+                       for (int i = 0; i < array.Length; i ++)
+                               output [i] = converter (array [i]);
                        
-                       return r;
+                       return output;
                }
                
-               [CLSCompliant (false)]
-               public static int FindLastIndex <T> (T [] a, Predicate <T> c)
+               public static int FindLastIndex<T> (T [] array, Predicate <T> match)
                {
-                       if (a == null)
-                               throw new ArgumentNullException ();
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
                        
-                       return FindLastIndex <T> (a, 0, a.Length, c);
+                       return FindLastIndex<T> (array, 0, array.Length, match);
                }
                
-               [CLSCompliant (false)]
-               public static int FindLastIndex <T> (T [] a, int idx, Predicate <T> c)
+               public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
                {
-                       if (a == null)
+                       if (array == null)
                                throw new ArgumentNullException ();
                        
-                       return FindLastIndex <T> (a, idx, a.Length - idx, c);
+                       return FindLastIndex<T> (array, startIndex, array.Length - startIndex, match);
                }
                
-               [CLSCompliant (false)]
-               public static int FindLastIndex <T> (T [] a, int idx, int cnt, Predicate <T> c)
+               public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
                {
-                       if (a == null || c == null)
-                               throw new ArgumentNullException ();
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
-                       if (idx > a.Length || idx + cnt > a.Length)
+                       if (startIndex > array.Length || startIndex + count > array.Length)
                                throw new ArgumentOutOfRangeException ();
                        
-                       for (int i = idx + cnt - 1; i >= idx; i --)
-                               if (c (a [i]))
+                       for (int i = startIndex + count - 1; i >= startIndex; i--)
+                               if (match (array [i]))
                                        return i;
                                
                        return -1;
                }
                
-               [CLSCompliant (false)]
-               public static int FindIndex <T> (T [] a, Predicate <T> c)
+               public static int FindIndex<T> (T [] array, Predicate<T> match)
                {
-                       if (a == null)
-                               throw new ArgumentNullException ();
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
                        
-                       return FindIndex <T> (a, 0, a.Length, c);
+                       return FindIndex<T> (array, 0, array.Length, match);
                }
                
-               [CLSCompliant (false)]
-               public static int FindIndex <T> (T [] a, int idx, Predicate <T> c)
+               public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
                {
-                       if (a == null)
-                               throw new ArgumentNullException ();
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
                        
-                       return FindIndex <T> (a, idx, a.Length - idx, c);
+                       return FindIndex<T> (array, startIndex, array.Length - startIndex, match);
                }
                
-               [CLSCompliant (false)]
-               public static int FindIndex <T> (T [] a, int idx, int cnt, Predicate <T> c)
+               public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
                {
-                       if (a == null || c == null)
-                               throw new ArgumentNullException ();
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
                        
-                       if (idx > a.Length || idx + cnt > a.Length)
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
+                       
+                       if (startIndex > array.Length || startIndex + count > array.Length)
                                throw new ArgumentOutOfRangeException ();
                        
-                       for (int i = idx; i < idx + cnt; i ++)
-                               if (c (a [i]))
+                       for (int i = startIndex; i < startIndex + count; i ++)
+                               if (match (array [i]))
                                        return i;
                                
                        return -1;
                }
                
-               [CLSCompliant (false)]
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
-               public static int BinarySearch <T> (T [] array, T value)
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               public static int BinarySearch<T> (T [] array, T value)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
                        
-                       return BinarySearch <T> (array, 0, array.Length, value, null);
+                       return BinarySearch<T> (array, 0, array.Length, value, null);
                }
                
-               [CLSCompliant (false)]
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
-               public static int BinarySearch <T> (T [] array, T value, IComparer <T> comparer)
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               public static int BinarySearch<T> (T [] array, T value, IComparer<T> comparer)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
                        
-                       return BinarySearch <T> (array, 0, array.Length, value, comparer);
+                       return BinarySearch<T> (array, 0, array.Length, value, comparer);
                }
                
-               [CLSCompliant (false)]
-               public static int BinarySearch <T> (T [] array, int offset, int length, T value)
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               public static int BinarySearch<T> (T [] array, int offset, int length, T value)
                {
-                       return BinarySearch <T> (array, offset, length, value, null);
+                       return BinarySearch<T> (array, offset, length, value, null);
                }
                
-               [CLSCompliant (false)]
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.MayFail)]
-               public static int BinarySearch <T> (T [] array, int index, int length, T value, IComparer <T> comparer)
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
+               public static int BinarySearch<T> (T [] array, int index, int length, T value, IComparer<T> comparer)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
@@ -1547,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)
@@ -1557,34 +2069,30 @@ namespace System
                                        else
                                                iMin = iMid + 1; // compensate for the rounding down
                                }
-                       }
-                       catch (Exception e) {
+                       } catch (Exception e) {
                                throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
                        }
 
                        return ~iMin;
                }
                
-               [CLSCompliant (false)]
-               public static int IndexOf <T> (T [] array, T value)
+               public static int IndexOf<T> (T [] array, T value)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
        
-                       return IndexOf (array, value, 0, array.Length);
+                       return IndexOf<T> (array, value, 0, array.Length);
                }
 
-               [CLSCompliant (false)]
-               public static int IndexOf <T> (T [] array, T value, int startIndex)
+               public static int IndexOf<T> (T [] array, T value, int startIndex)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
 
-                       return IndexOf (array, value, startIndex, array.Length - startIndex);
+                       return IndexOf<T> (array, value, startIndex, array.Length - startIndex);
                }
 
-               [CLSCompliant (false)]
-               public static int IndexOf <T> (T [] array, T value, int startIndex, int count)
+               public static int IndexOf<T> (T [] array, T value, int startIndex, int count)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
@@ -1594,34 +2102,32 @@ namespace System
                                throw new ArgumentOutOfRangeException ();
 
                        int max = startIndex + count;
+                       EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
                        for (int i = startIndex; i < max; i++) {
-                               if (Object.Equals (value, array [i]))
+                               if (equalityComparer.Equals (value, array [i]))
                                        return i;
                        }
 
                        return -1;
                }
                
-               [CLSCompliant (false)]
-               public static int LastIndexOf <T> (T [] array, T value)
+               public static int LastIndexOf<T> (T [] array, T value)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
 
-                       return LastIndexOf (array, value, array.Length - 1);
+                       return LastIndexOf<T> (array, value, array.Length - 1);
                }
 
-               [CLSCompliant (false)]
-               public static int LastIndexOf <T> (T [] array, T value, int startIndex)
+               public static int LastIndexOf<T> (T [] array, T value, int startIndex)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
 
-                       return LastIndexOf (array, value, startIndex, startIndex + 1);
+                       return LastIndexOf<T> (array, value, startIndex, startIndex + 1);
                }
 
-               [CLSCompliant (false)]
-               public static int LastIndexOf <T> (T [] array, T value, int startIndex, int count)
+               public static int LastIndexOf<T> (T [] array, T value, int startIndex, int count)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
@@ -1629,207 +2135,184 @@ namespace System
                        if (count < 0 || startIndex > array.Length || startIndex - count + 1 < 0)
                                throw new ArgumentOutOfRangeException ();
 
+                       EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
                        for (int i = startIndex; i >= startIndex - count + 1; i--) {
-                               if (Object.Equals (value, array [i]))
+                               if (equalityComparer.Equals (value, array [i]))
                                        return i;
                        }
 
                        return -1;
                }
                
-               [CLSCompliant (false)]
-               public static T [] FindAll <T> (T [] a, Predicate <T> p)
+               public static T [] FindAll<T> (T [] array, Predicate <T> match)
                {
-                       if (a == null || p == null)
-                               throw new ArgumentNullException ();
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
                        int pos = 0;
-                       T [] d = new T [a.Length];
-                       foreach (T t in a)
-                               if (p (t))
-                                       d [pos ++] = t;
+                       T [] d = new T [array.Length];
+                       foreach (T t in array)
+                               if (match (t))
+                                       d [pos++] = t;
                        
-                       Resize <T> (ref a, pos);
-                       return a;
+                       Resize <T> (ref d, pos);
+                       return d;
                }
 
-               [CLSCompliant (false)]
-               public static bool Exists <T> (T [] a, Predicate <T> p)
+               public static bool Exists<T> (T [] array, Predicate <T> match)
                {
-                       if (a == null || p == null)
-                               throw new ArgumentNullException ();
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
-                       foreach (T t in a)
-                               if (p (t))
+                       foreach (T t in array)
+                               if (match (t))
                                        return true;
                        return false;
                }
 
-               [CLSCompliant (false)]
-               public static IList<T> AsReadOnly<T> (T[] array)
+               public static ReadOnlyCollection<T> AsReadOnly<T> (T[] array)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
-                       return new ReadOnlyArray <T> (array);
+                       return new ReadOnlyCollection<T> (new ArrayReadOnlyList<T> (array));
                }
-               
-#if FIXME
-               [CLSCompliant (false)]
-               public static Nullable <T> Find <T> (T [] a, Predicate <T> p)
+
+               public static T Find<T> (T [] array, Predicate<T> match)
                {
-                       if (a == null || p == null)
-                               throw new ArgumentNullException ();
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
-                       foreach (T t in a)
-                               if (p (t))
-                                       return new Nullable <T> (t);
+                       foreach (T t in array)
+                               if (match (t))
+                                       return t;
                                
-                       return default (Nullable <T>);
+                       return default (T);
                }
                
-               [CLSCompliant (false)]
-               public static Nullable <T> FindLast <T> (T [] a, Predicate <T> p)
+               public static T FindLast<T> (T [] array, Predicate <T> match)
                {
-                       if (a == null || p == null)
-                               throw new ArgumentNullException ();
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
-                       for (int i = a.Length - 1; i >= 0; i--)
-                               if (p (a [i]))
-                                       return new Nullable <T> (a [i]);
+                       for (int i = array.Length - 1; i >= 0; i--)
+                               if (match (array [i]))
+                                       return array [i];
                                
-                       return default (Nullable <T>);
+                       return default (T);
                }
-#endif
 
-#if NET_2_0
-               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, CER.Success)]           
-#endif
-               // Fixme: wtf is constrained about this
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]           
+               //
+               // The constrained copy should guarantee that if there is an exception thrown
+               // during the copy, the destination array remains unchanged.
+               // This is related to System.Runtime.Reliability.CER
                public static void ConstrainedCopy (Array s, int s_i, Array d, int d_i, int c)
                {
                        Copy (s, s_i, d, d_i, c);
-               }               
-#endif
-       }
-
+               }
+#endif 
 
 #if NET_2_0
-               
-       internal struct ReadOnlyArrayEnumerator <T> : IEnumerator <T> {
-               const int NOT_STARTED = -2;
-                       
-               // this MUST be -1, because we depend on it in move next.
-               // we just decr the size, so, 0 - 1 == FINISHED
-               const int FINISHED = -1;
-                       
-               ReadOnlyArray <T> array;
-               int idx;
-                       
-               internal ReadOnlyArrayEnumerator (ReadOnlyArray<T> array)
+               class ArrayReadOnlyList<T> : IList<T>
                {
-                       this.array = array;
-                       idx = NOT_STARTED;
-               }
-                       
-               public void Dispose ()
-               {
-                       idx = NOT_STARTED;
-               }
-                       
-               public bool MoveNext ()
-               {
-                       if (idx == NOT_STARTED)
-                               idx = array.Count;
-                               
-                       return idx != FINISHED && -- idx != FINISHED;
-               }
-                       
-               public T Current {
-                       get {
-                               if (idx < 0)
-                                       throw new InvalidOperationException ();
-                                       
-                               return array [array.Count - 1 - idx];
+                       T [] array;
+                       bool is_value_type;
+
+                       public ArrayReadOnlyList (T [] array)
+                       {
+                               this.array = array;
+                               is_value_type = typeof (T).IsValueType;
                        }
-               }
-       }
 
-       internal class ReadOnlyArray <T> : ICollection <T>, IList <T>, IEnumerable <T>
-       {
-               T[] arr;
+                       public T this [int index] {
+                               get {
+                                       if (unchecked ((uint) index) >= unchecked ((uint) array.Length))
+                                               throw new ArgumentOutOfRangeException ("index");
+                                       return array [index];
+                               }
+                               set { throw ReadOnlyError (); }
+                       }
 
-               internal ReadOnlyArray (T[] array) {
-                       arr = array;
-               }
+                       public int Count {
+                               get { return array.Length; }
+                       }
 
-               // ICollection<T> interface
-               public int Count {
-                       get {
-                               return arr.Length;
+                       public bool IsReadOnly {
+                               get { return true; }
                        }
-               }
 
-               public bool IsReadOnly {
-                       get {
-                               return true;
+                       public void Add (T item)
+                       {
+                               throw ReadOnlyError ();
                        }
-               }
 
-               public void Add (T item) {
-                       throw new NotSupportedException ("Collection is read-only");
-               }
+                       public void Clear ()
+                       {
+                               throw ReadOnlyError ();
+                       }
 
-               public bool Remove (T item) {
-                       throw new NotSupportedException ("Collection is read-only");
-               }
+                       public bool Contains (T item)
+                       {
+                               return Array.IndexOf<T> (array, item) >= 0;
+                       }
 
-               public void Clear () {
-                       throw new NotSupportedException ("Collection is read-only");
-               }
+                       public void CopyTo (T [] array, int index)
+                       {
+                               array.CopyTo (array, index);
+                       }
 
-               public void CopyTo (T[] array, int index) {
-                       arr.CopyTo (array, index);
-               }
+                       IEnumerator IEnumerable.GetEnumerator ()
+                       {
+                               return GetEnumerator ();
+                       }
 
-               public bool Contains (T item) {
-                       return Array.IndexOf <T> (arr, item) != -1;
-               }
+                       public IEnumerator<T> GetEnumerator ()
+                       {
+                               for (int i = 0; i < array.Length; i++)
+                                       yield return array [i];
+                       }
 
-               // IList<T> interface
-               public T this [int index] {
-                       get {
-                               if (unchecked ((uint) index) >= unchecked ((uint) arr.Length))
-                                       throw new ArgumentOutOfRangeException ("index");
-                               return arr [index];
-                       } 
-                       set {
-                               if (unchecked ((uint) index) >= unchecked ((uint) arr.Length))
-                                       throw new ArgumentOutOfRangeException ("index");
-                               arr [index] = value;
+                       public int IndexOf (T item)
+                       {
+                               return Array.IndexOf<T> (array, item);
                        }
-               }
 
-               public void Insert (int index, T item) {
-                       throw new NotSupportedException ("Collection is read-only");
-               }
+                       public void Insert (int index, T item)
+                       {
+                               throw ReadOnlyError ();
+                       }
 
-               public void RemoveAt (int index) {
-                       throw new NotSupportedException ("Collection is read-only");
-               }
+                       public bool Remove (T item)
+                       {
+                               throw ReadOnlyError ();
+                       }
 
-               public int IndexOf (T item) {
-                       return Array.IndexOf <T> (arr, item);
-               }
+                       public void RemoveAt (int index)
+                       {
+                               throw ReadOnlyError ();
+                       }
 
-               // IEnumerable<T> interface
-               public IEnumerator<T> GetEnumerator () {
-                       return new ReadOnlyArrayEnumerator <T> (this);
+                       Exception ReadOnlyError ()
+                       {
+                               return new NotSupportedException ("This collection is read-only.");
+                       }
                }
-       }
-
 #endif
+       }
 
-#if BOOTSTRAP_WITH_OLDLIB || NET_2_0
+#if BOOTSTRAP_WITH_OLDLIB
        /* delegate used to swap array elements, keep defined outside Array */
        delegate void Swapper (int i, int j);
 #endif