216 lines
7.8 KiB
C#
216 lines
7.8 KiB
C#
![]() |
|
||
|
namespace system
|
||
|
{
|
||
|
|
||
|
public struct Span<T>
|
||
|
{
|
||
|
[java.attr.RetainType] private Reference array;
|
||
|
[java.attr.RetainType] private int shift;
|
||
|
[java.attr.RetainType] private int count;
|
||
|
[java.attr.RetainType] private int start;
|
||
|
|
||
|
public static int Shiftof(java.lang.Class cls = null)
|
||
|
{
|
||
|
if (cls == null)
|
||
|
cls = ((system.RuntimeType) typeof(T)).JavaClassForArray();
|
||
|
if (cls.isPrimitive())
|
||
|
{
|
||
|
if (cls == java.lang.Boolean.TYPE || cls == java.lang.Byte.TYPE)
|
||
|
return 0; // size 1, shift of 0
|
||
|
if (cls == java.lang.Character.TYPE || cls == java.lang.Short.TYPE)
|
||
|
return 1; // size 2, shift of 1
|
||
|
if (cls == java.lang.Integer.TYPE || cls == java.lang.Float.TYPE)
|
||
|
return 2; // size 3, shift of 2
|
||
|
if (cls == java.lang.Long.TYPE || cls == java.lang.Double.TYPE)
|
||
|
return 3; // size 4, shift of 3
|
||
|
}
|
||
|
return 4; // dummy size 16 (shift 4) for all non-primitive types
|
||
|
}
|
||
|
|
||
|
public object Array(java.lang.Class cls)
|
||
|
{
|
||
|
var array = this.array.Get();
|
||
|
if (array == null)
|
||
|
{
|
||
|
if (cls == null)
|
||
|
cls = ((system.RuntimeType) typeof(T)).JavaClassForArray();
|
||
|
|
||
|
int shift = this.shift;
|
||
|
if (shift != 0)
|
||
|
shift--;
|
||
|
else
|
||
|
{
|
||
|
shift = Shiftof(cls);
|
||
|
this.shift = shift + 1;
|
||
|
}
|
||
|
|
||
|
count = count >> shift;
|
||
|
this.array.Set(array = java.lang.reflect.Array.newInstance(cls, count));
|
||
|
|
||
|
}
|
||
|
return array;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Helper methods for instructions
|
||
|
//
|
||
|
|
||
|
public static int Sizeof()
|
||
|
{
|
||
|
// this helper method is invoked by code which uses the 'sizeof'
|
||
|
// instruction. see also CodeSpan::Sizeof method.
|
||
|
return 1 << Shiftof();
|
||
|
}
|
||
|
|
||
|
[java.attr.RetainName]
|
||
|
public static Span<object> Localloc(long bytes)
|
||
|
{
|
||
|
// this helper method is invoked by code which uses the 'localloc'
|
||
|
// instruction. see also CodeSpan::Localloc method.
|
||
|
int intBytes = (int) bytes;
|
||
|
if (intBytes != bytes)
|
||
|
throw new System.ArgumentOutOfRangeException();
|
||
|
return new Span<object>() { array = new Reference(), count = intBytes };
|
||
|
}
|
||
|
|
||
|
[java.attr.RetainName]
|
||
|
public static Span<char> String(java.lang.String str)
|
||
|
{
|
||
|
// this helper method is invoked by code which stores a string
|
||
|
// variable into a pointer. see also CodeSpan::Address method.
|
||
|
return new Span<char>(str.toCharArray()) { count = System.SByte.MinValue };
|
||
|
}
|
||
|
|
||
|
[java.attr.RetainName]
|
||
|
public Span<T> Add(long offset, System.Type spanType)
|
||
|
{
|
||
|
var shift = this.shift;
|
||
|
if (shift != 0)
|
||
|
shift--;
|
||
|
else
|
||
|
{
|
||
|
if (spanType == null)
|
||
|
spanType = typeof(T);
|
||
|
shift = Shiftof(((system.RuntimeType) spanType).JavaClassForArray());
|
||
|
this.shift = shift + 1;
|
||
|
}
|
||
|
|
||
|
var span = this;
|
||
|
|
||
|
int shifted_offset = ((int) offset) >> shift;
|
||
|
if ((shifted_offset << shift) != offset)
|
||
|
{
|
||
|
// we require offset to be a multiple of shift
|
||
|
throw new System.InvalidOperationException();
|
||
|
}
|
||
|
span.start = span.start + shifted_offset;
|
||
|
return span;
|
||
|
}
|
||
|
|
||
|
public ValueType Box()
|
||
|
{
|
||
|
// box a span element that is
|
||
|
// - returned as a by-reference result (CodeCall::Translate_Return)
|
||
|
// - assigned to a by-reference variable (CodeLocals::StoreValue)
|
||
|
return system.Array.Box(Array(null), start);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// helper methods to access a span of a primitive type.
|
||
|
// see also CodeSpan::LoadStore method.
|
||
|
//
|
||
|
|
||
|
public bool LoadZ() => ((bool[]) Array(java.lang.Boolean.TYPE))[start];
|
||
|
public void StoreZ(bool value) => ((bool[]) Array(java.lang.Boolean.TYPE))[start] = value;
|
||
|
|
||
|
public sbyte LoadB() => ((sbyte[]) Array(java.lang.Byte.TYPE))[start];
|
||
|
public void StoreB(sbyte value) => ((sbyte[]) Array(java.lang.Byte.TYPE))[start] = value;
|
||
|
|
||
|
public char LoadC() => ((char[]) Array(java.lang.Character.TYPE))[start];
|
||
|
public void StoreC(char value)
|
||
|
{
|
||
|
// disallow writing into a Span<char> created via String() method above
|
||
|
if (count == System.SByte.MinValue)
|
||
|
throw new System.InvalidOperationException();
|
||
|
((char[]) Array(java.lang.Character.TYPE))[start] = value;
|
||
|
}
|
||
|
|
||
|
public short LoadS() => ((short[]) Array(java.lang.Short.TYPE))[start];
|
||
|
public void StoreS(short value) => ((short[]) Array(java.lang.Short.TYPE))[start] = value;
|
||
|
|
||
|
public int LoadI() => ((int[]) Array(java.lang.Integer.TYPE))[start];
|
||
|
public void StoreI(int value) => ((int[]) Array(java.lang.Integer.TYPE))[start] = value;
|
||
|
|
||
|
public long LoadJ() => ((long[]) Array(java.lang.Long.TYPE))[start];
|
||
|
public void StoreJ(int value) => ((long[]) Array(java.lang.Long.TYPE))[start] = value;
|
||
|
|
||
|
public float LoadF() => ((float[]) Array(java.lang.Float.TYPE))[start];
|
||
|
public void StoreF(float value) => ((float[]) Array(java.lang.Float.TYPE))[start] = value;
|
||
|
|
||
|
public double LoadD() => ((double[]) Array(java.lang.Double.TYPE))[start];
|
||
|
public void StoreD(double value) => ((double[]) Array(java.lang.Double.TYPE))[start] = value;
|
||
|
|
||
|
public object Load() => ((object[]) Array((java.lang.Class) typeof(object)))[start];
|
||
|
public void Store(object value) => ((object[]) Array((java.lang.Class) typeof(object)))[start] = value;
|
||
|
|
||
|
//
|
||
|
// System.Span methods
|
||
|
//
|
||
|
|
||
|
[java.attr.RetainName]
|
||
|
public Span(Span<T> fromSpan, int count)
|
||
|
{
|
||
|
int shift = Shiftof();
|
||
|
if ( (! fromSpan.IsEmpty)
|
||
|
|| fromSpan.start != 0
|
||
|
|| fromSpan.count != (1 << shift) * count)
|
||
|
{
|
||
|
// input span should be result of 'localloc' instruction,
|
||
|
// as implemented by the Localloc method above, so the
|
||
|
// span should have a null array a matching byte count
|
||
|
throw new System.InvalidOperationException();
|
||
|
}
|
||
|
this.array = fromSpan.array;
|
||
|
this.array.Set(new T[count]);
|
||
|
this.count = count;
|
||
|
this.shift = shift + 1;
|
||
|
this.start = 0;
|
||
|
}
|
||
|
|
||
|
public Span(T[] array)
|
||
|
{
|
||
|
this.array = Reference.Box(array);
|
||
|
count = (array != null) ? array.Length : 0;
|
||
|
shift = Shiftof() + 1;
|
||
|
start = 0;
|
||
|
}
|
||
|
|
||
|
public Span(T[] array, int start, int length)
|
||
|
{
|
||
|
this.array = Reference.Box(array);
|
||
|
if (array == null)
|
||
|
{
|
||
|
if (start != 0 || length != 0)
|
||
|
throw new System.ArgumentOutOfRangeException();
|
||
|
count = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (start < 0 || length < 0 || (start + length > array.Length))
|
||
|
throw new System.ArgumentOutOfRangeException();
|
||
|
count = length - start;
|
||
|
}
|
||
|
this.shift = Shiftof() + 1;
|
||
|
this.start = 0;
|
||
|
}
|
||
|
|
||
|
public object this[int index] => system.Array.Box(array.Get(), start + index);
|
||
|
|
||
|
public int Length => count;
|
||
|
|
||
|
public bool IsEmpty => array == null || array.Get() == null;
|
||
|
public static Span<T> Empty => new Span<T>();
|
||
|
}
|
||
|
|
||
|
}
|