using System; namespace Cryville.Common.Pdt { /// /// Span on the memory of a . /// public unsafe struct PdtVariableMemory { readonly byte* _ptr; /// /// The length of the span. /// public int Length { get; private set; } /// /// The type of the span. /// public int Type { get; private set; } internal PdtVariableMemory(int type, byte* ptr, int len) { Type = type; _ptr = ptr; Length = len; } /// /// Copies the memory in the span to a buffer. /// /// The destination buffer. /// The offset on the destination buffer to start copying to. public void CopyTo(byte[] dest, int destOffset) { fixed (byte* ptr = dest) { CopyTo(ptr, destOffset, Length); } } /// /// Copies the memory in the span to a buffer. /// /// The destination buffer. /// The offset on the destination buffer to start copying to. /// The length to copy. public void CopyTo(byte* dest, int destOffset, int length) { for (int i = 0; i < length; i++) dest[destOffset + i] = _ptr[i]; } /// /// Gets the memory of the span as a number. /// /// A number. /// The span does not represent a number. 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; } /// /// Sets the memory of the span to a number. /// /// The number. /// The span does not represent a number. 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]; } /// /// Gets the memory of the span as a string. /// /// The offset on the span to start reading from. /// A string. /// The span at the offset does not represent a string. 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); } /// /// Sets the memory of the span to a string. /// /// The string. /// The offset from the start of the span. /// The span at the offset does not represent a string. /// The length of the span is not sufficient. 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; } /// /// Gets the memory of the span as an undefined identifier. /// /// The offset on the span to start reading from. /// The name of an undefined identifier. /// The span does not represent an undefined identifier. 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; } /// /// Gets the array suffix. /// /// The type of the array. /// The item count of the array. /// The span does not represent an array. 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; } /// /// Sets the array suffix. /// /// The type of the array. /// The item count of the array. /// The span does not represent an array. 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; } } }