Files
crtr/Assets/Cryville/Common/Pdt/PdtVariableMemory.cs
2022-09-30 17:32:21 +08:00

144 lines
5.6 KiB
C#

using System;
using System.Text;
using UnityEditor;
namespace Cryville.Common.Pdt {
/// <summary>
/// Span on the memory of a <see cref="PdtEvaluatorBase" />.
/// </summary>
public unsafe struct PdtVariableMemory {
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 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 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>
public void CopyTo(byte* dest, int destOffset, int length) {
for (int i = 0; i < length; i++)
dest[destOffset + i] = _ptr[i];
}
/// <summary>
/// Gets the memory of the span as a number.
/// </summary>
/// <returns>A number.</returns>
/// <exception cref="InvalidCastException">The span does not represent a number.</exception>
public float AsNumber() {
if (Type != PdtInternalType.Number)
throw new InvalidCastException("Not a number");
float value;
byte* ptr = (byte*)&value;
for (int i = 0; i < sizeof(float); i++)
ptr[i] = _ptr[i];
return value;
}
/// <summary>
/// Sets the memory of the span to a number.
/// </summary>
/// <param name="value">The number.</param>
/// <exception cref="InvalidCastException">The span does not represent a number.</exception>
public void SetNumber(float value) {
if (Type != PdtInternalType.Number)
throw new InvalidCastException("Not a number");
byte* ptr = (byte*)&value;
for (int i = 0; i < sizeof(float); i++)
_ptr[i] = 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 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 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 string AsIdentifier(int offset = 0) {
if (Type != PdtInternalType.Undefined && Type != PdtInternalType.Array)
throw new InvalidCastException("Not an identifier");
var len = *(int*)(_ptr + offset);
return new string((char*)(_ptr + offset + sizeof(int)), 0, len);
}
internal void* TrustedAsOfLength(int len) {
if (Length < len)
throw new InvalidCastException("Type not matched");
return _ptr;
}
/// <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 void GetArraySuffix(out int arrtype, out int pc) {
if (Type != PdtInternalType.Array && 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 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;
}
}
}