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; 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(); } // // 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, ICollection.Count // public static void ConstrainedCopy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length) { object copy = null; if (destinationArray != null) copy = Clone(destinationArray.arr, destinationArray.len); try { sourceArray.CopyTo((System.Array) (object) destinationArray, 0); copy = null; } finally { if (copy != null) destinationArray.arr = copy; } } 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) => 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("index"); if (intLength != length) throw new System.ArgumentOutOfRangeException("length"); Copy(sourceArray, intSourceIndex, destinationArray, intDestinationIndex, intLength); } public static void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length) { ThrowIfNull(sourceArray); ThrowIfNull(destinationArray); if (sourceArray.rank != 1 || sourceArray.rank != destinationArray.rank) throw new System.RankException("Rank_MultiDimNotSupported"); if (sourceIndex < 0 || destinationIndex < 0) throw new System.ArgumentOutOfRangeException("index"); if ( sourceIndex + length > sourceArray.len || destinationIndex + length > destinationArray.len) throw new System.ArgumentException("length"); var srcArr = sourceArray.arr; var dstArr = destinationArray.arr; var srcType = ((java.lang.Object) srcArr).getClass().getComponentType(); var dstType = ((java.lang.Object) dstArr).getClass().getComponentType(); if (srcType != dstType) throw new System.ArrayTypeMismatchException(); if (system.RuntimeType.IsValueClass(srcType)) { ValueType srcObj, dstObj; if ( object.ReferenceEquals(srcArr, dstArr) && destinationIndex > sourceIndex && destinationIndex < sourceIndex + length) { // copy backwards to prevent smearing while (length-- > 0) { srcObj = (ValueType) java.lang.reflect.Array.get(srcArr, sourceIndex + length); dstObj = (ValueType) java.lang.reflect.Array.get(dstArr, destinationIndex + length); ((ValueMethod) ((ValueType) srcObj)).CopyTo((ValueType) dstObj); } } else { for (int idx = 0; idx < length; idx++) { srcObj = (ValueType) java.lang.reflect.Array.get(srcArr, sourceIndex + idx); dstObj = (ValueType) java.lang.reflect.Array.get(dstArr, destinationIndex + idx); ((ValueMethod) ((ValueType) srcObj)).CopyTo((ValueType) dstObj); } } } else { // for an array of primitives or references, use built-in arraycopy java.lang.System.arraycopy(srcArr, sourceIndex, dstArr, destinationIndex, length); } } int ICollection.Count => len; // // System.Array methods // public static ReadOnlyCollection AsReadOnly(T[] array) { ThrowIfNull(array); return new ReadOnlyCollection(array); } public int Rank => 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("Rank_MultiDimNotSupported"); if (startIndex < 0 || startIndex > array.len) throw new System.ArgumentOutOfRangeException("startIndex"); if (count < 0 || count > array.len - startIndex) throw new System.ArgumentOutOfRangeException("count"); 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 // public static void Sort(Array array) => Sort(array, (system.collections.IComparer) null); public static void Sort(Array array, int index, int length) => Sort(array, null, index, length, null); public static void Sort(Array array, int index, int length, system.collections.IComparer comparer) => Sort(array, null, index, length, comparer); public static void Sort(Array array, system.collections.IComparer comparer) { ThrowIfNull(array); Sort(array, null, 0, array.len, comparer); } public static void Sort(Array keys, Array items) => Sort(keys, items, 0, 0, null); public static void Sort(Array keys, Array items, int index, int length) => Sort(keys, items, 0, 0, null); public static void Sort(Array keys, Array items, system.collections.IComparer comparer) => Sort(keys, items, 0, 0, null); public static void Sort(Array keys, Array items, int index, int length, system.collections.IComparer 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(); if (index < 0 || length < 0) throw new System.ArgumentOutOfRangeException(); if (keys.len - index < length) throw new System.ArgumentException(); if (length <= 1) return; int endIndex = index + length; 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) public static void Sort(TKey[] keys, TValue[] items) public static void Sort(T[] array, int index, int length) public static void Sort(TKey[] keys, TValue[] items, int index, int length) public static void Sort(T[] array, System.Collections.Generic.IComparer comparer) public static void Sort(TKey[] keys, TValue[] items, System.Collections.Generic.IComparer comparer) public static void Sort(T[] array, int index, int length, System.Collections.Generic.IComparer comparer) public static void Sort(TKey[] keys, TValue[] items, int index, int length, System.Collections.Generic.IComparer 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.ArgumentOutOfRangeException(); if (array.len - index < length) throw new System.ArgumentException(); switch (array.arr) { case bool[] boolArray: for (; length-- > 0; index++) boolArray[index] = default(bool); break; case sbyte[] byteArray: for (; length-- > 0; index++) byteArray[index] = default(sbyte); break; case char[] charArray: for (; length-- > 0; index++) charArray[index] = default(char); break; case short[] shortArray: for (; length-- > 0; index++) shortArray[index] = default(short); break; case int[] intArray: for (; length-- > 0; index++) intArray[index] = default(int); break; case long[] longArray: for (; length-- > 0; index++) longArray[index] = default(long); break; case float[] floatArray: for (; length-- > 0; index++) floatArray[index] = default(float); break; case double[] doubleArray: for (; length-- > 0; index++) doubleArray[index] = default(double); break; case object[] objectArray: if (system.RuntimeType.IsValueClass( ((java.lang.Object) array.arr).getClass().getComponentType())) { for (; length-- > 0; index++) ((ValueMethod) (ValueType) objectArray[index]).Clear(); } else { for (; length-- > 0; index++) objectArray[index] = null; } break; default: throw new System.InvalidOperationException(); } } 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 (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) valueArray[index])).CopyTo((ValueType) value); 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 (system.RuntimeType.IsValueClass(elemClass)) { if (elemClass == castToClass) return array; } else if (castToClass.isAssignableFrom(elemClass)) return array; if (@throw) GenericType.ThrowInvalidCastException(array, RuntimeType.GetType(castToClass).MakeArrayType()); } return null; } public static object CheckCast(object array, System.Type castToType, bool @throw) { if (array is object[]) { var elemClass = ((java.lang.Object) array).getClass().getComponentType(); var elemType = RuntimeType.GetType(elemClass); if (system.RuntimeType.IsValueClass(elemClass)) { if (object.ReferenceEquals(elemType, castToType)) 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 elementType = system.RuntimeType.GetType(objClass.getComponentType()); var newProxyObject = ProxyConstructor.newInstance(new object[] { obj, elementType }); 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; } [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("Rank_MultiDimNotSupported"); 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.util.ConcurrentModificationException), (exc) => new System.InvalidOperationException(exc.getMessage()) ); system.Util.DefineException( (java.lang.Class) typeof(java.lang.ArrayStoreException), (exc) => new System.ArrayTypeMismatchException(exc.getMessage()) ); } } }