197 lines
8.6 KiB
C#
197 lines
8.6 KiB
C#
using System;
|
|
using UnsafeIL;
|
|
|
|
namespace Cryville.Common.Pdt {
|
|
/// <summary>
|
|
/// Span on the memory of a <see cref="PdtEvaluatorBase" />.
|
|
/// </summary>
|
|
public unsafe struct PdtVariableMemory : IEquatable<PdtVariableMemory> {
|
|
readonly byte* _ptr;
|
|
/// <summary>
|
|
/// The length of the span.
|
|
/// </summary>
|
|
public int Length { get; private set; }
|
|
/// <summary>
|
|
/// The type of the span.
|
|
/// </summary>
|
|
public int Type { get; private set; }
|
|
internal PdtVariableMemory(int type, byte* ptr, int len) {
|
|
Type = type;
|
|
_ptr = ptr;
|
|
Length = len;
|
|
}
|
|
/// <summary>
|
|
/// Copies the memory in the span to another span.
|
|
/// </summary>
|
|
/// <param name="dest">The destination span.</param>
|
|
public readonly void CopyTo(PdtVariableMemory dest) {
|
|
CopyTo(dest._ptr, 0, Length);
|
|
}
|
|
/// <summary>
|
|
/// Copies the memory in the span to a buffer.
|
|
/// </summary>
|
|
/// <param name="dest">The destination buffer.</param>
|
|
/// <param name="destOffset">The offset on the destination buffer to start copying to.</param>
|
|
public readonly void CopyTo(byte[] dest, int destOffset) {
|
|
fixed (byte* ptr = dest) {
|
|
CopyTo(ptr, destOffset, Length);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Copies the memory in the span to a buffer.
|
|
/// </summary>
|
|
/// <param name="dest">The destination buffer.</param>
|
|
/// <param name="destOffset">The offset on the destination buffer to start copying to.</param>
|
|
/// <param name="length">The length to copy.</param>
|
|
/// <exception cref="ArgumentOutOfRangeException"><paramref name="length" /> is greater than the length of the span.</exception>
|
|
public readonly void CopyTo(byte* dest, int destOffset, int length) {
|
|
if (length > Length) throw new ArgumentOutOfRangeException("length");
|
|
for (int i = 0; i < length; i++)
|
|
dest[destOffset + i] = _ptr[i];
|
|
}
|
|
/// <inheritdoc />
|
|
public readonly bool Equals(PdtVariableMemory obj) {
|
|
if (Type != obj.Type || Length != obj.Length) return false;
|
|
for (int i = 0; i < Length; i++) {
|
|
if (*(_ptr + i) != *(obj._ptr + i)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
/// <summary>
|
|
/// Gets the memory of the span as a number.
|
|
/// </summary>
|
|
/// <param name="offset">The offset on the span to start reading from.</param>
|
|
/// <returns>A number.</returns>
|
|
/// <exception cref="InvalidCastException">The span at the offset does not represent a number.</exception>
|
|
public readonly float AsNumber(int offset = 0) {
|
|
if (Type != PdtInternalType.Number && Type != PdtInternalType.Vector)
|
|
throw new InvalidCastException("Not a number");
|
|
float value;
|
|
byte* ptr = (byte*)&value;
|
|
for (int i = 0; i < sizeof(float); i++)
|
|
ptr[i] = _ptr[i + offset];
|
|
return value;
|
|
}
|
|
/// <summary>
|
|
/// Sets the memory of the span to a number.
|
|
/// </summary>
|
|
/// <param name="value">The number.</param>
|
|
/// <param name="offset">The offset from the start of the span.</param>
|
|
/// <exception cref="InvalidCastException">The span at the offset does not represent a number.</exception>
|
|
/// <exception cref="InvalidOperationException">The length of the span is not sufficient.</exception>
|
|
public readonly void SetNumber(float value, int offset = 0) {
|
|
if (Type != PdtInternalType.Number && Type != PdtInternalType.Vector)
|
|
throw new InvalidCastException("Not a number");
|
|
if (Length < sizeof(float) + offset)
|
|
throw new InvalidOperationException("Frame length not sufficient");
|
|
byte* ptr = (byte*)&value;
|
|
for (int i = 0; i < sizeof(float); i++)
|
|
_ptr[i + offset] = ptr[i];
|
|
}
|
|
/// <summary>
|
|
/// Gets the memory of the span as a string.
|
|
/// </summary>
|
|
/// <param name="offset">The offset on the span to start reading from.</param>
|
|
/// <returns>A string.</returns>
|
|
/// <exception cref="InvalidCastException">The span at the offset does not represent a string.</exception>
|
|
public readonly string AsString(int offset = 0) {
|
|
if (Type != PdtInternalType.String && Type != PdtInternalType.Array)
|
|
throw new InvalidCastException("Not a string");
|
|
var len = *(int*)(_ptr + offset);
|
|
return new string((char*)(_ptr + offset + sizeof(int)), 0, len);
|
|
}
|
|
/// <summary>
|
|
/// Sets the memory of the span to a string.
|
|
/// </summary>
|
|
/// <param name="value">The string.</param>
|
|
/// <param name="offset">The offset from the start of the span.</param>
|
|
/// <exception cref="InvalidCastException">The span at the offset does not represent a string.</exception>
|
|
/// <exception cref="InvalidOperationException">The length of the span is not sufficient.</exception>
|
|
public readonly void SetString(string value, int offset = 0) {
|
|
if (Type != PdtInternalType.String && Type != PdtInternalType.Array)
|
|
throw new InvalidCastException("Not a string");
|
|
int strlen = value.Length;
|
|
if (Length < strlen * sizeof(char) + sizeof(int) + offset)
|
|
throw new InvalidOperationException("Frame length not sufficient");
|
|
char* ptr = (char*)(_ptr + offset + sizeof(int));
|
|
*(int*)(_ptr + offset) = strlen;
|
|
int i = 0;
|
|
foreach (var c in value) ptr[i++] = c;
|
|
}
|
|
/// <summary>
|
|
/// Gets the memory of the span as an undefined identifier.
|
|
/// </summary>
|
|
/// <param name="offset">The offset on the span to start reading from.</param>
|
|
/// <returns>The name of an undefined identifier.</returns>
|
|
/// <exception cref="InvalidCastException">The span does not represent an undefined identifier.</exception>
|
|
public readonly int AsIdentifier(int offset = 0) {
|
|
if (Type != PdtInternalType.Undefined && Type != PdtInternalType.Array)
|
|
throw new InvalidCastException("Not an identifier");
|
|
return *(int*)(_ptr + offset);
|
|
}
|
|
/// <summary>
|
|
/// Gets the memory of the span as an instance of the specified type.
|
|
/// </summary>
|
|
/// <typeparam name="T">The specified type.</typeparam>
|
|
/// <param name="offset">The offset on the span to start reading from.</param>
|
|
/// <returns>An instance of the specified type.</returns>
|
|
/// <exception cref="ArgumentOutOfRangeException"><paramref name="offset" /> is not less than the length of the span.</exception>
|
|
/// <exception cref="InvalidCastException">The length of the span is not sufficient.</exception>
|
|
/// <remarks>
|
|
/// <para>Use <see cref="AsNumber(int)" /> instead while reading an unaligned number.</para>
|
|
/// </remarks>
|
|
public readonly T As<T>(int offset = 0) {
|
|
var len = Unsafe.SizeOf<T>();
|
|
if (offset >= Length)
|
|
throw new ArgumentOutOfRangeException("offset");
|
|
if (offset + len > Length)
|
|
throw new InvalidCastException("Frame length not sufficient");
|
|
return Unsafe.Read<T>(_ptr + offset);
|
|
}
|
|
/// <summary>
|
|
/// Sets the memory of the span to an instance of the specified type.
|
|
/// </summary>
|
|
/// <typeparam name="T">The specified type.</typeparam>
|
|
/// <param name="value">The value.</param>
|
|
/// <param name="offset">The offset from the start of the span.</param>
|
|
/// <exception cref="ArgumentOutOfRangeException"><paramref name="offset" /> is not less than the length of the span.</exception>
|
|
/// <exception cref="InvalidCastException">The length of the span is not sufficient.</exception>
|
|
/// <remarks>
|
|
/// <para>Use <see cref="SetNumber(float, int)" /> instead while writing an unaligned number.</para>
|
|
/// </remarks>
|
|
public readonly void Set<T>(T value, int offset = 0) {
|
|
var len = Unsafe.SizeOf<T>();
|
|
if (offset >= Length)
|
|
throw new ArgumentOutOfRangeException("offset");
|
|
if (offset + len > Length)
|
|
throw new InvalidCastException("Frame length not sufficient");
|
|
Unsafe.Write(_ptr + offset, value);
|
|
}
|
|
/// <summary>
|
|
/// Gets the array suffix.
|
|
/// </summary>
|
|
/// <param name="arrtype">The type of the array.</param>
|
|
/// <param name="pc">The item count of the array.</param>
|
|
/// <exception cref="InvalidCastException">The span does not represent an array.</exception>
|
|
public readonly void GetArraySuffix(out int arrtype, out int pc) {
|
|
if (Type != PdtInternalType.Vector && Type != PdtInternalType.Array)
|
|
throw new InvalidCastException("Not an array or vector");
|
|
arrtype = *(int*)(_ptr + Length - sizeof(int));
|
|
if (Type == PdtInternalType.Array) pc = *(int*)(_ptr + Length - 2 * sizeof(int));
|
|
else pc = -1;
|
|
}
|
|
/// <summary>
|
|
/// Sets the array suffix.
|
|
/// </summary>
|
|
/// <param name="arrtype">The type of the array.</param>
|
|
/// <param name="pc">The item count of the array.</param>
|
|
/// <exception cref="InvalidCastException">The span does not represent an array.</exception>
|
|
public readonly void SetArraySuffix(int arrtype, int pc = 0) {
|
|
if (Type != PdtInternalType.Vector && Type != PdtInternalType.Array)
|
|
throw new InvalidCastException("Not an array or vector");
|
|
*(int*)(_ptr + Length - sizeof(int)) = arrtype;
|
|
if (Type == PdtInternalType.Array) *(int*)(_ptr + Length - 2 * sizeof(int)) = pc;
|
|
}
|
|
}
|
|
}
|