using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; namespace system { [System.Serializable] public abstract class Array : System.ICloneable, IList, IStructuralComparable, IStructuralEquatable { // // Array helper proxy used when casting an array to an interface // or to System.Array // [java.attr.RetainType] private object arr; [java.attr.RetainType] private int len; [java.attr.RetainType] private int rank; [java.attr.RetainType] private bool jagged; protected Array(object _arr) { arr = _arr; len = java.lang.reflect.Array.getLength(_arr); var s = ((java.lang.Object) arr).getClass().getName(); for (; rank < s.Length && s[rank] == '['; rank++) ; } static void ThrowIfNull(object checkObject) { if (checkObject == null) throw new System.ArgumentNullException(); } int ICollection.Count => len; // // ICloneable // public object Clone() => Clone(arr, len); public static object Clone(object arr, int len) { switch (arr) { case bool[] boolArray: return java.util.Arrays.copyOf(boolArray, len); case sbyte[] byteArray: return java.util.Arrays.copyOf(byteArray, len); case char[] charArray: return java.util.Arrays.copyOf(charArray, len); case short[] shortArray: return java.util.Arrays.copyOf(shortArray, len); case int[] intArray: return java.util.Arrays.copyOf(intArray, len); case long[] longArray: return java.util.Arrays.copyOf(longArray, len); case float[] floatArray: return java.util.Arrays.copyOf(floatArray, len); case double[] doubleArray: return java.util.Arrays.copyOf(doubleArray, len); } var type = ((java.lang.Object) arr).getClass().getComponentType(); var copy = java.util.Arrays.copyOf((object[]) arr, len); int idx; object obj; if (type.isArray()) { for (idx = 0; idx < len; idx++) { obj = java.lang.reflect.Array.get(copy, idx); if (obj != null) { obj = Clone(obj, java.lang.reflect.Array.getLength(obj)); java.lang.reflect.Array.set(copy, idx, obj); } } } else if (system.RuntimeType.IsValueClass(type)) { var copyArray = (ValueType[]) copy; for (idx = 0; idx < len; idx++) copyArray[idx] = ((ValueMethod) copyArray[idx]).Clone(); } return copy; } // // ConstrainedCopy, Copy, CopyTo, ICollection.CopyTo // private static void CheckCopyArgs(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length) { ThrowIfNull(sourceArray); ThrowIfNull(destinationArray); if ( sourceArray.rank != 1 && (! sourceArray.jagged) || sourceArray.rank != destinationArray.rank || sourceArray.jagged != destinationArray.jagged) throw new System.RankException(); if (sourceIndex < 0 || destinationIndex < 0) throw new System.ArgumentOutOfRangeException(); if ( sourceIndex + length > sourceArray.len || destinationIndex + length > destinationArray.len) throw new System.ArgumentException(); } public static void ConstrainedCopy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length) { CheckCopyArgs(sourceArray, sourceIndex, destinationArray, destinationIndex, length); var destinationArray_arr = destinationArray.arr; object copy = Clone(destinationArray_arr, destinationArray.len); try { CopyInternal(sourceArray.arr, sourceIndex, destinationArray_arr, destinationIndex, length); copy = null; } finally { if (copy != null) { CopyInternal(copy, sourceIndex, destinationArray_arr, destinationIndex, length); } } } public void CopyTo(System.Array array, long index) { int intIndex = (int) index; if (intIndex != index) throw new System.ArgumentOutOfRangeException(); CopyTo(array, intIndex); } public void CopyTo(System.Array array, int index) { // note that CopyTo is defined to only work for single dim arrays Copy(this, 0, (system.Array) (object) array, index, len); } public static void Copy(Array sourceArray, Array destinationArray, int length) => Copy(sourceArray, 0, destinationArray, 0, length); public static void Copy(Array sourceArray, Array destinationArray, long length) => Copy(sourceArray, 0, destinationArray, 0, length); public static void Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length) { int intSourceIndex = (int) sourceIndex; int intDestinationIndex = (int) destinationIndex; int intLength = (int) length; if (intSourceIndex != sourceIndex || intDestinationIndex != destinationIndex) throw new System.ArgumentOutOfRangeException(); if (intLength != length) throw new System.ArgumentOutOfRangeException(); Copy(sourceArray, intSourceIndex, destinationArray, intDestinationIndex, intLength); } public static void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length) { CheckCopyArgs(sourceArray, sourceIndex, destinationArray, destinationIndex, length); CopyInternal(sourceArray.arr, sourceIndex, destinationArray.arr, destinationIndex, length); } private static void CopyInternal(object srcArr, int srcIndex, object dstArr, int dstIndex, int length) { var srcElemType = ((java.lang.Object) srcArr).getClass().getComponentType(); var dstElemType = ((java.lang.Object) dstArr).getClass().getComponentType(); if (! dstElemType.isAssignableFrom(srcElemType)) throw new System.ArrayTypeMismatchException(); bool isValueType = system.RuntimeType.IsValueClass(srcElemType); if (isValueType != system.RuntimeType.IsValueClass(dstElemType)) throw new System.ArrayTypeMismatchException(); if (isValueType) { ValueType srcObj, dstObj; if ( object.ReferenceEquals(srcArr, dstArr) && dstIndex > srcIndex && dstIndex < srcIndex + length) { // copy backwards to prevent smearing while (length-- > 0) { srcObj = (ValueType) java.lang.reflect.Array.get(srcArr, srcIndex + length); dstObj = (ValueType) java.lang.reflect.Array.get(dstArr, dstIndex + length); ((ValueMethod) ((ValueType) srcObj)).CopyTo((ValueType) dstObj); } } else { for (int idx = 0; idx < length; idx++) { srcObj = (ValueType) java.lang.reflect.Array.get(srcArr, srcIndex + idx); dstObj = (ValueType) java.lang.reflect.Array.get(dstArr, dstIndex + idx); ((ValueMethod) ((ValueType) srcObj)).CopyTo((ValueType) dstObj); } } } else { // for an array of primitives or references, use built-in arraycopy java.lang.System.arraycopy(srcArr, srcIndex, dstArr, dstIndex, length); } } // // System.Array methods // public static ReadOnlyCollection AsReadOnly(T[] array) { ThrowIfNull(array); return new ReadOnlyCollection(array); } public int Rank => jagged ? 1 : rank; // // GetLength, GetLongLength, GetLowerBound, GetUpperBound // public int GetLength(int dimension) { if (dimension < 0 || dimension >= Rank) throw new System.IndexOutOfRangeException(); if (dimension == 0) return len; object sub = arr; for (int i = 0; i < dimension; i++) sub = java.lang.reflect.Array.get(sub, 0); return java.lang.reflect.Array.getLength(sub); } public long GetLongLength(int dimension) => GetLength(dimension); public int GetLowerBound(int dimension) => 0; public int GetUpperBound(int dimension) => GetLength(dimension) - 1; // // GetValue (integer) // public object GetValue(int index) => Load(arr, index); public object GetValue(int index1, int index2) { if (Rank != 2) throw new System.ArgumentException(); var sub = java.lang.reflect.Array.get(arr, index1); return Load(sub, index2); } public object GetValue(int index1, int index2, int index3) { if (Rank != 3) throw new System.ArgumentException(); var sub = java.lang.reflect.Array.get(arr, index1); sub = java.lang.reflect.Array.get(sub, index2); return Load(sub, index3); } public object GetValue(params int[] indices) { ThrowIfNull(indices); int n = indices.Length; if (Rank != n--) throw new System.ArgumentException(); object sub = arr; for (int i = 0; i < n; i++) sub = java.lang.reflect.Array.get(sub, indices[i]); return Load(sub, indices[n]); } // // GetValue (long) // public object GetValue(long index) { var intIndex = (int) index; if (intIndex != index) throw new System.ArgumentOutOfRangeException(); return GetValue(intIndex); } public object GetValue(long index1, long index2) { int intIndex1 = (int) index1; int intIndex2 = (int) index2; if (intIndex1 != index1 || intIndex2 != index2) throw new System.ArgumentOutOfRangeException(); return GetValue(intIndex1, intIndex2); } public object GetValue(long index1, long index2, long index3) { int intIndex1 = (int) index1; int intIndex2 = (int) index2; int intIndex3 = (int) index3; if (intIndex1 != index1 || intIndex2 != index2 || intIndex3 != index3) throw new System.ArgumentOutOfRangeException(); return GetValue(intIndex1, intIndex2, intIndex3); } public object GetValue(params long[] indices) { int[] intIndices = null; if (indices != null) { int n = indices.Length; intIndices = new int[n]; for (int i = 0; i < n; i++) { long longIndex = indices[i]; int intIndex = (int) longIndex; if (intIndex != longIndex) throw new System.ArgumentOutOfRangeException(); intIndices[i] = intIndex; } } return GetValue(intIndices); } // // SetValue (integer) // public void SetValue(object value, int index) => Store(arr, index, value); public void SetValue(object value, int index1, int index2) { if (Rank != 2) throw new System.ArgumentException(); var sub = java.lang.reflect.Array.get(arr, index1); Store(sub, index2, value); } public void SetValue(object value, int index1, int index2, int index3) { if (Rank != 3) throw new System.ArgumentException(); var sub = java.lang.reflect.Array.get(arr, index1); sub = java.lang.reflect.Array.get(sub, index2); Store(sub, index3, value); } public void SetValue(object value, params int[] indices) { ThrowIfNull(indices); int n = indices.Length; if (Rank != n--) throw new System.ArgumentException(); object sub = arr; for (int i = 0; i < n; i++) sub = java.lang.reflect.Array.get(sub, indices[i]); Store(sub, indices[n], value); } public void SetValue(object value, long index) { var intIndex = (int) index; if (intIndex != index) throw new System.ArgumentOutOfRangeException(); SetValue(value, intIndex); } public void SetValue(object value, long index1, long index2) { int intIndex1 = (int) index1; int intIndex2 = (int) index2; if (intIndex1 != index1 || intIndex2 != index2) throw new System.ArgumentOutOfRangeException(); SetValue(value, intIndex1, intIndex2); } public void SetValue(object value, long index1, long index2, long index3) { int intIndex1 = (int) index1; int intIndex2 = (int) index2; int intIndex3 = (int) index3; if (intIndex1 != index1 || intIndex2 != index2 || intIndex3 != index3) throw new System.ArgumentOutOfRangeException(); SetValue(value, intIndex1, intIndex2, intIndex3); } public void SetValue(object value, params long[] indices) { int[] intIndices = null; if (indices != null) { int n = indices.Length; intIndices = new int[n]; for (int i = 0; i < n; i++) { long longIndex = indices[i]; int intIndex = (int) longIndex; if (intIndex != longIndex) throw new System.ArgumentOutOfRangeException(); intIndices[i] = intIndex; } } SetValue(value, intIndices); } // // IndexOf // public static int IndexOf(Array array, object value, int startIndex, int count) { ThrowIfNull(array); if (array.Rank != 1) throw new System.RankException(); if (startIndex < 0 || startIndex > array.len) throw new System.ArgumentOutOfRangeException(); if (count < 0 || count > array.len - startIndex) throw new System.ArgumentOutOfRangeException(); int endIndex = startIndex + count; switch (array.arr) { case bool[] boolArray: var boolValue = (bool) value; for (; startIndex < endIndex; startIndex++) if (boolArray[startIndex] == boolValue) return startIndex; break; case sbyte[] byteArray: var byteValue = (sbyte) value; for (; startIndex < endIndex; startIndex++) if (byteArray[startIndex] == byteValue) return startIndex; break; case char[] charArray: var charValue = (char) value; for (; startIndex < endIndex; startIndex++) if (charArray[startIndex] == charValue) return startIndex; break; case short[] shortArray: var shortValue = (short) value; for (; startIndex < endIndex; startIndex++) if (shortArray[startIndex] == shortValue) return startIndex; break; case int[] intArray: var intValue = (int) value; for (; startIndex < endIndex; startIndex++) if (intArray[startIndex] == intValue) return startIndex; break; case long[] longArray: var longValue = (long) value; for (; startIndex < endIndex; startIndex++) if (longArray[startIndex] == longValue) return startIndex; break; case float[] floatArray: var floatValue = (float) value; for (; startIndex < endIndex; startIndex++) if (floatArray[startIndex] == floatValue) return startIndex; break; case double[] doubleArray: var doubleValue = (double) value; for (; startIndex < endIndex; startIndex++) if (doubleArray[startIndex] == doubleValue) return startIndex; break; case object[] objectArray: if (value == null) { for (; startIndex < endIndex; startIndex++) if (objectArray[startIndex] == null) return startIndex; } else { for (; startIndex < endIndex; startIndex++) { var objectAtIndex = objectArray[startIndex]; if (objectAtIndex != null && objectAtIndex.Equals(value)) return startIndex; } } break; default: throw new System.InvalidOperationException(); } return -1; } public static int IndexOf(Array array, object value, int startIndex) { ThrowIfNull(array); return IndexOf(array, value, startIndex, array.len - startIndex); } public static int IndexOf(Array array, object value) => IndexOf(array, value, 0); public static int IndexOf(T[] array, T value) => IndexOf((Array) (object) array, (object) value, 0); public static int IndexOf(T[] array, T value, int startIndex) => IndexOf((Array) (object) array, (object) value, startIndex); public static int IndexOf(T[] array, T value, int startIndex, int count) => IndexOf((Array) (object) array, (object) value, startIndex, count); // // IndexOf // public static int LastIndexOf(Array array, object value, int startIndex, int count) { ThrowIfNull(array); if (array.Rank != 1) throw new System.RankException(); if (startIndex < 0 || startIndex > array.len) throw new System.ArgumentOutOfRangeException(); if (count < 0 || count > array.len - startIndex) throw new System.ArgumentOutOfRangeException(); int endIndex = startIndex + count; switch (array.arr) { case bool[] boolArray: var boolValue = (bool) value; while (endIndex-- > startIndex) if (boolArray[endIndex] == boolValue) return endIndex; break; case sbyte[] byteArray: var byteValue = (sbyte) value; while (endIndex-- > startIndex) if (byteArray[endIndex] == byteValue) return endIndex; break; case char[] charArray: var charValue = (char) value; while (endIndex-- > startIndex) if (charArray[endIndex] == charValue) return endIndex; break; case short[] shortArray: var shortValue = (short) value; while (endIndex-- > startIndex) if (shortArray[endIndex] == shortValue) return endIndex; break; case int[] intArray: var intValue = (int) value; while (endIndex-- > startIndex) if (intArray[endIndex] == intValue) return endIndex; break; case long[] longArray: var longValue = (long) value; while (endIndex-- > startIndex) if (longArray[endIndex] == longValue) return endIndex; break; case float[] floatArray: var floatValue = (float) value; while (endIndex-- > startIndex) if (floatArray[endIndex] == floatValue) return endIndex; break; case double[] doubleArray: var doubleValue = (double) value; while (endIndex-- > startIndex) if (doubleArray[endIndex] == doubleValue) return endIndex; break; case object[] objectArray: if (value == null) { while (endIndex-- > startIndex) if (objectArray[endIndex] == null) return endIndex; } else { while (endIndex-- > startIndex) { var objectAtIndex = objectArray[endIndex]; if (objectAtIndex != null && objectAtIndex.Equals(value)) return endIndex; } } break; default: throw new System.InvalidOperationException(); } return -1; } public static int LastIndexOf(Array array, object value, int startIndex) { ThrowIfNull(array); return LastIndexOf(array, value, startIndex, array.len - startIndex); } public static int LastIndexOf(Array array, object value) => LastIndexOf(array, value, 0); public static int LastIndexOf(T[] array, T value) => LastIndexOf((Array) (object) array, (object) value, 0); public static int LastIndexOf(T[] array, T value, int startIndex) => LastIndexOf((Array) (object) array, (object) value, startIndex); public static int LastIndexOf(T[] array, T value, int startIndex, int count) => LastIndexOf((Array) (object) array, (object) value, startIndex, count); // // Sort (non-generic) // public static void Sort(Array array) => SortCommon(array, array, 0, -1, false, null); public static void Sort(Array array, system.collections.IComparer comparer) => SortCommon(array, array, 0, -1, false, comparer); public static void Sort(Array array, int index, int length) => SortCommon(array, array, index, length, true, null); public static void Sort(Array array, int index, int length, system.collections.IComparer comparer) => SortCommon(array, array, index, length, true, comparer); public static void Sort(Array keys, Array items) => SortCommon(keys, items, 0, -1, false, null); public static void Sort(Array keys, Array items, system.collections.IComparer comparer) => SortCommon(keys, items, 0, -1, false, comparer); public static void Sort(Array keys, Array items, int index, int length) => SortCommon(keys, items, index, length, true, null); public static void Sort(Array keys, Array items, int index, int length, system.collections.IComparer comparer) => SortCommon(keys, items, index, length, true, comparer); // // Sort (generic) // public static void Sort(T[] array) => SortGeneric(array, array, 0, -1, false, null); public static void Sort(T[] array, IComparer comparer) => SortGeneric(array, array, 0, -1, false, comparer); public static void Sort(T[] array, int index, int length) => SortGeneric(array, array, index, length, true, null); public static void Sort(T[] array, int index, int length, IComparer comparer) => SortGeneric(array, array, index, length, true, comparer); public static void Sort(TKey[] keys, TValue[] items) => SortGeneric(keys, items, 0, -1, false, null); public static void Sort(TKey[] keys, TValue[] items, IComparer comparer) => SortGeneric(keys, items, 0, -1, false, comparer); public static void Sort(TKey[] keys, TValue[] items, int index, int length) => SortGeneric(keys, items, index, length, true, null); public static void Sort(TKey[] keys, TValue[] items, int index, int length, IComparer comparer) => SortGeneric(keys, items, index, length, true, comparer); private static void SortGeneric(object keys_, object items_, int index, int length, bool haveLength, IComparer comparer) { ThrowIfNull(keys_); var keys = GetProxy(keys_); Array items; if (object.ReferenceEquals(keys_, items_)) items = keys; else { ThrowIfNull(items_); items = GetProxy(items_); } SortCommon(keys, items, index, length, haveLength, new system.collections.GenericComparerProxy(comparer)); } // // Sort (common method) // private static void SortCommon(Array keys, Array items, int index, int length, bool haveLength, java.util.Comparator comparer) { ThrowIfNull(keys); if (! object.ReferenceEquals(keys, items)) // sorting different arrays throw new System.PlatformNotSupportedException(); // not yet supported if (keys.rank != 1) throw new System.RankException(); int endIndex; if (index < 0) throw new System.ArgumentOutOfRangeException(); if (haveLength) { if (length < 0) throw new System.ArgumentOutOfRangeException(); if (keys.len - index < length) throw new System.ArgumentException(); endIndex = index + length; } else { endIndex = keys.len; if (index >= endIndex) throw new System.ArgumentException(); length = endIndex - index; } if (length <= 1) return; if (comparer == null) { switch (keys.arr) { case sbyte[] byteArray: java.util.Arrays.sort(byteArray, index, endIndex); return; case char[] charArray: java.util.Arrays.sort(charArray, index, endIndex); return; case short[] shortArray: java.util.Arrays.sort(shortArray, index, endIndex); return; case int[] intArray: java.util.Arrays.sort(intArray, index, endIndex); return; case long[] longArray: java.util.Arrays.sort(longArray, index, endIndex); return; case float[] floatArray: java.util.Arrays.sort(floatArray, index, endIndex); return; case double[] doubleArray: java.util.Arrays.sort(doubleArray, index, endIndex); return; case object[] objectArray: java.util.Arrays.sort(objectArray, index, endIndex); return; } } else { var objectArray = keys.arr as object[]; if (objectArray == null) { // sorting a primitive array using a comparer, not yet supported throw new System.PlatformNotSupportedException(); } java.util.Arrays.sort(objectArray, index, endIndex, comparer); } } /*public static void Sort(T[] array, Comparison comparison)*/ // // BinarySearch // public static int BinarySearch(Array array, object value) { ThrowIfNull(array); return BinarySearch(array, 0, array.len, value, null); } public static int BinarySearch(Array array, int index, int length, object value) => BinarySearch(array, index, length, value, null); public static int BinarySearch(Array array, object value, System.Collections.IComparer comparer) { ThrowIfNull(array); return BinarySearch(array, 0, array.len, value, comparer); } public static int BinarySearch(Array array, int index, int length, object value, System.Collections.IComparer comparer) { ThrowIfNull(array); if (index < 0 || length < 0) throw new System.ArgumentOutOfRangeException(); if (array.len - index < length) throw new System.ArgumentException(); if (array.rank != 1) throw new System.RankException(); /*not supported if (comparer == null || comparer == System.Collections.Comparer.Default) { }*/ throw new System.PlatformNotSupportedException(); } public static int BinarySearch(T[] array, T value) => BinarySearch(array, value); public static int BinarySearch(T[] array, T value, System.Collections.Generic.IComparer comparer) { throw new System.PlatformNotSupportedException(); } public static int BinarySearch(T[] array, int index, int length, T value) { throw new System.PlatformNotSupportedException(); } public static int BinarySearch(T[] array, int index, int length, T value, System.Collections.Generic.IComparer comparer) { throw new System.PlatformNotSupportedException(); } // // Clear // public static void Clear(Array array, int index, int length) { ThrowIfNull(array); if (index < 0 || length < 0) throw new System.IndexOutOfRangeException(); var endIndex = index + length; if (endIndex > array.len) throw new System.IndexOutOfRangeException(); switch (array.arr) { case bool[] boolArray: java.util.Arrays.fill(boolArray, index, endIndex, false); break; case sbyte[] byteArray: java.util.Arrays.fill(byteArray, index, endIndex, (sbyte) 0); break; case char[] charArray: java.util.Arrays.fill(charArray, index, endIndex, (char) 0); break; case short[] shortArray: java.util.Arrays.fill(shortArray, index, endIndex, (short) 0); break; case int[] intArray: java.util.Arrays.fill(intArray, index, endIndex, (int) 0); break; case long[] longArray: java.util.Arrays.fill(longArray, index, endIndex, (long) 0); break; case float[] floatArray: java.util.Arrays.fill(floatArray, index, endIndex, (float) 0); break; case double[] doubleArray: java.util.Arrays.fill(doubleArray, index, endIndex, (double) 0); break; case object[] objectArray: if (system.RuntimeType.IsValueClass( ((java.lang.Object) (object) objectArray) .getClass().getComponentType())) { for (; length-- > 0; index++) ((ValueMethod) (ValueType) objectArray[index]).Clear(); } else { java.util.Arrays.fill(objectArray, index, endIndex, null); } break; default: throw new System.InvalidOperationException(); } } // // Fill // public static void Fill(T[] array, T value) { ThrowIfNull(array); FillCommon(array, (object) value, 0, java.lang.reflect.Array.getLength(array)); } public static void Fill(T[] array, T value, int startIndex, int count) { ThrowIfNull(array); if (startIndex < 0 || count < 0) throw new System.IndexOutOfRangeException(); var endIndex = startIndex + count; if (endIndex > java.lang.reflect.Array.getLength(array)) throw new System.IndexOutOfRangeException(); FillCommon(array, (object) value, startIndex, endIndex); } private static void FillCommon(object array, object value, int startIndex, int endIndex) { switch (array) { case bool[] boolArray: java.util.Arrays.fill(boolArray, startIndex, endIndex, (bool) value); break; case sbyte[] byteArray: java.util.Arrays.fill(byteArray, startIndex, endIndex, (sbyte) value); break; case char[] charArray: java.util.Arrays.fill(charArray, startIndex, endIndex, (char) value); break; case short[] shortArray: java.util.Arrays.fill(shortArray, startIndex, endIndex, (short) value); break; case int[] intArray: java.util.Arrays.fill(intArray, startIndex, endIndex, (int) value); break; case long[] longArray: java.util.Arrays.fill(longArray, startIndex, endIndex, (long) value); break; case float[] floatArray: java.util.Arrays.fill(floatArray, startIndex, endIndex, (float) value); break; case double[] doubleArray: java.util.Arrays.fill(doubleArray, startIndex, endIndex, (double) value); break; case object[] objectArray: if (system.RuntimeType.IsValueClass( ((java.lang.Object) array).getClass().getComponentType())) { ValueType v = (ValueType) value; for (; startIndex < endIndex; startIndex++) ((ValueMethod) v).CopyTo((ValueType) objectArray[startIndex]); } else { java.util.Arrays.fill(objectArray, startIndex, endIndex, value); } break; default: throw new System.InvalidOperationException(); } } // // Initialize // public void Initialize() { var type = ((java.lang.Object) arr).getClass().getComponentType(); if (system.RuntimeType.IsValueClass(type)) { var objectArray = (object[]) arr; for (int idx = 0; idx < len; idx++) ((ValueMethod) (ValueType) objectArray[idx]).Clear(); } } /*public static bool TrueForAll(T[] array, Predicate match) public static void Reverse(Array array) public static void Reverse(Array array, int index, int length) public static void Resize (ref T[] array, int newSize) public static void ForEach (T[] array, Action action); public static bool Exists (T[] array, Predicate match); public static T[] Empty (); public static TOutput[] ConvertAll (TInput[] array, Converter converter); //LastIndexOf, Find, FindAll, FindIndex, FindLast, CreateInstance*/ // // IList interface // bool IList.Contains(object value) => IndexOf(this, value, 0, len) >= 0; int IList.IndexOf(object value) => IndexOf(this, value); void IList.Clear() => Clear(this, 0, len); // Array does not support addition and removal int IList.Add(object value) => throw new System.NotSupportedException(); void IList.Insert(int index, object value) => throw new System.NotSupportedException(); void IList.Remove(object value) => throw new System.NotSupportedException(); void IList.RemoveAt(int index) => throw new System.NotSupportedException(); object IList.this[int index] { get => Load(arr, index); set => SetValue(value, index); } public bool IsReadOnly => false; public bool IsFixedSize => true; public bool IsSynchronized => false; public object SyncRoot => arr; // // IStructuralComparable, IStructuralEquatable // int IStructuralComparable.CompareTo(object other, IComparer comparer) { if (other == null) return 1; Array otherArray = other as Array; if (otherArray == null || len != otherArray.len) throw new System.ArgumentException(); for (int i = 0; i < len; i++) { var c = comparer.Compare(Load(arr, i), Load(otherArray.arr, i)); if (c != 0) return c; } return 0; } bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { if (other == null) return false; if (object.ReferenceEquals(this, other)) return true; Array otherArray = other as Array; if (otherArray == null || len != otherArray.len) return false; for (int i = 0; i < len; i++) { if (! comparer.Equals(Load(arr, i), Load(otherArray.arr, i))) return false; } return true; } int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { ThrowIfNull(comparer); int hash = 0; for (int i = (len >= 8 ? len - 8 : 0); i < len; i++) { // same calculation as in reference implementation of System.Array hash = ((hash << 5) + hash) ^ (comparer.GetHashCode(Load(arr, i))); } return hash; } // // Helper methods for array initialization and access // public static object New(int count, System.Type type) { var runtimeType = (system.RuntimeType) type; var cls = runtimeType.JavaClassForArray(); var array = java.lang.reflect.Array.newInstance(cls, count); if (cls.getComponentType() != null) MarkJagged(array); else if (system.RuntimeType.IsValueClass(cls)) { Initialize(array, runtimeType, (system.ValueType) runtimeType.CallConstructor(true), 1); } return array; } public static void Initialize(object array, System.Type type, system.ValueType model, int dims) { if (model == null) model = (system.ValueType) (((system.RuntimeType) type).CallConstructor(true)); if (dims == 1) InitSingle((object[]) array, model); else InitMulti((object[]) array, model, dims); void InitSingle(object[] array, system.ValueType model) { int n = array.Length; if (n > 0) { java.lang.reflect.Array.set(array, 0, model); for (int i = 1; i < n; i++) java.lang.reflect.Array.set(array, i, ((ValueMethod) model).Clone()); } } void InitMulti(object[] array, system.ValueType model, int dims) { int n = array.Length; if (dims == 1 && n > 0) { for (int i = 0; i < n; i++) java.lang.reflect.Array.set(array, i, ((ValueMethod) model).Clone()); } else if (dims > 1) { for (int i = 0; i < n; i++) InitMulti((object[]) array[i], model, dims - 1); } } } public static void Store(object array, int index, object value) { try { switch (array) { case bool[] boolArray: boolArray[index] = ((Boolean) value).Get() != 0 ? true : false; break; case sbyte[] byteArray: byteArray[index] = (sbyte) ((SByte) value).Get(); break; case char[] charArray: charArray[index] = (char) ((Char) value).Get(); break; case short[] shortArray: shortArray[index] = (short) ((Int16) value).Get(); break; case int[] intArray: intArray[index] = (int) ((Int32) value).Get(); break; case long[] longArray: longArray[index] = (long) ((Int64) value).Get(); break; case float[] floatArray: floatArray[index] = (float) ((Single) value).Get(); break; case double[] doubleArray: doubleArray[index] = (double) ((Double) value).Get(); break; case ValueType[] valueArray: // this will throw invalid cast if the types do not match. // but note that it will succeed with generic instance types // even when the type arguments do not match. ((ValueMethod) (ValueType) value).CopyTo(valueArray[index]); break; case object[] objectArray: // note that if a value type is being stored, we assume // that it was already boxed, and we don't clone it here if (value is system.Reference valueRef) value = valueRef.Get(); objectArray[index] = value; break; } } catch (System.Exception exc) { throw new System.ArrayTypeMismatchException("", exc); } } public static object Load(object array, int index) { // if array of a primitive type, returns a boxed copy of array[index]. // if array of a value type or reference type, returns array[index]. switch (array) { case bool[] boolArray: return Boolean.Box(boolArray[index] ? 1 : 0); case sbyte[] byteArray: return SByte.Box(byteArray[index]); case char[] charArray: return Char.Box(charArray[index]); case short[] shortArray: return Int16.Box(shortArray[index]); case int[] intArray: return Int32.Box(intArray[index]); case long[] longArray: return Int64.Box(longArray[index]); case float[] floatArray: return Single.Box(floatArray[index]); case double[] doubleArray: return Double.Box(doubleArray[index]); case object[] objectArray: return objectArray[index]; } throw new System.IndexOutOfRangeException(); } public static ValueType Box(object array, int index) { // called from CodeArrays::Address(), // array parameter is always a single-dim array // returns a boxed reference into an array switch (array) { case bool[] boolArray: return Boolean.Box(boolArray, index); case sbyte[] byteArray: return SByte.Box(byteArray, index); case char[] charArray: return Char.Box(charArray, index); case short[] shortArray: return Int16.Box(shortArray, index); case int[] intArray: return Int32.Box(intArray, index); case long[] longArray: return Int64.Box(longArray, index); case float[] floatArray: return Single.Box(floatArray, index); case double[] doubleArray: return Double.Box(doubleArray, index); case ValueType[] valueArray: return valueArray[index]; case object[] objectArray: return Reference.Box(objectArray, index); } throw new System.IndexOutOfRangeException(); } // // CheckCast // public static object CheckCast(object array, java.lang.Class castToClass, bool @throw) { if (array is object[]) { var elemClass = ((java.lang.Object) array).getClass().getComponentType(); if (elemClass != null) { if (system.RuntimeType.IsValueClass(elemClass)) { if (elemClass == castToClass) return array; } else if (castToClass.isAssignableFrom(elemClass)) return array; } } if (array != null && @throw) { GenericType.ThrowInvalidCastException(array, RuntimeType.GetType(castToClass).MakeArrayType()); } return null; } public static object CheckCast(object array, System.Type castToType, bool @throw) { if (array != null) { if (array is system.Array.ProxySyncRoot proxyArray) array = proxyArray.SyncRoot; var elemClass = ((java.lang.Object) array).getClass().getComponentType(); if (elemClass != null) { var elemType = RuntimeType.GetType(elemClass); if (system.RuntimeType.IsValueClass(elemClass)) { if (object.ReferenceEquals(elemType, castToType)) return array; } else if (elemClass.isPrimitive()) { var castToClass = ((RuntimeType) castToType).JavaClassForArray(); if (castToClass == elemClass) return array; } else { if (castToType.IsAssignableFrom(elemType)) return array; } } if (@throw) GenericType.ThrowInvalidCastException(array, castToType.MakeArrayType()); } return null; } // // IEnumerator // public IEnumerator GetEnumerator() => new Enumerator(arr, len, Rank); [System.Serializable] public class Enumerator : IEnumerator, System.ICloneable { [java.attr.RetainType] private object arr; [java.attr.RetainType] private int len; [java.attr.RetainType] private int rank; [java.attr.RetainType] private int idx; [java.attr.RetainType] private Enumerator sub; public Enumerator(object _arr, int _len, int _rank) { arr = _arr; len = _len; rank = _rank; idx = -1; } public bool MoveNext() { for (;;) { if (sub != null) { if (sub.MoveNext()) return true; sub = null; } int next = idx + 1; if (next >= len) return false; idx = next; if (rank > 1) { var subArr = java.lang.reflect.Array.get(arr, idx); sub = new Enumerator(subArr, java.lang.reflect.Array.getLength(subArr), rank - 1); continue; } return true; } } public object Current { get { if (sub != null) return sub.Current; if (idx < 0) throw new System.InvalidOperationException(); if (idx >= len) throw new System.InvalidOperationException(); return Load(arr, idx); } } public void Reset() { idx = -1; if (sub != null) sub = null; } public object Clone() => MemberwiseClone(); } // // GetProxy // public static object GetProxy(object obj, System.Type castToType, bool callCast) { var objClass = ((java.lang.Object) obj).getClass(); if (objClass.isArray()) { int ok = 0; // check if asking to cast the object to System.Array or one of // the non-generic interfaces that an array should implement if ( object.ReferenceEquals(castToType, cachedArrayType) || object.ReferenceEquals(castToType, cachedICloneable) || object.ReferenceEquals(castToType, cachedPlainIEnumerable) || object.ReferenceEquals(castToType, cachedPlainICollection) || object.ReferenceEquals(castToType, cachedPlainIList) || object.ReferenceEquals(castToType, cachedIStructuralComparable) || object.ReferenceEquals(castToType, cachedIStructuralEquatable)) { ok = 1; // non-generic } else if (castToType.IsConstructedGenericType) { // otherwise check if asking to cast the object to one of the // generic interfaces that an array should implement. later on, // the call to IGenericObject.TryCast() verifies the actual // generic parameters types (see the check for ok == 2, below). var genericDef = castToType.GetGenericTypeDefinition(); if ( object.ReferenceEquals(genericDef, cachedGenericIEnumerable) || object.ReferenceEquals(genericDef, cachedGenericICollection) || object.ReferenceEquals(genericDef, cachedGenericIList) || object.ReferenceEquals(genericDef, cachedGenericIReadOnlyCollection) || object.ReferenceEquals(genericDef, cachedGenericIReadOnlyList)) { ok = 2; // generic } } if (ok != 0) { var proxy = ArrayProxyCache.GetOrAdd(obj, null); if (object.ReferenceEquals(proxy, null)) { // create the Array.Proxy object, where T is the array element. // note that we use reflection to call the constructor, which takes // one additional hidden parameter for the generic type. var newProxyObject = ProxyConstructor.newInstance(new object[] { obj, GetArrayElementType(obj, objClass) }); proxy = ArrayProxyCache.GetOrAdd(obj, newProxyObject); } if (ok == 2) { // if we are getting a proxy for a generic interface, we must now // make sure the proxy object supports the specific generic type. var genericProxy = ((IGenericObject) proxy).TryCast(castToType); if (callCast) proxy = genericProxy; else if (genericProxy == null) proxy = null; } return proxy; } } else if (objClass == (java.lang.Class) typeof(java.lang.String)) { // string can be cast to system.collections.IEnumerable, // system.ICloneable, and, specifically in this implementation, // also to system.Array (see CodeCall::ShouldCastArrayArgument // and CodeArrays::MaybeGetProxy methods) if ( object.ReferenceEquals(castToType, cachedArrayType) || object.ReferenceEquals(castToType, cachedICloneable) || object.ReferenceEquals(castToType, cachedPlainIEnumerable) || object.ReferenceEquals(castToType, cachedGenericIEnumerable)) { return GetProxy( ((java.lang.String) obj).toCharArray(), castToType, callCast); } if (castToType.IsConstructedGenericType) { // castable to system.collections.generic.IEnumerable var genericDef = castToType.GetGenericTypeDefinition(); if (object.ReferenceEquals(genericDef, cachedGenericIEnumerable)) { return GetProxy( ((java.lang.String) obj).toCharArray(), castToType, callCast); } } return String.CreateWrapper(obj, castToType); } return null; } public static Array GetProxy(object obj) { var proxy = GetProxy(obj, cachedArrayType, false); if (proxy == null) GenericType.ThrowInvalidCastException(obj, cachedArrayType); // because 'proxy' is of type 'object', casting it to directly to // System.Array would generate code that calls GetProxy (see also // CodeCall.Translate_Return and GenericUtil.ShouldCallGenericCast), // we avoid this by casting it first to ProxySyncRoot return (Array) (Array.ProxySyncRoot) proxy; } private static System.Type GetArrayElementType( object arrayObject, java.lang.Class arrayClass) { // an array object does not keep generic type information // for its component, so a Tuple[] array becomes // just Tuple$$2[]. casting to IEnumerable> // would fail. below, we try to extract the concrete generic // type from the first element in the array. // // first, check if the array component is a non-concrete // generic type, and that the array has at least one element. var elementType = system.RuntimeType.GetType( arrayClass.getComponentType()); if ( elementType.IsGenericTypeDefinition && java.lang.reflect.Array.getLength(arrayObject) > 0) { // extract the first element, and make sure it is the same // class as the array (so same number of generic argument) var element0 = java.lang.reflect.Array.get(arrayObject, 0); if ( (! object.ReferenceEquals(element0, null)) && element0.GetType() is RuntimeType element0Type && ((RuntimeType) elementType).JavaClassForArray() == element0Type.JavaClassForArray()) { // return a concrete generic type elementType = elementType.MakeGenericType( element0Type.GetGenericArguments()); } } return elementType; } public static void MarkJagged(object obj) { ((Array) GetProxy(obj, cachedArrayType, false)).jagged = true; } [java.attr.RetainType] private static readonly System.Type cachedArrayType = system.RuntimeType.GetType((java.lang.Class) typeof(System.Array)); [java.attr.RetainType] private static readonly System.Type cachedICloneable = system.RuntimeType.GetType((java.lang.Class) typeof(System.ICloneable)); [java.attr.RetainType] private static System.Type cachedPlainIEnumerable = system.RuntimeType.GetType((java.lang.Class) typeof(System.Collections.IEnumerable)); [java.attr.RetainType] private static System.Type cachedPlainICollection = system.RuntimeType.GetType((java.lang.Class) typeof(System.Collections.ICollection)); [java.attr.RetainType] private static System.Type cachedPlainIList = system.RuntimeType.GetType((java.lang.Class) typeof(System.Collections.IList)); [java.attr.RetainType] private static System.Type cachedIStructuralComparable = system.RuntimeType.GetType((java.lang.Class) typeof(System.Collections.IStructuralComparable)); [java.attr.RetainType] private static System.Type cachedIStructuralEquatable = system.RuntimeType.GetType((java.lang.Class) typeof(System.Collections.IStructuralEquatable)); [java.attr.RetainType] private static System.Type cachedGenericIEnumerable = system.RuntimeType.GetType((java.lang.Class) typeof(System.Collections.Generic.IEnumerable<>)); [java.attr.RetainType] private static System.Type cachedGenericICollection = system.RuntimeType.GetType((java.lang.Class) typeof(System.Collections.Generic.ICollection<>)); [java.attr.RetainType] private static System.Type cachedGenericIList = system.RuntimeType.GetType((java.lang.Class) typeof(System.Collections.Generic.IList<>)); [java.attr.RetainType] private static System.Type cachedGenericIReadOnlyCollection = system.RuntimeType.GetType((java.lang.Class) typeof(System.Collections.Generic.IReadOnlyCollection<>)); [java.attr.RetainType] private static System.Type cachedGenericIReadOnlyList = system.RuntimeType.GetType((java.lang.Class) typeof(System.Collections.Generic.IReadOnlyList<>)); #pragma warning disable 0436 [java.attr.RetainType] private static readonly java.lang.reflect.Constructor ProxyConstructor = (java.lang.reflect.Constructor) (object) (((java.lang.Class) typeof(Array.Proxy<>)).getDeclaredConstructors())[0]; #pragma warning restore 0436 [java.attr.RetainType] private static readonly system.runtime.compilerservices.ConditionalWeakTable ArrayProxyCache = new system.runtime.compilerservices.ConditionalWeakTable(); public interface ProxySyncRoot { // this interface is used by system.threading.Monitor to identify // an array proxy object, and get a reference to the actual array object SyncRoot { get; } } public sealed class Proxy : Array, IList, IReadOnlyList, ProxySyncRoot { public Proxy(object _arr) : base(_arr) {} IEnumerator IEnumerable.GetEnumerator() => new GenericEnumerator(arr, len, Rank); [System.Serializable] public class GenericEnumerator : system.Array.Enumerator, IEnumerator { public GenericEnumerator(object _arr, int _len, int _rank) : base(_arr, _len, _rank) {} T IEnumerator.Current => (T) base.Current; void System.IDisposable.Dispose() {} } bool ICollection.Contains(T value) => IndexOf(this, value, 0, len) >= 0; int IList.IndexOf(T value) => IndexOf(this, value); void ICollection.CopyTo(T[] array, int index) { if (Rank != 1) throw new System.ArgumentException(); base.CopyTo(array, index); } // Array does not support addition and removal void ICollection.Add(T value) => throw new System.NotSupportedException("Array"); void ICollection.Clear() => throw new System.NotSupportedException("Array"); bool ICollection.Remove (T value) => throw new System.NotSupportedException("Array"); void IList.Insert(int index, T value) => throw new System.NotSupportedException("Array"); void IList.RemoveAt(int index) => throw new System.NotSupportedException("Array"); public int Count => len; // implements ICollection, IReadOnlyCollection public T this[int index] { // implements IList, IReadOnlyList get => (T) Load(arr, index); set => SetValue(value, index); } } // // static initializer // static Array() { // translate exception java.lang.NegativeArraySizeException // into System.ArgumentOutOfRangeException system.Util.DefineException( (java.lang.Class) typeof(java.lang.NegativeArraySizeException), (exc) => new System.ArgumentOutOfRangeException(exc.getMessage()) ); system.Util.DefineException( (java.lang.Class) typeof(java.lang.IndexOutOfBoundsException), (exc) => new System.IndexOutOfRangeException(exc.getMessage()) ); system.Util.DefineException( (java.lang.Class) typeof(java.lang.NegativeArraySizeException), (exc) => new System.OverflowException( "Array dimensions exceeded supported range.") ); /*system.Util.DefineException( (java.lang.Class) typeof(java.util.ConcurrentModificationException), (exc) => new System.InvalidOperationException(exc.getMessage()) );*/ system.Util.DefineException( (java.lang.Class) typeof(java.lang.ArrayStoreException), (exc) => new System.ArrayTypeMismatchException(exc.getMessage()) ); } } }