From: Marek Safar Date: Wed, 5 Apr 2017 07:33:26 +0000 (+0200) Subject: [corlib] Share corert Array code X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=8b7a2ebc537e8468adeabce81b386a8c08f61ce1;p=mono.git [corlib] Share corert Array code --- diff --git a/mcs/class/corlib/System/Array.cs b/mcs/class/corlib/System/Array.cs index 946647ae149..a72d68e4738 100644 --- a/mcs/class/corlib/System/Array.cs +++ b/mcs/class/corlib/System/Array.cs @@ -589,31 +589,6 @@ namespace System return source.IsAssignableFrom (target) || target.IsAssignableFrom (source); } - public static T[] FindAll (T[] array, Predicate match) - { - if (array == null) - throw new ArgumentNullException ("array"); - - if (match == null) - throw new ArgumentNullException ("match"); - - int pos = 0; - T[] d = Empty(); - for (int i = 0; i < array.Length; i++) { - if (match (array [i])) { - if (pos == d.Length) - Resize (ref d, pos == 0 ? 4 : pos * 2); - - d [pos++] = array [i]; - } - } - - if (pos != d.Length) - Resize (ref d, pos); - - return d; - } - [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)] // // The constrained copy should guarantee that if there is an exception thrown @@ -624,9 +599,40 @@ namespace System Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length); } - object GetValueWithFlattenedIndex_NoErrorCheck (int flattenedIndex) + public static T[] Empty() + { + return EmptyArray.Value; + } + + public void Initialize() + { + return; + } + + static int IndexOfImpl(T[] array, T value, int startIndex, int count) + { + return EqualityComparer.Default.IndexOf (array, value, startIndex, count); + } + + static int LastIndexOfImpl(T[] array, T value, int startIndex, int count) + { + return EqualityComparer.Default.LastIndexOf (array, value, startIndex, count); + } + + static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer) { - return GetValueImpl (flattenedIndex); + Object[] objKeys = keys as Object[]; + Object[] objItems = null; + if (objKeys != null) + objItems = items as Object[]; + + if (objKeys != null && (items == null || objItems != null)) { + SorterObjectArray sorter = new SorterObjectArray(objKeys, objItems, comparer); + sorter.Sort(index, length); + } else { + SorterGenericArray sorter = new SorterGenericArray(keys, items, comparer); + sorter.Sort(index, length); + } } #region Unsafe array operations @@ -678,5 +684,16 @@ namespace System return comparison(x, y); } } + + partial class ArrayEnumerator + { + public Object Current { + get { + if (_index < 0) throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted); + if (_index >= _endIndex) throw new InvalidOperationException(SR.InvalidOperation_EnumEnded); + return _array.GetValueImpl(_index); + } + } + } } } diff --git a/mcs/class/corlib/corert/Array.Portable.cs b/mcs/class/corlib/corert/Array.Portable.cs deleted file mode 100644 index 96e4ee325f4..00000000000 --- a/mcs/class/corlib/corert/Array.Portable.cs +++ /dev/null @@ -1,1619 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime; -using System.Threading; -using System.Collections; -using System.Diagnostics; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Diagnostics.Contracts; -#if MONO -using System.Diagnostics.Private; -#endif - -namespace System -{ - public abstract partial class Array : ICollection, IEnumerable, IList, IStructuralComparable, IStructuralEquatable, ICloneable - { - public static Array CreateInstance(Type elementType, params long[] lengths) - { - if (lengths == null) - throw new ArgumentNullException(nameof(lengths)); - if (lengths.Length == 0) - throw new ArgumentException(SR.Arg_NeedAtLeast1Rank); - - int[] intLengths = new int[lengths.Length]; - - for (int i = 0; i < lengths.Length; ++i) - { - long len = lengths[i]; - if (len > int.MaxValue || len < int.MinValue) - throw new ArgumentOutOfRangeException("len", SR.ArgumentOutOfRange_HugeArrayNotSupported); - intLengths[i] = (int)len; - } - - return Array.CreateInstance(elementType, intLengths); - } - - public static ReadOnlyCollection AsReadOnly(T[] array) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - // T[] implements IList. - return new ReadOnlyCollection(array); - } - - public static void Resize(ref T[] array, int newSize) - { - if (newSize < 0) - throw new ArgumentOutOfRangeException(nameof(newSize), SR.ArgumentOutOfRange_NeedNonNegNum); - - T[] larray = array; - if (larray == null) - { - array = new T[newSize]; - return; - } - - if (larray.Length != newSize) - { - T[] newArray = new T[newSize]; - Copy(larray, 0, newArray, 0, larray.Length > newSize ? newSize : larray.Length); - array = newArray; - } - } - - // Number of elements in the Array. - int ICollection.Count - { get { return Length; } } - - // Is this Array read-only? - bool IList.IsReadOnly - { get { return false; } } - - Object IList.this[int index] - { - get - { - return GetValue(index); - } - - set - { - SetValue(value, index); - } - } - - int IList.Add(Object value) - { - throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); - } - - bool IList.Contains(Object value) - { - return Array.IndexOf(this, value) >= 0; - } - - void IList.Clear() - { - Array.Clear(this, GetLowerBound(0), this.Length); - } - - int IList.IndexOf(Object value) - { - return Array.IndexOf(this, value); - } - - void IList.Insert(int index, Object value) - { - throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); - } - - void IList.Remove(Object value) - { - throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); - } - - void IList.RemoveAt(int index) - { - throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); - } - - // CopyTo copies a collection into an Array, starting at a particular - // index into the array. - // - // This method is to support the ICollection interface, and calls - // Array.Copy internally. If you aren't using ICollection explicitly, - // call Array.Copy to avoid an extra indirection. - // - public void CopyTo(Array array, int index) - { - // Note: Array.Copy throws a RankException and we want a consistent ArgumentException for all the IList CopyTo methods. - if (array != null && array.Rank != 1) - throw new ArgumentException(SR.Arg_RankMultiDimNotSupported); - - Array.Copy(this, GetLowerBound(0), array, index, Length); - } - - // Make a new array which is a deep copy of the original array. - // - public Object Clone() - { - return MemberwiseClone(); - } - - Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) - { - if (other == null) - { - return 1; - } - - Array o = other as Array; - - if (o == null || this.Length != o.Length) - { - throw new ArgumentException(SR.ArgumentException_OtherNotArrayOfCorrectLength, nameof(other)); - } - - int i = 0; - int c = 0; - - while (i < o.Length && c == 0) - { - object left = GetValue(i); - object right = o.GetValue(i); - - c = comparer.Compare(left, right); - i++; - } - - return c; - } - - Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) - { - if (other == null) - { - return false; - } - - if (Object.ReferenceEquals(this, other)) - { - return true; - } - - Array o = other as Array; - - if (o == null || o.Length != this.Length) - { - return false; - } - - int i = 0; - while (i < o.Length) - { - object left = GetValue(i); - object right = o.GetValue(i); - - if (!comparer.Equals(left, right)) - { - return false; - } - i++; - } - - return true; - } - - // From System.Web.Util.HashCodeCombiner - internal static int CombineHashCodes(int h1, int h2) - { - return (((h1 << 5) + h1) ^ h2); - } - - int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) - { - if (comparer == null) - throw new ArgumentNullException(nameof(comparer)); - - int ret = 0; - - for (int i = (this.Length >= 8 ? this.Length - 8 : 0); i < this.Length; i++) - { - ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(i))); - } - - return ret; - } - - // Searches an array for a given element using a binary search algorithm. - // Elements of the array are compared to the search value using the - // IComparable interface, which must be implemented by all elements - // of the array and the given search value. This method assumes that the - // array is already sorted according to the IComparable interface; - // if this is not the case, the result will be incorrect. - // - // The method returns the index of the given value in the array. If the - // array does not contain the given value, the method returns a negative - // integer. The bitwise complement operator (~) can be applied to a - // negative result to produce the index of the first element (if any) that - // is larger than the given search value. - // - public static int BinarySearch(Array array, Object value) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - return BinarySearch(array, array.GetLowerBound(0), array.Length, value, null); - } - - public static TOutput[] ConvertAll(TInput[] array, Converter converter) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - if (converter == null) - throw new ArgumentNullException(nameof(converter)); - - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.Result().Length == array.Length); - Contract.EndContractBlock(); - - TOutput[] newArray = new TOutput[array.Length]; - for (int i = 0; i < array.Length; i++) - { - newArray[i] = converter(array[i]); - } - return newArray; - } - - public static void Copy(Array sourceArray, Array destinationArray, long length) - { - if (length > Int32.MaxValue || length < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_HugeArrayNotSupported); - - Array.Copy(sourceArray, destinationArray, (int)length); - } - - public static void Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length) - { - if (sourceIndex > Int32.MaxValue || sourceIndex < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(sourceIndex), SR.ArgumentOutOfRange_HugeArrayNotSupported); - if (destinationIndex > Int32.MaxValue || destinationIndex < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(destinationIndex), SR.ArgumentOutOfRange_HugeArrayNotSupported); - if (length > Int32.MaxValue || length < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_HugeArrayNotSupported); - - Array.Copy(sourceArray, (int)sourceIndex, destinationArray, (int)destinationIndex, (int)length); - } - - public void CopyTo(Array array, long index) - { - if (index > Int32.MaxValue || index < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_HugeArrayNotSupported); - Contract.EndContractBlock(); - - this.CopyTo(array, (int)index); - } - - public static void ForEach(T[] array, Action action) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - if (action == null) - throw new ArgumentNullException(nameof(action)); - - Contract.EndContractBlock(); - - for (int i = 0; i < array.Length; i++) - { - action(array[i]); - } - } - - public long LongLength - { - get - { - long ret = GetLength(0); - - for (int i = 1; i < Rank; ++i) - { - ret = ret * GetLength(i); - } - - return ret; - } - } - - public long GetLongLength(int dimension) - { - // This method does throw an IndexOutOfRangeException for compat if dimension < 0 or >= Rank - // by calling GetUpperBound - return GetLength(dimension); - } - - public Object GetValue(long index) - { - if (index > Int32.MaxValue || index < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_HugeArrayNotSupported); - Contract.EndContractBlock(); - - return this.GetValue((int)index); - } - - public Object GetValue(long index1, long index2) - { - if (index1 > Int32.MaxValue || index1 < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(index1), SR.ArgumentOutOfRange_HugeArrayNotSupported); - if (index2 > Int32.MaxValue || index2 < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(index2), SR.ArgumentOutOfRange_HugeArrayNotSupported); - Contract.EndContractBlock(); - - return this.GetValue((int)index1, (int)index2); - } - - public Object GetValue(long index1, long index2, long index3) - { - if (index1 > Int32.MaxValue || index1 < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(index1), SR.ArgumentOutOfRange_HugeArrayNotSupported); - if (index2 > Int32.MaxValue || index2 < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(index2), SR.ArgumentOutOfRange_HugeArrayNotSupported); - if (index3 > Int32.MaxValue || index3 < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(index3), SR.ArgumentOutOfRange_HugeArrayNotSupported); - Contract.EndContractBlock(); - - return this.GetValue((int)index1, (int)index2, (int)index3); - } - - public Object GetValue(params long[] indices) - { - if (indices == null) - throw new ArgumentNullException(nameof(indices)); - if (Rank != indices.Length) - throw new ArgumentException(SR.Arg_RankIndices); - Contract.EndContractBlock(); - - int[] intIndices = new int[indices.Length]; - - for (int i = 0; i < indices.Length; ++i) - { - long index = indices[i]; - if (index > Int32.MaxValue || index < Int32.MinValue) - throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_HugeArrayNotSupported); - intIndices[i] = (int)index; - } - - return this.GetValue(intIndices); - } - - public void Initialize() - { - // Project N port note: On the desktop, this api is a nop unless the array element type is a value type with - // an explicit nullary constructor. Such a type cannot be expressed in C# so Project N does not support this. - // The ILC toolchain fails the build if it encounters such a type. - return; - } - - public bool IsFixedSize { get { return true; } } - - public bool IsReadOnly { get { return false; } } - - // Is this Array synchronized (i.e., thread-safe)? If you want a synchronized - // collection, you can use SyncRoot as an object to synchronize your - // collection with. You could also call GetSynchronized() - // to get a synchronized wrapper around the Array. - public bool IsSynchronized { get { return false; } } - - // Returns an object appropriate for synchronizing access to this - // Array. - public Object SyncRoot { get { return this; } } - - // Searches a section of an array for a given element using a binary search - // algorithm. Elements of the array are compared to the search value using - // the IComparable interface, which must be implemented by all - // elements of the array and the given search value. This method assumes - // that the array is already sorted according to the IComparable - // interface; if this is not the case, the result will be incorrect. - // - // The method returns the index of the given value in the array. If the - // array does not contain the given value, the method returns a negative - // integer. The bitwise complement operator (~) can be applied to a - // negative result to produce the index of the first element (if any) that - // is larger than the given search value. - // - public static int BinarySearch(Array array, int index, int length, Object value) - { - return BinarySearch(array, index, length, value, null); - } - - // Searches an array for a given element using a binary search algorithm. - // Elements of the array are compared to the search value using the given - // IComparer interface. If comparer is null, elements of the - // array are compared to the search value using the IComparable - // interface, which in that case must be implemented by all elements of the - // array and the given search value. This method assumes that the array is - // already sorted; if this is not the case, the result will be incorrect. - // - // The method returns the index of the given value in the array. If the - // array does not contain the given value, the method returns a negative - // integer. The bitwise complement operator (~) can be applied to a - // negative result to produce the index of the first element (if any) that - // is larger than the given search value. - // - public static int BinarySearch(Array array, Object value, IComparer comparer) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - return BinarySearch(array, array.GetLowerBound(0), array.Length, value, comparer); - } - - // Searches a section of an array for a given element using a binary search - // algorithm. Elements of the array are compared to the search value using - // the given IComparer interface. If comparer is null, - // elements of the array are compared to the search value using the - // IComparable interface, which in that case must be implemented by - // all elements of the array and the given search value. This method - // assumes that the array is already sorted; if this is not the case, the - // result will be incorrect. - // - // The method returns the index of the given value in the array. If the - // array does not contain the given value, the method returns a negative - // integer. The bitwise complement operator (~) can be applied to a - // negative result to produce the index of the first element (if any) that - // is larger than the given search value. - // - public static int BinarySearch(Array array, int index, int length, Object value, IComparer comparer) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - if (index < 0 || length < 0) - throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum); - if (array.Length - index < length) - throw new ArgumentException(SR.Argument_InvalidOffLen); - if (array.Rank != 1) - throw new RankException(SR.Rank_MultiDimNotSupported); - - if (comparer == null) comparer = LowLevelComparer.Default; - - int lo = index; - int hi = index + length - 1; - Object[] objArray = array as Object[]; - if (objArray != null) - { - while (lo <= hi) - { - // i might overflow if lo and hi are both large positive numbers. - int i = GetMedian(lo, hi); - - int c; - try - { - c = comparer.Compare(objArray[i], value); - } - catch (Exception e) - { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); - } - if (c == 0) return i; - if (c < 0) - { - lo = i + 1; - } - else - { - hi = i - 1; - } - } - } - else - { - while (lo <= hi) - { - int i = GetMedian(lo, hi); - - int c; - try - { - c = comparer.Compare(array.GetValue(i), value); - } - catch (Exception e) - { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); - } - if (c == 0) return i; - if (c < 0) - { - lo = i + 1; - } - else - { - hi = i - 1; - } - } - } - return ~lo; - } - - private static int GetMedian(int low, int hi) - { - // Note both may be negative, if we are dealing with arrays w/ negative lower bounds. - return low + ((hi - low) >> 1); - } - - public static int BinarySearch(T[] array, T value) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - return BinarySearch(array, 0, array.Length, value, null); - } - - public static int BinarySearch(T[] array, T value, System.Collections.Generic.IComparer comparer) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - return BinarySearch(array, 0, array.Length, value, comparer); - } - - public static int BinarySearch(T[] array, int index, int length, T value) - { - return BinarySearch(array, index, length, value, null); - } - - public static int BinarySearch(T[] array, int index, int length, T value, System.Collections.Generic.IComparer comparer) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - if (index < 0 || length < 0) - throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum); - if (array.Length - index < length) - throw new ArgumentException(SR.Argument_InvalidOffLen); - - return ArraySortHelper.BinarySearch(array, index, length, value, comparer); - } - - // Returns the index of the first occurrence of a given value in an array. - // The array is searched forwards, and the elements of the array are - // compared to the given value using the Object.Equals method. - // - public static int IndexOf(Array array, Object value) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - return IndexOf(array, value, array.GetLowerBound(0), array.Length); - } - - // Returns the index of the first occurrence of a given value in a range of - // an array. The array is searched forwards, starting at index - // startIndex and ending at the last element of the array. The - // elements of the array are compared to the given value using the - // Object.Equals method. - // - public static int IndexOf(Array array, Object value, int startIndex) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - int lb = array.GetLowerBound(0); - return IndexOf(array, value, startIndex, array.Length - startIndex + lb); - } - - // Returns the index of the first occurrence of a given value in a range of - // an array. The array is searched forwards, starting at index - // startIndex and upto count elements. The - // elements of the array are compared to the given value using the - // Object.Equals method. - // - public static int IndexOf(Array array, Object value, int startIndex, int count) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - if (array.Rank != 1) - throw new RankException(SR.Rank_MultiDimNotSupported); - int lb = array.GetLowerBound(0); - if (startIndex < lb || startIndex > array.Length + lb) - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - if (count < 0 || count > array.Length - startIndex + lb) - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - - Object[] objArray = array as Object[]; - int endIndex = startIndex + count; - if (objArray != null) - { - if (value == null) - { - for (int i = startIndex; i < endIndex; i++) - { - if (objArray[i] == null) return i; - } - } - else - { - for (int i = startIndex; i < endIndex; i++) - { - Object obj = objArray[i]; - if (obj != null && obj.Equals(value)) return i; - } - } - } - else - { - for (int i = startIndex; i < endIndex; i++) - { - Object obj = array.GetValue(i); - if (obj == null) - { - if (value == null) return i; - } - else - { - if (obj.Equals(value)) return i; - } - } - } - return lb - 1; - } - - /// - /// This version is called from Array.IndexOf and Contains, so it's in every unique array instance due to array interface implementation. - /// Do not call into IndexOf(Array array, Object value, int startIndex, int count) for size and space reasons. - /// Otherwise there will be two IndexOf methods for each unique array instance, and extra parameter checking which are not needed for the common case. - /// - public static int IndexOf(T[] array, T value) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - // See comment above Array.GetComparerForReferenceTypesOnly for details - EqualityComparer comparer = GetComparerForReferenceTypesOnly(); - - if (comparer != null) - { - for (int i = 0; i < array.Length; i++) - { - if (comparer.Equals(array[i], value)) - return i; - } - } - else - { - for (int i = 0; i < array.Length; i++) - { - if (StructOnlyEquals(array[i], value)) - return i; - } - } - - return -1; - } - - public static int IndexOf(T[] array, T value, int startIndex) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - return IndexOf(array, value, startIndex, array.Length - startIndex); - } - - public static int IndexOf(T[] array, T value, int startIndex, int count) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (startIndex < 0 || startIndex > array.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - - if (count < 0 || count > array.Length - startIndex) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - - int endIndex = startIndex + count; - - // See comment above Array.GetComparerForReferenceTypesOnly for details - EqualityComparer comparer = GetComparerForReferenceTypesOnly(); - - if (comparer != null) - { - for (int i = startIndex; i < endIndex; i++) - { - if (comparer.Equals(array[i], value)) - return i; - } - } - else - { - for (int i = startIndex; i < endIndex; i++) - { - if (StructOnlyEquals(array[i], value)) - return i; - } - } - - return -1; - } - - public static int LastIndexOf(Array array, Object value) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - return LastIndexOf(array, value, array.Length - 1, array.Length); - } - - // Returns the index of the last occurrence of a given value in a range of - // an array. The array is searched backwards, starting at index - // startIndex and ending at index 0. The elements of the array are - // compared to the given value using the Object.Equals method. - // - public static int LastIndexOf(Array array, Object value, int startIndex) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - return LastIndexOf(array, value, startIndex, startIndex + 1); - } - - // Returns the index of the last occurrence of a given value in a range of - // an array. The array is searched backwards, starting at index - // startIndex and counting uptocount elements. The elements of - // the array are compared to the given value using the Object.Equals - // method. - // - public static int LastIndexOf(Array array, Object value, int startIndex, int count) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - if (array.Length == 0) - { - return -1; - } - - if (startIndex < 0 || startIndex >= array.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - if (count < 0) - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - if (count > startIndex + 1) - throw new ArgumentOutOfRangeException("endIndex", SR.ArgumentOutOfRange_EndIndexStartIndex); - if (array.Rank != 1) - throw new RankException(SR.Rank_MultiDimNotSupported); - - Object[] objArray = array as Object[]; - int endIndex = startIndex - count + 1; - if (objArray != null) - { - if (value == null) - { - for (int i = startIndex; i >= endIndex; i--) - { - if (objArray[i] == null) return i; - } - } - else - { - for (int i = startIndex; i >= endIndex; i--) - { - Object obj = objArray[i]; - if (obj != null && obj.Equals(value)) return i; - } - } - } - else - { - for (int i = startIndex; i >= endIndex; i--) - { - Object obj = array.GetValue(i); - if (obj == null) - { - if (value == null) return i; - } - else - { - if (obj.Equals(value)) return i; - } - } - } - return -1; // Return lb-1 for arrays with negative lower bounds. - } - - public static int LastIndexOf(T[] array, T value) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - return LastIndexOf(array, value, array.Length - 1, array.Length); - } - - public static int LastIndexOf(T[] array, T value, int startIndex) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - // if array is empty and startIndex is 0, we need to pass 0 as count - return LastIndexOf(array, value, startIndex, (array.Length == 0) ? 0 : (startIndex + 1)); - } - - public static int LastIndexOf(T[] array, T value, int startIndex, int count) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (array.Length == 0) - { - // - // Special case for 0 length List - // accept -1 and 0 as valid startIndex for compablility reason. - // - if (startIndex != -1 && startIndex != 0) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - - // only 0 is a valid value for count if array is empty - if (count != 0) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - return -1; - } - - // Make sure we're not out of range - if (startIndex < 0 || startIndex >= array.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - - // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0. - if (count < 0 || startIndex - count + 1 < 0) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - - // See comment above Array.GetComparerForReferenceTypesOnly for details - EqualityComparer comparer = GetComparerForReferenceTypesOnly(); - - int endIndex = startIndex - count + 1; - if (comparer != null) - { - for (int i = startIndex; i >= endIndex; i--) - { - if (comparer.Equals(array[i], value)) - return i; - } - } - else - { - for (int i = startIndex; i >= endIndex; i--) - { - if (StructOnlyEquals(array[i], value)) - return i; - } - } - - return -1; - } - - // Reverses all elements of the given array. Following a call to this - // method, an element previously located at index i will now be - // located at index length - i - 1, where length is the - // length of the array. - // - public static void Reverse(Array array) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - Reverse(array, array.GetLowerBound(0), array.Length); - } - - // Reverses the elements in a range of an array. Following a call to this - // method, an element in the range given by index and count - // which was previously located at index i will now be located at - // index index + (index + count - i - 1). - // Reliability note: This may fail because it may have to box objects. - // - public static void Reverse(Array array, int index, int length) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - int lowerBound = array.GetLowerBound(0); - if (index < lowerBound || length < 0) - throw new ArgumentOutOfRangeException((index < lowerBound ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum); - if (array.Length - (index - lowerBound) < length) - throw new ArgumentException(SR.Argument_InvalidOffLen); - if (array.Rank != 1) - throw new RankException(SR.Rank_MultiDimNotSupported); - - int i = index; - int j = index + length - 1; - Object[] objArray = array as Object[]; - if (objArray != null) - { - while (i < j) - { - Object temp = objArray[i]; - objArray[i] = objArray[j]; - objArray[j] = temp; - i++; - j--; - } - } - else - { - while (i < j) - { - Object temp = array.GetValue(i); - array.SetValue(array.GetValue(j), i); - array.SetValue(temp, j); - i++; - j--; - } - } - } - - public static void Reverse(T[] array) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - Reverse(array, 0, array.Length); - } - - public static void Reverse(T[] array, int index, int length) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - if (index < 0 || length < 0) - throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(length)), SR.ArgumentOutOfRange_NeedNonNegNum); - if (array.Length - index < length) - throw new ArgumentException(SR.Argument_InvalidOffLen); - - int i = index; - int j = index + length - 1; - while (i < j) - { - T temp = array[i]; - array[i] = array[j]; - array[j] = temp; - i++; - j--; - } - } - - public void SetValue(object value, long index) - { - if (index > int.MaxValue || index < int.MinValue) - throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_HugeArrayNotSupported); - - SetValue(value, (int)index); - } - - public void SetValue(object value, long index1, long index2) - { - if (index1 > int.MaxValue || index1 < int.MinValue) - throw new ArgumentOutOfRangeException(nameof(index1), SR.ArgumentOutOfRange_HugeArrayNotSupported); - if (index2 > int.MaxValue || index2 < int.MinValue) - throw new ArgumentOutOfRangeException(nameof(index2), SR.ArgumentOutOfRange_HugeArrayNotSupported); - - SetValue(value, (int)index1, (int)index2); - } - - public void SetValue(object value, long index1, long index2, long index3) - { - if (index1 > int.MaxValue || index1 < int.MinValue) - throw new ArgumentOutOfRangeException(nameof(index1), SR.ArgumentOutOfRange_HugeArrayNotSupported); - if (index2 > int.MaxValue || index2 < int.MinValue) - throw new ArgumentOutOfRangeException(nameof(index2), SR.ArgumentOutOfRange_HugeArrayNotSupported); - if (index3 > int.MaxValue || index3 < int.MinValue) - throw new ArgumentOutOfRangeException(nameof(index3), SR.ArgumentOutOfRange_HugeArrayNotSupported); - - SetValue(value, (int)index1, (int)index2, (int)index3); - } - - public void SetValue(object value, params long[] indices) - { - if (indices == null) - throw new ArgumentNullException(nameof(indices)); - if (Rank != indices.Length) - throw new ArgumentException(SR.Arg_RankIndices); - - int[] intIndices = new int[indices.Length]; - - for (int i = 0; i < indices.Length; ++i) - { - long index = indices[i]; - if (index > int.MaxValue || index < int.MinValue) - throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_HugeArrayNotSupported); - intIndices[i] = (int)index; - } - - SetValue(value, intIndices); - } - - // Sorts the elements of an array. The sort compares the elements to each - // other using the IComparable interface, which must be implemented - // by all elements of the array. - // - public static void Sort(Array array) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - Sort(array, null, array.GetLowerBound(0), array.Length, null); - } - - // Sorts the elements in a section of an array. The sort compares the - // elements to each other using the IComparable interface, which - // must be implemented by all elements in the given section of the array. - // - public static void Sort(Array array, int index, int length) - { - Sort(array, null, index, length, null); - } - - // Sorts the elements of an array. The sort compares the elements to each - // other using the given IComparer interface. If comparer is - // null, the elements are compared to each other using the - // IComparable interface, which in that case must be implemented by - // all elements of the array. - // - public static void Sort(Array array, IComparer comparer) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - Sort(array, null, array.GetLowerBound(0), array.Length, comparer); - } - - // Sorts the elements in a section of an array. The sort compares the - // elements to each other using the given IComparer interface. If - // comparer is null, the elements are compared to each other using - // the IComparable interface, which in that case must be implemented - // by all elements in the given section of the array. - // - public static void Sort(Array array, int index, int length, IComparer comparer) - { - Sort(array, null, index, length, comparer); - } - - public static void Sort(Array keys, Array items) - { - if (keys == null) - { - throw new ArgumentNullException(nameof(keys)); - } - - Sort(keys, items, keys.GetLowerBound(0), keys.Length, null); - } - - public static void Sort(Array keys, Array items, IComparer comparer) - { - if (keys == null) - { - throw new ArgumentNullException(nameof(keys)); - } - - Sort(keys, items, keys.GetLowerBound(0), keys.Length, comparer); - } - - public static void Sort(Array keys, Array items, int index, int length) - { - Sort(keys, items, index, length, null); - } - - public static void Sort(Array keys, Array items, int index, int length, IComparer comparer) - { - if (keys == null) - throw new ArgumentNullException(nameof(keys)); - if (keys.Rank != 1 || (items != null && items.Rank != 1)) - throw new RankException(SR.Rank_MultiDimNotSupported); - int keysLowerBound = keys.GetLowerBound(0); - if (items != null && keysLowerBound != items.GetLowerBound(0)) - throw new ArgumentException(SR.Arg_LowerBoundsMustMatch); - if (index < keysLowerBound || length < 0) - throw new ArgumentOutOfRangeException((length < 0 ? nameof(length) : nameof(index)), SR.ArgumentOutOfRange_NeedNonNegNum); - if (keys.Length - (index - keysLowerBound) < length || (items != null && (index - keysLowerBound) > items.Length - length)) - throw new ArgumentException(SR.Argument_InvalidOffLen); - - if (length > 1) - { -#if CORERT - IComparer comparerT = new ComparerAsComparerT(comparer); - Object[] objKeys = keys as Object[]; - Object[] objItems = items as Object[]; - - // Unfortunately, on Project N, we don't have the ability to specialize ArraySortHelper<> on demand - // for value types. Rather than incur a boxing cost on every compare and every swap (and maintain a separate introsort algorithm - // just for this), box them all, sort them as an Object[] array and unbox them back. - - // Check if either of the arrays need to be copied. - if (objKeys == null) - { - objKeys = new Object[index + length]; - Array.CopyImplValueTypeArrayToReferenceArray(keys, index, objKeys, index, length, reliable: false); - } - if (objItems == null && items != null) - { - objItems = new Object[index + length]; - Array.CopyImplValueTypeArrayToReferenceArray(items, index, objItems, index, length, reliable: false); - } - - Sort(objKeys, objItems, index, length, comparerT); - - // If either array was copied, copy it back into the original - if (objKeys != keys) - { - Array.CopyImplReferenceArrayToValueTypeArray(objKeys, index, keys, index, length, reliable: false); - } - if (objItems != items) - { - Array.CopyImplReferenceArrayToValueTypeArray(objItems, index, items, index, length, reliable: false); - } -#else - Object[] objKeys = keys as Object[]; - Object[] objItems = null; - if (objKeys != null) - objItems = items as Object[]; - if (objKeys != null && (items == null || objItems != null)) - { - SorterObjectArray sorter = new SorterObjectArray(objKeys, objItems, comparer); - sorter.Sort(index, length); - } - else - { - SorterGenericArray sorter = new SorterGenericArray(keys, items, comparer); - sorter.Sort(index, length); - } -#endif - } - } - - // Wraps an IComparer inside an IComparer. - private sealed class ComparerAsComparerT : IComparer - { - public ComparerAsComparerT(IComparer comparer) - { - _comparer = (comparer == null) ? LowLevelComparer.Default : comparer; - } - - public int Compare(Object x, Object y) - { - return _comparer.Compare(x, y); - } - - private IComparer _comparer; - } - - public static void Sort(T[] array) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - Sort(array, 0, array.Length, null); - } - - public static void Sort(T[] array, int index, int length) - { - Sort(array, index, length, null); - } - - public static void Sort(T[] array, System.Collections.Generic.IComparer comparer) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - Sort(array, 0, array.Length, comparer); - } - - public static void Sort(T[] array, int index, int length, System.Collections.Generic.IComparer comparer) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - if (index < 0 || length < 0) - throw new ArgumentOutOfRangeException((length < 0 ? nameof(length) : nameof(index)), SR.ArgumentOutOfRange_NeedNonNegNum); - if (array.Length - index < length) - throw new ArgumentException(SR.Argument_InvalidOffLen); - - if (length > 1) - ArraySortHelper.Sort(array, index, length, comparer); - } - - public static void Sort(T[] array, Comparison comparison) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (comparison == null) - { - throw new ArgumentNullException(nameof(comparison)); - } - - ArraySortHelper.Sort(array, 0, array.Length, comparison); - } - - public static void Sort(TKey[] keys, TValue[] items) - { - if (keys == null) - throw new ArgumentNullException(nameof(keys)); - Contract.EndContractBlock(); - Sort(keys, items, 0, keys.Length, null); - } - - public static void Sort(TKey[] keys, TValue[] items, int index, int length) - { - Sort(keys, items, index, length, null); - } - - public static void Sort(TKey[] keys, TValue[] items, IComparer comparer) - { - if (keys == null) - throw new ArgumentNullException(nameof(keys)); - Contract.EndContractBlock(); - Sort(keys, items, 0, keys.Length, comparer); - } - - public static void Sort(TKey[] keys, TValue[] items, int index, int length, IComparer comparer) - { - if (keys == null) - throw new ArgumentNullException(nameof(keys)); - if (index < 0 || length < 0) - throw new ArgumentOutOfRangeException((length < 0 ? nameof(length) : nameof(index)), SR.ArgumentOutOfRange_NeedNonNegNum); - if (keys.Length - index < length || (items != null && index > items.Length - length)) - throw new ArgumentException(SR.Argument_InvalidOffLen); - Contract.EndContractBlock(); - - if (length > 1) - { - if (items == null) - { - Sort(keys, index, length, comparer); - return; - } - - ArraySortHelper.Default.Sort(keys, items, index, length, comparer); - } - } - - public static T[] Empty() - { - return EmptyArray.Value; - } - - public static bool Exists(T[] array, Predicate match) - { - return Array.FindIndex(array, match) != -1; - } - - public static void Fill(T[] array, T value) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - for (int i = 0; i < array.Length; i++) - { - array[i] = value; - } - } - - public static void Fill(T[] array, T value, int startIndex, int count) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (startIndex < 0 || startIndex > array.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - - if (count < 0 || startIndex > array.Length - count) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - - for (int i = startIndex; i < startIndex + count; i++) - { - array[i] = value; - } - } - - public static T Find(T[] array, Predicate match) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (match == null) - { - throw new ArgumentNullException(nameof(match)); - } - - for (int i = 0; i < array.Length; i++) - { - if (match(array[i])) - { - return array[i]; - } - } - return default(T); - } - - public static int FindIndex(T[] array, Predicate match) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - return FindIndex(array, 0, array.Length, match); - } - - public static int FindIndex(T[] array, int startIndex, Predicate match) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - return FindIndex(array, startIndex, array.Length - startIndex, match); - } - - public static int FindIndex(T[] array, int startIndex, int count, Predicate match) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (startIndex < 0 || startIndex > array.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - - if (count < 0 || startIndex > array.Length - count) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - - if (match == null) - { - throw new ArgumentNullException(nameof(match)); - } - - int endIndex = startIndex + count; - for (int i = startIndex; i < endIndex; i++) - { - if (match(array[i])) return i; - } - return -1; - } - - public static T FindLast(T[] array, Predicate match) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (match == null) - { - throw new ArgumentNullException(nameof(match)); - } - - for (int i = array.Length - 1; i >= 0; i--) - { - if (match(array[i])) - { - return array[i]; - } - } - return default(T); - } - - public static int FindLastIndex(T[] array, Predicate match) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - return FindLastIndex(array, array.Length - 1, array.Length, match); - } - - public static int FindLastIndex(T[] array, int startIndex, Predicate match) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - return FindLastIndex(array, startIndex, startIndex + 1, match); - } - - public static int FindLastIndex(T[] array, int startIndex, int count, Predicate match) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (match == null) - { - throw new ArgumentNullException(nameof(match)); - } - - if (array.Length == 0) - { - // Special case for 0 length List - if (startIndex != -1) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - } - else - { - // Make sure we're not out of range - if (startIndex < 0 || startIndex >= array.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - } - - // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0. - if (count < 0 || startIndex - count + 1 < 0) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - - int endIndex = startIndex - count; - for (int i = startIndex; i > endIndex; i--) - { - if (match(array[i])) - { - return i; - } - } - return -1; - } - - public static bool TrueForAll(T[] array, Predicate match) - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (match == null) - { - throw new ArgumentNullException(nameof(match)); - } - - for (int i = 0; i < array.Length; i++) - { - if (!match(array[i])) - { - return false; - } - } - return true; - } - - public IEnumerator GetEnumerator() - { - return new ArrayEnumerator(this); - } - - // These functions look odd, as they are part of a complex series of compiler intrinsics - // designed to produce very high quality code for equality comparison cases without utilizing - // reflection like other platforms. The major complication is that the specification of - // IndexOf is that it is supposed to use IEquatable if possible, but that requirement - // cannot be expressed in IL directly due to the lack of constraints. - // Instead, specialization at call time is used within the compiler. - // - // General Approach - // - Perform fancy redirection for Array.GetComparerForReferenceTypesOnly(). If T is a reference - // type or UniversalCanon, have this redirect to EqualityComparer.get_Default, Otherwise, use - // the function as is. (will return null in that case) - // - Change the contents of the IndexOf functions to have a pair of loops. One for if - // GetComparerForReferenceTypesOnly returns null, and one for when it does not. - // - If it does not return null, call the EqualityComparer code. - // - If it does return null, use a special function StructOnlyEquals(). - // - Calls to that function result in calls to a pair of helper function in - // EqualityComparerHelpers (StructOnlyEqualsIEquatable, or StructOnlyEqualsNullable) - // depending on whether or not they are the right function to call. - // - The end result is that in optimized builds, we have the same single function compiled size - // characteristics that the old EqualsOnlyComparer.Equals function had, but we maintain - // correctness as well. - private static EqualityComparer GetComparerForReferenceTypesOnly() - { -#if !CORERT - return System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences () ? EqualityComparer.Default : null; -#else - return EqualityComparer.Default; -#endif - } - - private static bool StructOnlyEquals(T left, T right) - { - return left.Equals(right); - } - - private sealed class ArrayEnumerator : IEnumerator, ICloneable - { - private Array _array; - private int _index; - private int _endIndex; // cache array length, since it's a little slow. - - internal ArrayEnumerator(Array array) - { - _array = array; - _index = -1; - _endIndex = array.Length; - } - - public bool MoveNext() - { - if (_index < _endIndex) - { - _index++; - return (_index < _endIndex); - } - return false; - } - - public Object Current - { - get - { - if (_index < 0) throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted); - if (_index >= _endIndex) throw new InvalidOperationException(SR.InvalidOperation_EnumEnded); - return _array.GetValueWithFlattenedIndex_NoErrorCheck(_index); - } - } - - public void Reset() - { - _index = -1; - } - - public object Clone() - { - return MemberwiseClone(); - } - } - } -} \ No newline at end of file diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index 6fb6cd13270..8859e1f1cb5 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -1639,7 +1639,6 @@ ReferenceSources/Type.cs coreclr/SorterArray.cs corert/AddrofIntrinsics.cs -corert/Array.Portable.cs corert/Debug.cs corert/Interop.cs corert/Interop.MemAllocFree.cs @@ -1677,6 +1676,7 @@ corert/RuntimeThread.cs ../../../external/corert/src/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeThreadPoolIOHandle.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Array.cs ../../../external/corert/src/System.Private.CoreLib/src/System/Tuple.cs ../../../external/corert/src/System.Private.CoreLib/src/System/ValueTuple.cs