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 instructions, IEnumerable constants) : ISerialize { public readonly FixedArray Instructions = new(instructions); public readonly FixedArray 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; } /// /// 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).
/// 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). ///
/// /// 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. /// 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(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; } }