Add project files.

This commit is contained in:
2022-09-30 17:32:21 +08:00
parent df69e65c88
commit e8e36b83bd
561 changed files with 40626 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
using System;
namespace Cryville.Common.Pdt {
/// <summary>
/// Base of evaluator for PDT expressions.
/// </summary>
public abstract class PdtEvaluatorBase {
private struct StackFrame {
public int Offset;
public int Length;
public int Type;
}
int _framecount = 0;
int _goffset = 0;
readonly StackFrame[] _stack = new StackFrame[256];
readonly byte[] _mem = new byte[0x100000];
bool _revokepttconst;
/// <summary>
/// Evaluates an expression and passes the result to a target operator.
/// </summary>
/// <param name="target">The target operator.</param>
/// <param name="exp">The expression to evaluate.</param>
public void Evaluate(PdtOperator target, PdtExpression exp) {
_framecount = 0;
_goffset = 0;
_revokepttconst = false;
for (var ins = exp.Instructions.First; ins != null; ins = ins.Next)
ins.Value.Execute(this);
Operate(target, _framecount, true);
if (exp.IsPotentialConstant) {
exp.IsConstant = exp.IsPotentialConstant = !_revokepttconst;
}
}
/// <summary>
/// Optimizes an expression by merging its instructions.
/// </summary>
/// <param name="exp">The expression to optimize.</param>
public void Optimize(PdtExpression exp) {
_framecount = 0;
_goffset = 0;
var il = exp.Instructions;
for (var ins = il.First; ins != null; ins = ins.Next) {
var i = ins.Value;
if (i is PdtInstruction.Operate) {
int fc0 = _framecount;
int fc1 = ((PdtInstruction.Operate)i).ParamCount;
try { i.Execute(this); } catch (Exception) { }
if (fc0 - _framecount == fc1) {
unsafe {
fixed (StackFrame* frame = &_stack[_framecount++]) {
frame->Type = PdtInternalType.Error;
frame->Offset = -1;
frame->Length = 0;
}
}
}
else {
var frame = _stack[_framecount - 1];
il.AddAfter(ins, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length));
ins = ins.Next;
for (var j = 0; j <= fc1; j++) il.Remove(ins.Previous);
}
}
else if (i is PdtInstruction.PushVariable) {
i.Execute(this);
var frame = _stack[_framecount - 1];
if (frame.Type != PdtInternalType.Undefined) {
il.AddAfter(ins, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length));
ins = ins.Next;
il.Remove(ins.Previous);
}
}
else i.Execute(this);
}
exp.IsConstant = true;
exp.IsPotentialConstant = true;
for (var ins = il.First; ins != null; ins = ins.Next) {
if (!(ins.Value is PdtInstruction.PushConstant)) {
exp.IsConstant = false;
}
else if (!(ins.Value is PdtInstruction.PushVariable)) {
exp.IsPotentialConstant = false;
return;
}
}
}
/// <summary>
/// Revokes the potential constant mark of the current expression.
/// </summary>
protected void RevokePotentialConstant() {
_revokepttconst = true;
}
internal unsafe void PushConstant(int type, byte[] value) {
fixed (StackFrame* frame = &_stack[_framecount++]) {
frame->Type = type;
frame->Offset = _goffset;
frame->Length = value.Length;
Array.Copy(value, 0, _mem, _goffset, value.Length);
_goffset += value.Length;
}
}
internal unsafe void PushVariable(ref string name) {
fixed (StackFrame* frame = &_stack[_framecount++]) {
byte[] value;
GetVariable(name, out frame->Type, out value);
frame->Offset = _goffset;
frame->Length = value.Length;
Array.Copy(value, 0, _mem, _goffset, value.Length);
_goffset += value.Length;
}
}
/// <summary>
/// Gets a variable of the specified name.
/// </summary>
/// <param name="name">The name of the variable.</param>
/// <param name="type">The type of the variable.</param>
/// <param name="value">The value of the variable.</param>
protected abstract void GetVariable(string name, out int type, out byte[] value);
internal void Operate(ref string name, int pc) {
Operate(GetOperator(name, pc), pc);
}
/// <summary>
/// Gets an operator of the specified name and the suggested parameter count.
/// </summary>
/// <param name="name">The name of the operator.</param>
/// <param name="pc">Suggested parameter count.</param>
/// <returns>An operator of the specific name.</returns>
/// <remarks>The parameter count of the returned operator does not necessarily equal to <paramref name="pc" />.</remarks>
protected abstract PdtOperator GetOperator(string name, int pc);
bool _failure;
unsafe void Operate(PdtOperator op, int pc, bool noset = false) {
fixed (byte* pmem = _mem) {
op.Begin(this);
for (int i = 0; i < pc; i++) {
var frame = _stack[--_framecount];
op.LoadOperand(new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length));
_goffset -= frame.Length;
}
op.Call(pmem + _goffset, noset);
}
}
internal unsafe PdtVariableMemory StackAlloc(int type, byte* ptr, int len) {
fixed (StackFrame* frame = &_stack[_framecount++]) {
frame->Type = type;
frame->Offset = _goffset;
frame->Length = len;
_goffset += len;
return new PdtVariableMemory(type, ptr, len);
}
}
internal void DiscardStack() {
_goffset -= _stack[--_framecount].Length;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e91dc9e4fd28a584c8f2fce4f9e9b648
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,247 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Cryville.Common.Pdt {
/// <summary>
/// PDT expression.
/// </summary>
public class PdtExpression {
internal LinkedList<PdtInstruction> Instructions;
/// <summary>
/// Whether the value of this expression is constant.
/// </summary>
/// <remarks>The value of this property is <c>false</c> until it is optimized.</remarks>
public bool IsConstant { get; internal set; }
internal bool IsPotentialConstant;
internal PdtExpression(LinkedList<PdtInstruction> ins) {
Instructions = ins;
}
public override string ToString() {
string r = "";
bool flag = false;
foreach (PdtInstruction ins in Instructions) {
if (flag) r += "; ";
r += ins.ToString();
flag = true;
}
return r;
}
}
internal abstract class PdtInstruction {
internal abstract void Execute(PdtEvaluatorBase etor);
public class PushConstant : PdtInstruction {
public int Type { get; private set; }
public byte[] Value { get; private set; }
public PushConstant(int type, byte[] value) {
Type = type;
Value = value;
}
public PushConstant(int type, byte[] buffer, int offset, int len) {
Type = type;
Value = new byte[len];
Array.Copy(buffer, offset, Value, 0, len);
}
internal override void Execute(PdtEvaluatorBase etor) {
etor.PushConstant(Type, Value);
}
public override string ToString() {
return string.Format("pushc ({0:x8}){1}", Type, BitConverter.ToString(Value));
}
}
public class PushVariable : PdtInstruction {
private string m_name;
public string Name { get { return m_name; } }
public PushVariable(string name) {
m_name = name;
}
internal override void Execute(PdtEvaluatorBase etor) {
etor.PushVariable(ref m_name);
}
public override string ToString() {
return string.Format("pushv {0}", Name);
}
}
public class Operate : PdtInstruction {
private string m_name;
public string Name { get { return m_name; } }
public int ParamCount { get; private set; }
public Operate(string name, int paramCount) {
m_name = name;
ParamCount = paramCount;
}
internal override void Execute(PdtEvaluatorBase etor) {
etor.Operate(ref m_name, ParamCount);
}
public override string ToString() {
return string.Format("op {0}({1})", Name, ParamCount);
}
}
}
public partial class PdtInterpreter<T> {
readonly static Dictionary<char, int> pri = new Dictionary<char, int> {
{ '*', 5 }, { '/', 5 }, { '%', 5 },
{ '+', 4 }, { '-', 4 },
{ '=', 3 }, { '<', 3 }, { '>', 3 },
{ '&', 2 },
{ '|', 1 }, { '!', 1 },
{ ',', 0 },
};
readonly static PdtExpression _emptyexp;
static PdtInterpreter() {
var ins = new LinkedList<PdtInstruction>();
ins.AddLast(new PdtInstruction.PushConstant(
PdtInternalType.Number, BitConverter.GetBytes(1f)
));
_emptyexp = new PdtExpression(ins);
}
PdtExpToken GetToken() {
ws();
var result = new PdtExpToken {
Type = ct & 0x0fe0
};
switch (result.Type) {
case 0x0020: result.Value = GetIdentifier(); break;
case 0x0040: result.Value = GetNumber(); break;
case 0x0100: result.Value = GetString(); break;
default: result.Value = cc.ToString(); Position++; break;
}
return result;
}
private struct PdtExpToken {
public int Type { get; set; }
public string Value { get; set; }
public override string ToString() {
return string.Format("0x{0:x4}: {1}", Type, Value);
}
public readonly static PdtExpToken EmptyOperator = new PdtExpToken {
Type = 0x0080,
Value = "",
};
}
/// <summary>
/// Interprets an expression from the current position and loads it onto an instruction set.
/// </summary>
/// <param name="ins">The instruction set.</param>
/// <param name="enc">
/// <para>The enclosing scope type of the (sub)expression. May be one of the following:</para>
/// <list type="bullet">
/// <item><term><c>-2</c></term><description>The expression is in a root scope which ends at a semicolon.</description></item>
/// <item><term><c>-1</c></term><description>The expression is in a bracketed scope which ends at a closing parenthesis.</description></item>
/// <item><term>Any non-negative values</term><description>The expression is in an auxiliary scope which ends before a closing parenthesis or an operator whose priority is lower (less) than the value of this parameter.</description></item>
/// </list>
/// </param>
/// <param name="pc">The parameter count in this (sub)expression.</param>
/// <param name="token">The token already parsed but required for the interpretation of the subexpression.</param>
/// <returns>The expression token following this (sub)expression.</returns>
PdtExpToken InterpretExp(LinkedList<PdtInstruction> ins, int enc, out int pc, PdtExpToken? token = null) {
PdtExpToken t1, t2;
int insc0 = ins.Count;
pc = 1;
if (token == null) t1 = PdtExpToken.EmptyOperator;
else t1 = token.Value;
while (true) {
t2 = InterpretExpBlock(ins);
panic:
switch (t2.Type) {
case 0x0080:
if (t1.Value != "") {
int p1 = pri[t1.Value[0]];
int p2 = pri[t2.Value[0]];
if (p2 <= enc) goto exit;
if (p2 > p1) {
int _;
t2 = InterpretExp(ins, p1, out _, t2);
goto panic;
}
if (t1.Value != ",") ins.AddLast(new PdtInstruction.Operate(t1.Value, 2));
else pc++;
}
t1 = t2;
break;
case 0x0400:
if (enc == -2) throw new FormatException("Expression not enclosed correctly: Too many closing brackets");
if (ins.Count == insc0) pc = 0;
goto exit;
case 0x0800:
goto exit;
}
}
exit:
if (t1.Value != "," && t1.Value != "") ins.AddLast(new PdtInstruction.Operate(t1.Value, 2));
else if (t1.Value == ",") pc++;
return t2;
}
/// <summary>
/// Interprets an expression block which consists of several adjacent constants and subexpressions, optionally with a unary operator.
/// </summary>
/// <param name="ins">The instruction set.</param>
/// <returns>The expression token following this expression block.</returns>
PdtExpToken InterpretExpBlock(LinkedList<PdtInstruction> ins) {
var t = GetToken();
if (t.Type == 0x0080) {
var r = InterpretExpBlock(ins);
ins.AddLast(new PdtInstruction.Operate(t.Value, 1));
return r;
}
bool flag = false;
PdtExpToken? buf = null;
while (true) {
if (buf != null && t.Type != 0x0200) {
PdtExpression def;
if (defs.TryGetValue(buf.Value.Value, out def)) {
foreach (var i in def.Instructions) ins.AddLast(i);
}
else ins.AddLast(new PdtInstruction.PushVariable(buf.Value.Value));
buf = null;
TryPushAdjMul(ins, ref flag);
}
switch (t.Type) {
case 0x0020:
buf = t;
break;
case 0x0040:
float num = float.Parse(t.Value);
ins.AddLast(new PdtInstruction.PushConstant(PdtInternalType.Number, BitConverter.GetBytes(num)));
break;
case 0x0100:
int strlen = t.Value.Length;
unsafe {
var strbuf = new byte[strlen * sizeof(char) + sizeof(int)];
fixed (byte* psuffix = strbuf) {
*(int*)psuffix = strlen;
}
Encoding.Unicode.GetBytes(t.Value, 0, strlen, strbuf, sizeof(int));
ins.AddLast(new PdtInstruction.PushConstant(PdtInternalType.String, strbuf));
}
break;
case 0x0200:
int pc;
InterpretExp(ins, -1, out pc);
if (buf != null) {
ins.AddLast(new PdtInstruction.Operate(buf.Value.Value, pc));
buf = null;
}
else if (pc > 1) {
ins.AddLast(new PdtInstruction.Operate(",", pc));
}
else if (pc == 0)
throw new FormatException("Empty subexpression");
break;
default:
return t;
}
if (buf == null) TryPushAdjMul(ins, ref flag);
t = GetToken();
}
}
void TryPushAdjMul(LinkedList<PdtInstruction> ins, ref bool flag) {
if (flag) ins.AddLast(new PdtInstruction.Operate("*", 2));
else flag = true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a551104b532c8d0469917e3e0e8c2cba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
namespace Cryville.Common.Pdt {
/// <summary>
/// The identifiers of the internal types of PDT.
/// </summary>
public static class PdtInternalType {
internal readonly static int Error = "error".GetHashCode();
/// <summary>
/// Array of a same variable-length type, with a suffix indicating the element count and the element type.
/// </summary>
public readonly static int Array = "array".GetHashCode();
/// <summary>
/// IEEE 754 32-bit floating-point number.
/// </summary>
public readonly static int Number = "number".GetHashCode();
/// <summary>
/// A sequence of UTF-16 code units, with a prefix indicating the number of the code units.
/// </summary>
public readonly static int String = "string".GetHashCode();
/// <summary>
/// A sequence of UTF-16 code units representing the name of an undefined variable.
/// </summary>
public readonly static int Undefined = "undefined".GetHashCode();
/// <summary>
/// Vector of a same constant-length type, with a suffix indicating the element type.
/// </summary>
public readonly static int Vector = "vector".GetHashCode();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 36eb4aecae64aff4891c4ddd2d1ff68c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,232 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
namespace Cryville.Common.Pdt {
/// <summary>
/// Interpreter for Property Definition Tree (PDT) file format.
/// </summary>
/// <typeparam name="T">The object type represented by the PDT.</typeparam>
public partial class PdtInterpreter<T> {
/// <summary>
/// The character category map.
/// </summary>
/// <remarks>
/// <list type="bullet">
/// <item><term><c>0x0001</c></term><description>White Space</description></item>
/// <item><term><c>0x0010</c></term><description>Identifier</description></item>
/// <item><term><c>0x0020</c></term><description>Identifier Begin</description></item>
/// <item><term><c>0x0040</c></term><description>Digit</description></item>
/// <item><term><c>0x0080</c></term><description>Operator</description></item>
/// <item><term><c>0x0100</c></term><description>String</description></item>
/// <item><term><c>0x0200</c></term><description>Opening Bracket</description></item>
/// <item><term><c>0x0400</c></term><description>Closing Bracket</description></item>
/// <item><term><c>0x0800</c></term><description>End of Expression</description></item>
/// <item><term><c>0x1000</c></term><description>End of Key</description></item>
/// </list>
/// </remarks>
readonly static int[] cm = new int[] {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0001, 0x0080, 0x0100, 0x0000, 0x0030, 0x0080, 0x0080, 0x0000, 0x0200, 0x0400, 0x0080, 0x0080, 0x0080, 0x0080, 0x0040, 0x0080,
0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x1000, 0x1800, 0x0080, 0x0080, 0x0080, 0x0000,
0x0080, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0030,
0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x1000, 0x0080, 0x1000, 0x0000, 0x0000,
};
/// <summary>
/// Interprets a source string to an object of type <typeparamref name="T" />.
/// </summary>
/// <param name="src">The source string.</param>
/// <returns>The interpreted object.</returns>
public static T Interpret(string src) {
return Interpret(src, BinderAttribute.CreateBinderOfType(typeof(T)));
}
/// <summary>
/// Interprets a source string to an object of type <typeparamref name="T" /> with a binder.
/// </summary>
/// <param name="src">The source string.</param>
/// <param name="binder">The binder.</param>
/// <returns>The interpreted object.</returns>
public static T Interpret(string src, Binder binder) {
return new PdtInterpreter<T>(src, binder).Interpret();
}
readonly string _src;
readonly Binder _binder;
protected int Position { get; private set; }
#pragma warning disable IDE1006
protected char cc { get { return _src[Position]; } }
protected int ct { get { return cm[cc]; } }
protected string tokenb(int flag) { // Token Whitelist
int sp = Position;
while ((ct & flag) == 0) Position++;
return _src.Substring(sp, Position - sp);
}
protected string tokenw(int flag) { // Token Whitelist
int sp = Position;
while ((ct & flag) != 0) Position++;
return _src.Substring(sp, Position - sp);
}
protected void ws() {
while ((ct & 0x0001) != 0) Position++;
}
#pragma warning restore IDE1006
protected char GetChar() {
char r = cc;
Position++;
return r;
}
protected string GetIdentifier() {
if ((ct & 0x0020) == 0) return "";
return tokenw(0x0010);
}
protected string GetNumber() {
return tokenw(0x0040);
}
protected string GetString() {
int sp = Position;
do {
if (cc == '\\') Position++;
Position++;
} while (ct != 0x0100);
Position++;
return Regex.Replace(_src.Substring(sp + 1, Position - sp - 2), @"\\(.)", "$1");
}
protected PdtExpression GetExp() {
var ins = new LinkedList<PdtInstruction>();
int _;
InterpretExp(ins, -2, out _);
return new PdtExpression(ins);
}
readonly Dictionary<string, PdtExpression> defs = new Dictionary<string, PdtExpression>();
/// <summary>
/// Creates an instance of the <see cref="PdtInterpreter{T}" /> class.
/// </summary>
/// <param name="src">The source string.</param>
/// <param name="binder">The binder. May be <c>null</c>.</param>
public PdtInterpreter(string src, Binder binder) {
_src = src;
_binder = binder;
if (_binder == null)
_binder = BinderAttribute.CreateBinderOfType(typeof(T));
}
/// <summary>
/// Interprets the source to an object of type <typeparamref name="T" />.
/// </summary>
/// <returns>The interpreted object.</returns>
public T Interpret() {
InterpretDirectives();
return (T)InterpretObject(typeof(T));
}
void InterpretDirectives() {
bool flag = false;
ws();
while (cc == '#') {
Position++;
switch (GetIdentifier()) {
case "ver":
ws();
Logger.Log("main", 3, "PDT", "Legacy PDT directive #ver={0} found. Ignoring.", GetNumber());
break;
case "format":
ws();
if (GetNumber() != "1")
throw new NotSupportedException("Format not supported");
flag = true;
break;
case "define":
if (!flag) throw new FormatException("Format directive not found");
ws();
string dname = GetIdentifier();
ws();
PdtExpression dexp = GetExp();
defs.Add(dname, dexp);
break;
default:
throw new NotSupportedException("Unsupported directive found");
}
ws();
}
if (!flag) throw new FormatException("Format directive not found");
}
object InterpretObject(Type type) {
var result = ReflectionHelper.InvokeEmptyConstructor(type);
bool dictflag = ReflectionHelper.IsGenericDictionary(type);
while (true) {
try { ws(); }
catch (IndexOutOfRangeException) { return result; }
object pkey = InterpretKey(type);
char c = GetChar();
switch (c) {
case '{':
if (dictflag) {
var ktype = type.GetGenericArguments()[0];
var ptype = type.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = InterpretObject(ptype);
((IDictionary)result).Add(key, value);
}
else {
MemberInfo prop;
bool flag = ReflectionHelper.TryFindMemberWithAttribute<ElementListAttribute>(type, out prop);
if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey);
Type ptype = ReflectionHelper.GetMemberType(prop);
if (ReflectionHelper.IsGenericDictionary(ptype)) {
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
if (flag) {
object key = _binder.ChangeType(pkey, ktype, null);
object value = InterpretObject(vtype);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value);
}
else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype));
}
else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype));
}
break;
case ':':
case ';':
var exp = c == ';' ? _emptyexp : GetExp();
if (dictflag) {
var ktype = type.GetGenericArguments()[0];
var vtype = type.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = _binder.ChangeType(exp, vtype, null);
((IDictionary)result).Add(key, value);
}
else {
MemberInfo prop;
bool flag = ReflectionHelper.TryFindMemberWithAttribute<PropertyListAttribute>(type, out prop);
if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey);
var ptype = ReflectionHelper.GetMemberType(prop);
if (!typeof(IDictionary).IsAssignableFrom(ptype)) {
object value = _binder.ChangeType(exp, ptype, null);
ReflectionHelper.SetValue(prop, result, value, _binder);
}
else {
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = _binder.ChangeType(exp, vtype, null);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value);
}
}
break;
case '}':
return result;
}
}
}
protected virtual object InterpretKey(Type type) {
return tokenb(0x1000).Trim();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2a66a8564bee7c8449417a795cee8729
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,77 @@
using System;
namespace Cryville.Common.Pdt {
/// <summary>
/// PDT operator.
/// </summary>
public unsafe abstract class PdtOperator {
byte* _prmem;
int _loadindex;
readonly PdtVariableMemory[] _operands;
/// <summary>
/// The count of the operands loaded.
/// </summary>
protected int LoadedOperandCount { get { return ParamCount - _loadindex; } }
/// <summary>
/// Gets the operand at the specified index.
/// </summary>
/// <param name="index">The index.</param>
/// <returns>The operand at the specified index.</returns>
/// <exception cref="IndexOutOfRangeException"><paramref name="index" /> is not less than <see cref="LoadedOperandCount" /> or less than 0.</exception>
protected PdtVariableMemory GetOperand(int index) {
if (index >= LoadedOperandCount || index < 0) throw new IndexOutOfRangeException();
int i = index + _loadindex;
return _operands[i];
}
internal int ParamCount { get; private set; }
/// <summary>
/// Creates an instance of the <see cref="PdtOperator" /> class.
/// </summary>
/// <param name="pc">The suggested parameter count.</param>
protected PdtOperator(int pc) {
ParamCount = pc;
_operands = new PdtVariableMemory[pc];
}
PdtEvaluatorBase _etor;
bool _failure = false;
bool _rfreq = true;
internal void Begin(PdtEvaluatorBase etor) {
_etor = etor;
_failure = false;
_loadindex = ParamCount;
}
internal void LoadOperand(PdtVariableMemory mem) {
if (_loadindex == 0) return;
_operands[--_loadindex] = mem;
}
internal void Call(byte* prmem, bool noset) {
_prmem = prmem;
_rfreq = false;
Execute();
if (!_rfreq && !noset) throw new InvalidOperationException("Return frame not set");
if (_failure) {
if (_rfreq) _etor.DiscardStack();
throw new InvalidOperationException("Evaluation failed");
}
}
/// <summary>
/// Executes the operator.
/// </summary>
protected abstract void Execute();
/// <summary>
/// Gets a return frame.
/// </summary>
/// <param name="type">The type of the frame.</param>
/// <param name="len">The length of the frame.</param>
/// <returns>The return frame.</returns>
/// <exception cref="InvalidOperationException">The return frame has already been requested.</exception>
protected PdtVariableMemory GetReturnFrame(int type, int len) {
if (_rfreq) {
_failure = true;
throw new InvalidOperationException("Return frame already requested");
}
_rfreq = true;
return _etor.StackAlloc(type, _prmem, len);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dc184c2d84fe5ea449cea78cba46d74d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,749 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Cryville.Common.Pdt {
#if false
[Obsolete]
public static class PdtReader {
readonly static char[] ws = {
' ', '\t', '\n', '\r'
};
readonly static char[] spunc = {
' ', '\t', '\n', '\r',
'{', '}', ';'
};
readonly static char[] ipunc = {
' ', '\t', '\n', '\r',
'{', '}', ';',
':'
};
readonly static char[] vpunc = {
'{', '}', ';'
};
static int pos;
static string data;
static char cc {
get {
return data[pos];
}
}
static bool eof {
get {
return pos == data.Length;
}
}
static Dictionary<string, Expression> definitions;
public static T Read<T>(string _data, Binder binder = null) {
data = _data;
pos = 0;
definitions = new Dictionary<string, Expression>();
while (true) {
if (cc == '#') {
SkipChar();
var s = GetIdentifier();
switch (s) {
case "ver":
var s2 = GetString();
if (s2 != "1") throw new FormatException("Invalid PDT version");
continue;
case "define":
var s3 = GetString();
var s4 = GetValue();
definitions.Add(s3, new Expression(s4, definitions));
SkipChar();
// TODO
continue;
default:
SkipLine();
continue;
}
}
break;
}
if (binder == null)
binder = BinderAttribute.CreateBinderOfType(typeof(T));
return (T)ParseObject(typeof(T), binder);
}
static object ParseObject(Type type, Binder binder) {
// TODO Binder
object obj = type.GetConstructor(new Type[]{}).Invoke(new object[]{});
while (true) {
if (eof) return obj;
string str = GetValue();
if (cc == '{') { // List item
SkipChar();
string strkey = str;
if (typeof(IDictionary).IsAssignableFrom(type)) {
var ktype = type.GetGenericArguments()[0];
var ptype = type.GetGenericArguments()[1];
object key = binder.ChangeType(strkey, ktype, null);
object value = ParseObject(ptype, binder);
((IDictionary)obj).Add(key, value);
}
else {
MemberInfo prop = null;
Type ttype = null;
bool flag = ReflectionHelper.TryFindMemberWithAttribute<ElementListAttribute>(type, out prop);
if (!flag)
prop = ReflectionHelper.GetMember(type, strkey);
ttype = ReflectionHelper.GetMemberType(prop);
if (!typeof(IDictionary).IsAssignableFrom(ttype)) {
throw new NotImplementedException();
}
else {
var ktype = ttype.GetGenericArguments()[0];
var ptype = ttype.GetGenericArguments()[1];
if (flag) {
object key = binder.ChangeType(strkey, ktype, null);
object value = ParseObject(ptype, binder);
((IDictionary)ReflectionHelper.GetValue(prop, obj)).Add(key, value);
}
else {
ReflectionHelper.SetValue(prop, obj, ParseObject(ttype, binder));
}
}
}
}
else if (cc == ';') { // Single property
SkipChar();
string strkey;
MemberInfo prop = null;
if (str[0] == '*') { // Component-like property
strkey = str.Substring(1);
prop = ReflectionHelper.FindMemberWithAttribute<ComponentListAttribute>(type);
var ttype = ReflectionHelper.GetMemberType(prop);
if (!typeof(IList).IsAssignableFrom(ttype))
throw new Exception(); // TODO
var ktype = ttype.GetGenericArguments()[0];
object key = binder.ChangeType(strkey, ktype, null);
((IList)ReflectionHelper.GetValue(prop, obj)).Add(key);
}
else { // Common property
var kv = str.Split(new char[]{':'}, 2);
strkey = kv[0];
// TODO
if (typeof(IDictionary).IsAssignableFrom(type)) {
var ktype = type.GetGenericArguments()[0];
var ptype = type.GetGenericArguments()[1];
object key = binder.ChangeType(strkey, ktype, null);
object value = binder.ChangeType(new Expression(
kv.Length == 1 ? "true" : kv[1], definitions
), ptype, null);
((IDictionary)obj).Add(key, value);
}
else {
bool flag = ReflectionHelper.TryFindMemberWithAttribute<PropertyListAttribute>(type, out prop);
if (!flag)
prop = ReflectionHelper.GetMember(type, strkey);
var ttype = ReflectionHelper.GetMemberType(prop);
if (!typeof(IDictionary).IsAssignableFrom(ttype)) {
object value = binder.ChangeType(new Expression(
kv.Length == 1 ? "true" : kv[1], definitions
), ttype, null);
ReflectionHelper.SetValue(prop, obj, value, binder);
}
else {
var ktype = ttype.GetGenericArguments()[0];
var ptype = ttype.GetGenericArguments()[1];
object key = binder.ChangeType(strkey, ktype, null);
object value = binder.ChangeType(new Expression(
kv.Length == 1 ? "true" : kv[1], definitions
), ptype, null);
((IDictionary)ReflectionHelper.GetValue(prop, obj)).Add(key, value);
}
}
}
}
else if (cc == '}') {
try { SkipChar(); }
catch (IndexOutOfRangeException) { }
return obj;
}
else throw new Exception(); // TODO
}
}
static void SkipChar() {
pos++;
SkipWs();
}
static void SkipWs() {
while (true) {
for (; ws.Contains(cc); pos++);
if (data[pos] == '/' && data[pos + 1] == '*') {
for (; data[pos] != '*' || data[pos+1] != '/'; pos++);
pos += 2;
}
else return;
}
}
static string GetIdentifier() {
SkipWs();
string r = "";
for (; !ipunc.Contains(cc); pos++) r += cc;
SkipWs();
return r;
}
static string GetString() {
SkipWs();
string r = "";
for (; !spunc.Contains(cc); pos++) r += cc;
SkipWs();
return r;
}
static string GetValue() {
SkipWs();
string r = "";
for (; !vpunc.Contains(cc); pos++) r += cc;
SkipWs();
return r.Trim();
}
static void SkipLine() {
for (; cc != '\n'; pos++);
SkipWs();
}
}
#endif
public class ElementListAttribute : Attribute { }
public class ComponentListAttribute : Attribute { }
public class PropertyListAttribute : Attribute { }
#if false
[Obsolete]
public abstract class ExpBase {
public string exp {
get;
private set;
}
public ExpBase(string s) {
exp = s;
}
public override string ToString() {
return exp;
}
}
[Obsolete]
public abstract class ValueBase : ExpBase {
public ValueBase(string s) : base(s) { }
object preEvalResult;
byte preEvalDepth = 0;
public bool IsDynamic {
get { return preEvalDepth == 0; }
}
protected abstract object EvalInternal(IEvaluator etor);
public void PreEval(IEvaluator etor, byte depth = 1) {
if (depth == 0) throw new ArgumentException("depth cannot be 0");
if (preEvalDepth != 0 && preEvalDepth < depth) return;
try {
preEvalResult = PreEvalInternal(etor, depth);
preEvalDepth = depth;
}
catch (Exception) { }
}
protected virtual object PreEvalInternal(IEvaluator etor, byte depth) {
return Eval(etor);
}
public object Eval(IEvaluator etor) {
if (preEvalDepth != 0)
return preEvalResult;
return EvalInternal(etor);
}
}
[Obsolete]
public class Identifier : ValueBase {
public Identifier(string s) : base(s) { }
protected override object EvalInternal(IEvaluator etor) {
return etor.EvalIdentifier(exp);
}
}
[Obsolete]
public class Operand : ExpBase {
public OperandPriority Priority {
get;
private set;
}
public Operand(string s) : base(s) {
switch (s) {
case ".": Priority = OperandPriority.Prop; break;
case "*": case "/": Priority = OperandPriority.Mul; break;
case "+": case "-": Priority = OperandPriority.Add; break;
case " ": case ",": Priority = OperandPriority.Sep; break;
default: Priority = OperandPriority.None; break;
}
}
public Operand(string s, OperandPriority p) : base(s) {
Priority = p;
}
}
[Obsolete]
public enum OperandPriority {
None = 0,
Prop = 5,
NeibMul = 4,
Mul = 3,
Add = 2,
Sep = 1
}
[Obsolete]
public abstract class ConstantBase : ValueBase {
public ConstantBase(string s) : base(s) { }
}
[Obsolete]
public class CNumber : ConstantBase {
public CNumber(string s) : base(s) { }
protected override object EvalInternal(IEvaluator etor) {
return etor.ParseNumber(exp);
}
}
[Obsolete]
public class CString : ConstantBase {
public CString(string s) : base(s) { }
protected override object EvalInternal(IEvaluator etor) {
return etor.ParseString(exp);
}
}
[Obsolete]
public class BracketInitial : ExpBase {
public BracketInitial() : base("(") { }
}
[Obsolete]
public class BracketFinal : ExpBase {
public BracketFinal() : base(")") { }
}
[Obsolete]
public class Expression : ValueBase {
List<ValueBase> estack = new List<ValueBase>();
List<Operand> ostack = new List<Operand>();
StackType type;
enum StackType {
Root, Unary, Bracketed, Supportive, Function
}
readonly OperandPriority Priority;
public Expression(string s, Dictionary<string, Expression> def) : base("") {
var exp = s.Trim();
type = StackType.Root;
int pos = 0;
var b = new List<ExpBase>();
while (pos < exp.Length) {
b.Add(Forward(ref exp, ref pos));
}
var lb = b[b.Count - 1];
if (def.ContainsKey(lb.exp)) {
b.Add(def[lb.exp]);
b.Remove(lb);
}
for (int i = b.Count - 2; i >= 0; i--) {
// TODO Insertion
var lhb = b[i];
var rhb = b[i + 1];
if (lhb is ConstantBase || lhb is Expression || lhb is BracketFinal) {
if (rhb is Identifier || rhb is Expression || rhb is BracketInitial) {
b.Insert(i + 1, new Operand("*", OperandPriority.NeibMul));
}
}
else if (lhb is Identifier) {
if (rhb is Expression) {
b.Insert(i + 1, new Operand("*", OperandPriority.NeibMul));
}
if (def.ContainsKey(lhb.exp)) {
b.Insert(i, def[lhb.exp]);
b.Remove(lhb);
}
}
}
int p = 0;
estack.Add(new Expression(b, ref p, StackType.Bracketed, def));
}
public Expression Clone() {
var r = (Expression)this.MemberwiseClone();
var es = new ValueBase[estack.Count];
estack.CopyTo(es);
r.estack = es.ToList();
var os = new Operand[ostack.Count];
ostack.CopyTo(os);
r.ostack = os.ToList();
return r;
}
Expression(List<ExpBase> b, ref int p, StackType t, Dictionary<string, Expression> def) : base("") {
type = t;
if (t == StackType.Unary) {
ostack.Add((Operand)b[p]);
p++;
}
while (p < b.Count - 1) {
if (estack.Count == 0) {
var b0 = b[p];
if (b0 is Operand) {
var lp = p;
var e = new Expression(
b,
ref p,
StackType.Unary,
def
);
b.Insert(p, e);
b.RemoveRange(lp, p - lp);
p = lp;
}
else if (b0 is BracketInitial) {
var lp = p;
p++;
var e = new Expression(
b,
ref p,
StackType.Bracketed,
def
);
b.Insert(p, e);
b.RemoveRange(lp, p - lp);
p = lp;
}
estack.Add((ValueBase)b[p]);
p++;
if (t == StackType.Unary) {
if (estack.Count != 1)
throw new Exception(); // TODO
else return;
}
}
if (p >= b.Count) return;
var b1 = b[p];
if (b1 is BracketFinal) {
if (t == StackType.Bracketed) p++;
return;
}
var b2 = b[p + 1];
if (b2 is BracketInitial) {
var lp = p + 1;
p += 2;
var e = new Expression(
b,
ref p,
StackType.Bracketed,
def
);
b.Insert(p, e);
b.RemoveRange(lp, p - lp);
p = lp - 1;
b2 = b[p + 1];
}
if (b1 is Operand) {
if (estack.Count == 1)
Priority = ((Operand)b1).Priority;
if (b2 is Operand) {
var lp = p + 1;
p++;
var e = new Expression(
b,
ref p,
StackType.Unary,
def
);
b.Insert(p, e);
b.RemoveRange(lp, p - lp);
p = lp - 1;
b2 = b[p + 1];
}
if (p + 2 >= b.Count) {
ostack.Add((Operand)b1);
estack.Add((ValueBase)b2);
p += 2;
return;
}
var b3 = b[p + 2];
if (b3 is BracketFinal) {
ostack.Add((Operand)b1);
estack.Add((ValueBase)b2);
p += 2;
if (t == StackType.Bracketed) p++;
return;
}
else if (b3 is Operand) {
var o1 = (Operand)b1; var o2 = (Operand)b3;
if (o2.Priority == Priority) {
ostack.Add(o1); estack.Add((ValueBase)b2);
p += 2;
continue;
}
else if (o2.Priority > Priority) {
var lp = p + 1;
p++;
var e = new Expression(
b, ref p,
StackType.Supportive, def
);
b.Insert(p, e);
b.RemoveRange(lp, p - lp);
p = lp - 1;
continue;
}
else if (o2.Priority < Priority) {
ostack.Add(o1);
estack.Add((ValueBase)b2);
// b.RemoveRange(0, 2);
if (type == StackType.Bracketed) {
Expression cl = this.Clone();
cl.type = StackType.Supportive;
estack.Clear();
ostack.Clear();
estack.Add(cl);
Priority = o2.Priority;
p += 2;
continue;
}
else {
type = StackType.Supportive;
p += 2;
return;
}
}
}
else
throw new Exception(); // TODO
}
else
throw new Exception(); // TODO
throw new Exception(); // TODO
/*if (lb is Identifier) {
if (def.ContainsKey(lb.exp)) {
b.Add(def[lb.exp]);
b.Remove(lb);
}
}
// Unary
if (estack.Count == 0) {
if (b[0] is Operand) {
b.Add(new Expression(
b,
ref p,
StackType.Unary,
def
));
b.RemoveAt(0);
}
if (b[0] is ValueBase) {
estack.Add((ValueBase)b[0]);
b.RemoveAt(0);
if (type == StackType.Unary) return;
if (b.Count == 0) continue;
}
}
if (estack.Count == 1) {
if (b[0] is Operand)
Priority = ((Operand)b[0]).Priority;
}
// Bracket
if (lb is BracketInitial) {
b.Remove(lb);
b.Add(new Expression(b, ref p, StackType.Bracketed, def));
}
else if (lb is BracketFinal) {
if (type != StackType.Bracketed) p--;
foreach (var i in b) {
if (i is Operand) ostack.Add((Operand)i);
else if (i is BracketFinal) return;
else estack.Add((ValueBase)i);
}
}
var c = b.Count;
if (c <= 1) continue;
// Two blocks
lb = b[c - 1];
var lb1 = b[c - 2];
if (lb is Operand && lb1 is Operand) {
b.Add(new Expression(
b,
ref p,
StackType.Unary,
def
));
b.RemoveAt(b.Count - 2);
}
c = b.Count;
if (c <= 2) continue;
// Three blocks
var b0 = b[0];
var b1 = b[1];
var b2 = b[2];
if (!(b0 is Operand))
throw new Exception(); // TODO
if (!(b1 is ValueBase))
throw new Exception(); // TODO
if (!(b2 is Operand))
throw new Exception(); // TODO
var o1 = (Operand)b0; var o2 = (Operand)b2;
if (o2.Priority == Priority) {
ostack.Add(o1); estack.Add((ValueBase)b1);
b.Remove(o1); b.Remove(b1);
continue;
}
if (o2.Priority > Priority) {
b.Add(new Expression(
b, ref p,
StackType.Supportive, def
));
b.RemoveRange(1, b.Count - 2);
continue;
}
if (o2.Priority < Priority) {
ostack.Add(o1);
estack.Add((ValueBase)b1);
b.RemoveRange(0, 2);
if (type == StackType.Bracketed) {
Expression cl = this.Clone();
cl.type = StackType.Supportive;
estack.Clear();
ostack.Clear();
estack.Add(cl);
Priority = o2.Priority;
}
else {
type = StackType.Supportive;
// p = o2.Index;
return;
}
}*/
}
estack.Add((ValueBase)b[b.Count - 1]);
p++;
}
ExpBase Forward(ref string s, ref int p) {
char sc = s[p];
string r = "";
if (cat(sc) == 3) {
p++;
return new BracketInitial();
}
else if (cat(sc) == 4) {
p++;
return new BracketFinal();
}
else if (cat(sc) == 5) {
for (; p < s.Length; p++) {
if (cat(s[p]) != 5) break;
r += s[p];
}
if (r == ".") return new Operand(r);
else return new CNumber(r);
}
else if (cat(sc) == 2) {
p++;
for (; s[p] != sc; p++)
r += s[p];
p++;
return new CString(r);
}
else if (cat(sc) == 0) {
for (; p < s.Length; p++) {
if (cat(s[p]) != 0) break;
r += s[p];
}
if (p == s.Length) return new Identifier(r);
if (s[p] == '(') return new Operand(r);
else return new Identifier(r);
}
else if (cat(sc) == 1) {
p++;
return new Operand(sc.ToString());
}
else
throw new Exception(); // TODO
}
protected override object EvalInternal(IEvaluator etor) {
if (type == StackType.Unary) {
if (ostack[0].Priority == OperandPriority.None)
return etor.OperateFunction(ostack[0], estack[0].Eval(etor));
else
return etor.OperateUnary(ostack[0], estack[0].Eval(etor));
}
else {
object r = estack[0].Eval(etor);
for (int i = 0; i < ostack.Count; i++) {
r = etor.OperateBinary(
ostack[i], r, estack[i+1].Eval(etor)
);
}
return r;
}
}
public T Eval<T>(IEvaluator etor) {
return (T)etor.Cast(typeof(T), EvalInternal(etor));
}
protected override object PreEvalInternal(IEvaluator etor, byte depth) {
try { return EvalInternal(etor); }
catch (Exception) {
foreach (var v in estack)
v.PreEval(etor, depth);
throw;
}
}
// 0: Other, 1: Operand, 2: String,
// 3: SOE, 4: EOE, 5: Number
static readonly byte[] ctl = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 2, 1, 0, 1, 1, 2, 3, 4, 1, 1, 1, 1, 5, 1,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
};
static byte cat(char c) {
if (c >> 7 != 0)
return 0;
else
return ctl[c];
}
public override string ToString() {
if (type == StackType.Unary)
return string.Format("{0}{1}", ostack[0], estack[0]);
if (type == StackType.Function)
return string.Format("{0}{1}", ostack[0], estack[0]);
string r = estack[0].ToString();
for (int i = 0; i < ostack.Count; i++) {
r += ostack[i].ToString();
r += estack[i + 1].ToString();
}
if (type == StackType.Bracketed)
r = string.Format("({0})", r);
return r;
}
}
[Obsolete]
public interface IEvaluator {
object ParseNumber(string exp);
object ParseString(string exp);
object EvalIdentifier(string exp);
object OperateUnary(Operand op, object q);
object OperateBinary(Operand op, object q, object r);
object OperateFunction(Operand op, object q);
// TODO [Obsolete]
object Cast(Type type, object obj);
//public abstract Func<Type, object, object> GetCastCallback(Type dest, Type source);
}
#endif
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 688e46fb4d8e6a041844f592f1333af7
timeCreated: 1608801352
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,143 @@
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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0e710eef537a1ac488ef6bce16625b62
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: