86 lines
3.1 KiB
C#
86 lines
3.1 KiB
C#
using Qrakhen.Qamp.Core.Abstractions;
|
|
using Qrakhen.Qamp.Core.Collections;
|
|
using Qrakhen.Qamp.Core.Values;
|
|
using Qrakhen.Qamp.Core.Values.Objects;
|
|
|
|
namespace Qrakhen.Qamp.Core.Execution;
|
|
|
|
using Unsigned = ulong;
|
|
using Signed = long;
|
|
using Char = char;
|
|
using Byte = byte;
|
|
using Bool = bool;
|
|
using Decimal = double;
|
|
|
|
public class Segment(
|
|
IEnumerable<Instruction> instructions,
|
|
IEnumerable<Value> constants) : ISerialize<Segment>
|
|
{
|
|
public readonly FixedArray<Instruction> Instructions = new(instructions);
|
|
public readonly FixedArray<Value> Constants = new(constants);
|
|
|
|
public byte Read(long offset) => Instructions[offset];
|
|
|
|
public byte[] Read(long offset, int length)
|
|
{
|
|
ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + length, Instructions.Length);
|
|
byte[] bytes = new byte[length];
|
|
for (int i = 0; i < length; i++)
|
|
bytes[i] = Instructions[offset + i];
|
|
return bytes;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Although this always returns a long, the actually stored data in the instruction set has a dynamic width
|
|
/// (anything between 1 and 9 bytes, 1 if it's just a byte, and 1 + n, where n is up to 8 bytes).<br/>
|
|
/// If the first byte read is masked with 0x80, it means that this byte represents the amount of bytes that
|
|
/// shall be read. If it is not, the byte is returned directly (for smaller offsets).
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// All of this is done to compress compiled instruction size.
|
|
/// Todo: It will need to be tested wheter the cost on performance is stronger than anticipated.
|
|
/// </remarks>
|
|
public long ReadDynamic(long offset, out int read)
|
|
{
|
|
byte value = Read(offset);
|
|
read = 1;
|
|
if (value < 0x80) // 0x80 flag for length, less than 0x80 means direct read
|
|
return value;
|
|
int length = value ^ 0x80;
|
|
read += length;
|
|
var data = new byte[8];
|
|
for (int i = 0; i < length; i++)
|
|
data[i] = Read(offset + i);
|
|
return data.ToInt64();
|
|
}
|
|
|
|
public short ReadShort(long offset) => BitConverter.ToInt16(Read(offset, 2));
|
|
public int ReadInt(long offset) => BitConverter.ToInt32(Read(offset, 4));
|
|
public long ReadLong(long offset) => BitConverter.ToInt64(Read(offset, 8));
|
|
|
|
public byte[] Serialize()
|
|
{
|
|
var opCodes = Instructions.Select(i => (byte)i).ToArray();
|
|
var constants = Constants.ToArray();
|
|
byte[] bytes = new byte[sizeof(long) + opCodes.Length];
|
|
System.Array.Copy(opCodes.LongLength.GetBytes(), 0, bytes, 0, sizeof(long));
|
|
System.Array.Copy(opCodes, 0, bytes, sizeof(long), opCodes.Length);
|
|
var list = new List<byte>(bytes);
|
|
foreach (var constant in constants) {
|
|
var data = constant.Signed.GetDynamicBytes();
|
|
if (data.Length == 1)
|
|
list.Add(data[0]);
|
|
else {
|
|
list.Add((byte)(data.Length | 0x80));
|
|
list.AddRange(data);
|
|
}
|
|
}
|
|
return list.ToArray();
|
|
}
|
|
|
|
public static Segment Deserialize(byte[] data)
|
|
{
|
|
return null;
|
|
}
|
|
}
|