1691 lines
66 KiB
C#
1691 lines
66 KiB
C#
|
|
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<T> AsReadOnly<T>(T[] array)
|
|
{
|
|
ThrowIfNull(array);
|
|
return new ReadOnlyCollection<T>(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>(T[] array, T value)
|
|
=> IndexOf((Array) (object) array, (object) value, 0);
|
|
|
|
public static int IndexOf<T>(T[] array, T value, int startIndex)
|
|
=> IndexOf((Array) (object) array, (object) value, startIndex);
|
|
|
|
public static int IndexOf<T>(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>(T[] array, T value)
|
|
=> LastIndexOf((Array) (object) array, (object) value, 0);
|
|
|
|
public static int LastIndexOf<T>(T[] array, T value, int startIndex)
|
|
=> LastIndexOf((Array) (object) array, (object) value, startIndex);
|
|
|
|
public static int LastIndexOf<T>(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>(T[] array)
|
|
=> SortGeneric<T>(array, array, 0, -1, false, null);
|
|
|
|
public static void Sort<T>(T[] array, IComparer<T> comparer)
|
|
=> SortGeneric<T>(array, array, 0, -1, false, comparer);
|
|
|
|
public static void Sort<T>(T[] array, int index, int length)
|
|
=> SortGeneric<T>(array, array, index, length, true, null);
|
|
|
|
public static void Sort<T>(T[] array, int index, int length, IComparer<T> comparer)
|
|
=> SortGeneric<T>(array, array, index, length, true, comparer);
|
|
|
|
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items)
|
|
=> SortGeneric<TKey>(keys, items, 0, -1, false, null);
|
|
|
|
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, IComparer<TKey> comparer)
|
|
=> SortGeneric<TKey>(keys, items, 0, -1, false, comparer);
|
|
|
|
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length)
|
|
=> SortGeneric<TKey>(keys, items, index, length, true, null);
|
|
|
|
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length,
|
|
IComparer<TKey> comparer)
|
|
=> SortGeneric<TKey>(keys, items, index, length, true, comparer);
|
|
|
|
private static void SortGeneric<T>(object keys_, object items_,
|
|
int index, int length,
|
|
bool haveLength,
|
|
IComparer<T> 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<T>(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>(T[] array, Comparison<T> 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>(T[] array, T value) => BinarySearch(array, value);
|
|
|
|
public static int BinarySearch<T>(T[] array, T value,
|
|
System.Collections.Generic.IComparer<T> comparer)
|
|
{
|
|
throw new System.PlatformNotSupportedException();
|
|
}
|
|
|
|
public static int BinarySearch<T>(T[] array, int index, int length, T value)
|
|
{
|
|
throw new System.PlatformNotSupportedException();
|
|
}
|
|
|
|
public static int BinarySearch<T>(T[] array, int index, int length, T value,
|
|
System.Collections.Generic.IComparer<T> 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>(T[] array, T value)
|
|
{
|
|
ThrowIfNull(array);
|
|
FillCommon(array, (object) value, 0, java.lang.reflect.Array.getLength(array));
|
|
}
|
|
|
|
public static void Fill<T>(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>(T[] array, Predicate<T> match)
|
|
public static void Reverse(Array array)
|
|
public static void Reverse(Array array, int index, int length)
|
|
public static void Resize<T> (ref T[] array, int newSize)
|
|
public static void ForEach<T> (T[] array, Action<T> action);
|
|
public static bool Exists<T> (T[] array, Predicate<T> match);
|
|
public static T[] Empty<T> ();
|
|
public static TOutput[] ConvertAll<TInput,TOutput> (TInput[] array, Converter<TInput,TOutput> 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<T> 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<char>
|
|
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<int,string>[] array becomes
|
|
// just Tuple$$2[]. casting to IEnumerable<Tuple<int,string>>
|
|
// 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<T> : Array, IList<T>, IReadOnlyList<T>, ProxySyncRoot
|
|
{
|
|
public Proxy(object _arr) : base(_arr) {}
|
|
|
|
IEnumerator<T> IEnumerable<T>.GetEnumerator() => new GenericEnumerator(arr, len, Rank);
|
|
|
|
[System.Serializable]
|
|
public class GenericEnumerator : system.Array.Enumerator, IEnumerator<T>
|
|
{
|
|
public GenericEnumerator(object _arr, int _len, int _rank) : base(_arr, _len, _rank) {}
|
|
T IEnumerator<T>.Current => (T) base.Current;
|
|
void System.IDisposable.Dispose() {}
|
|
}
|
|
|
|
bool ICollection<T>.Contains(T value) => IndexOf(this, value, 0, len) >= 0;
|
|
int IList<T>.IndexOf(T value) => IndexOf(this, value);
|
|
|
|
void ICollection<T>.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<T>.Add(T value) => throw new System.NotSupportedException("Array");
|
|
void ICollection<T>.Clear() => throw new System.NotSupportedException("Array");
|
|
bool ICollection<T>.Remove (T value) => throw new System.NotSupportedException("Array");
|
|
void IList<T>.Insert(int index, T value) => throw new System.NotSupportedException("Array");
|
|
void IList<T>.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())
|
|
);
|
|
|
|
}
|
|
}
|
|
}
|