parent
c6613679cc
commit
22dd934e95
17 changed files with 20776 additions and 302 deletions
@ -1,3 +1,6 @@ |
|||||||
[submodule "src/flecs-cs"] |
[submodule "src/flecs-cs"] |
||||||
path = src/flecs-cs |
path = src/flecs-cs |
||||||
url = https://github.com/flecs-hub/flecs-cs |
url = https://github.com/flecs-hub/flecs-cs |
||||||
|
[submodule "src/flecs"] |
||||||
|
path = src/flecs |
||||||
|
url = https://github.com/SanderMertens/flecs.git |
||||||
|
@ -0,0 +1,17 @@ |
|||||||
|
{ |
||||||
|
"version": "0.2.0", |
||||||
|
"configurations": [ |
||||||
|
{ |
||||||
|
"name": "Launch BindGen", |
||||||
|
"type": "coreclr", |
||||||
|
"request": "launch", |
||||||
|
"preLaunchTask": "build", |
||||||
|
"env": { "LIBCLANG_DISABLE_CRASH_RECOVERY": "true" }, |
||||||
|
"cwd": "${workspaceFolder}/src/gaemstone.ECS.BindGen", |
||||||
|
"program": "${workspaceFolder}/src/gaemstone.ECS.BindGen/bin/Debug/net7.0/gaemstone.ECS.BindGen.dll", |
||||||
|
"args": [], |
||||||
|
"console": "internalConsole", |
||||||
|
"stopAtEntry": false, |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
{ |
||||||
|
"files.exclude": { |
||||||
|
"**/.git": true, |
||||||
|
"**/.DS_Store": true, |
||||||
|
"**/bin": true, |
||||||
|
"**/obj": true, |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
{ |
||||||
|
"version": "2.0.0", |
||||||
|
"tasks": [ |
||||||
|
{ |
||||||
|
"group": "build", |
||||||
|
"label": "build", |
||||||
|
"type": "shell", "command": "dotnet", |
||||||
|
"options": { "cwd": "src/gaemstone.ECS.BindGen" }, |
||||||
|
"args": [ "build", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], |
||||||
|
"presentation": { "reveal": "silent" }, |
||||||
|
"problemMatcher": "$msCompile" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1 @@ |
|||||||
|
Subproject commit ddf4dfc8d0b09eec42876ea06f5f42849a0c23be |
@ -0,0 +1,421 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.IO; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using ClangSharp.Interop; |
||||||
|
|
||||||
|
namespace gaemstone.ECS.BindGen; |
||||||
|
|
||||||
|
public unsafe static class Program |
||||||
|
{ |
||||||
|
// TODO: Handle being called from other working directories gracefully. |
||||||
|
private const string FlecsRepositoryLocation = "../flecs"; |
||||||
|
private const string OutputFolderLocation = "../gaemstone.ECS/flecs"; |
||||||
|
|
||||||
|
private static readonly Dictionary<string, string> TypeAliases = new() { |
||||||
|
{ "int8_t" , "sbyte" }, |
||||||
|
{ "int16_t", "short" }, |
||||||
|
{ "int32_t", "int" }, |
||||||
|
{ "int64_t", "long" }, |
||||||
|
|
||||||
|
{ "uint8_t" , "byte" }, |
||||||
|
{ "uint16_t", "ushort" }, |
||||||
|
{ "uint32_t", "uint" }, |
||||||
|
{ "uint64_t", "ulong" }, |
||||||
|
|
||||||
|
{ "ecs_flags8_t" , "byte" }, |
||||||
|
{ "ecs_flags16_t", "ushort" }, |
||||||
|
{ "ecs_flags32_t", "uint" }, |
||||||
|
{ "ecs_flags64_t", "ulong" }, |
||||||
|
|
||||||
|
{ "ecs_size_t", "int" }, |
||||||
|
}; |
||||||
|
|
||||||
|
public static void Main() |
||||||
|
{ |
||||||
|
using var fileConstants = File.CreateText(Path.Combine(OutputFolderLocation, "flecs+Constants.g.cs")); |
||||||
|
using var fileStructs = File.CreateText(Path.Combine(OutputFolderLocation, "flecs+Structs.g.cs")); |
||||||
|
using var fileFunctions = File.CreateText(Path.Combine(OutputFolderLocation, "flecs+Functions.g.cs")); |
||||||
|
|
||||||
|
static string StartProcessAndReturnOutput(string program, string arguments, string workDir = "") |
||||||
|
{ |
||||||
|
var gitProcess = new Process { StartInfo = new() { |
||||||
|
FileName = "git", Arguments = "describe --tags --always", WorkingDirectory = workDir, |
||||||
|
RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true, |
||||||
|
} }; |
||||||
|
gitProcess.Start(); |
||||||
|
var result = gitProcess.StandardOutput.ReadToEnd().Trim(); |
||||||
|
gitProcess.WaitForExit(); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
var bindgenVersion = StartProcessAndReturnOutput("git", "describe --tags --always"); |
||||||
|
var flecsVersion = StartProcessAndReturnOutput("git", "describe --tags --always", FlecsRepositoryLocation); |
||||||
|
|
||||||
|
var autoGeneratedHeader = $$"""
|
||||||
|
// <auto-generated> |
||||||
|
// Generated by gaemstone.ECS.BindGen {{ bindgenVersion }} |
||||||
|
// Time: {{ DateTime.UtcNow :u}} |
||||||
|
// Flecs version: {{ flecsVersion }} |
||||||
|
// </auto-generated> |
||||||
|
""";
|
||||||
|
|
||||||
|
fileConstants.WriteLine($$"""
|
||||||
|
{{ autoGeneratedHeader }} |
||||||
|
|
||||||
|
#pragma warning disable CS8981 |
||||||
|
public static partial class flecs |
||||||
|
{ |
||||||
|
""");
|
||||||
|
|
||||||
|
fileStructs.Write($$"""
|
||||||
|
{{ autoGeneratedHeader }} |
||||||
|
|
||||||
|
using System.Runtime.InteropServices; |
||||||
|
|
||||||
|
#pragma warning disable CS8981 |
||||||
|
public static unsafe partial class flecs |
||||||
|
{ |
||||||
|
""");
|
||||||
|
|
||||||
|
fileFunctions.WriteLine($$"""
|
||||||
|
{{ autoGeneratedHeader }} |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Runtime.InteropServices; |
||||||
|
|
||||||
|
#pragma warning disable CS8981 |
||||||
|
public static unsafe partial class flecs |
||||||
|
{ |
||||||
|
private const string LibraryName = "flecs"; |
||||||
|
|
||||||
|
/// <summary> Indicates types are marked as "const" on C's end. </summary> |
||||||
|
[AttributeUsage(AttributeTargets.Parameter, AttributeTargets.ReturnValue)] |
||||||
|
public class ConstAttribute : Attribute { } |
||||||
|
""");
|
||||||
|
|
||||||
|
using var unit = CXTranslationUnit.CreateFromSourceFile( |
||||||
|
CXIndex.Create(), Path.Combine(FlecsRepositoryLocation, "flecs.h"), |
||||||
|
default, default); |
||||||
|
|
||||||
|
unit.Cursor.VisitChildren((cursor, _, _) => { |
||||||
|
switch (cursor) { |
||||||
|
case { Location.IsFromMainFile: false }: // Not from the file we're trying to parse. |
||||||
|
case { Kind: CXCursorKind.CXCursor_MacroInstantiation |
||||||
|
or CXCursorKind.CXCursor_InclusionDirective }: // Ignore these altogether. |
||||||
|
break; |
||||||
|
|
||||||
|
case { Kind: CXCursorKind.CXCursor_MacroDefinition }: |
||||||
|
WriteMacro(fileConstants, 1, cursor); |
||||||
|
break; |
||||||
|
|
||||||
|
// case { Kind: CXCursorKind.CXCursor_TypedefDecl }: |
||||||
|
// WriteTypedef(cursor, output); |
||||||
|
// break; |
||||||
|
|
||||||
|
case { Kind: CXCursorKind.CXCursor_EnumDecl }: |
||||||
|
fileStructs.WriteLine(); |
||||||
|
WriteEnum(fileStructs, 1, cursor); |
||||||
|
break; |
||||||
|
|
||||||
|
case { Kind: CXCursorKind.CXCursor_StructDecl }: |
||||||
|
// Skip forward declarations, unless they're not defined at all. |
||||||
|
if (!cursor.IsDefinition && !cursor.Definition.IsNull) break; |
||||||
|
fileStructs.WriteLine(); |
||||||
|
WriteStruct(fileStructs, 1, cursor); |
||||||
|
break; |
||||||
|
|
||||||
|
case { Kind: CXCursorKind.CXCursor_FunctionDecl }: |
||||||
|
fileFunctions.WriteLine(); |
||||||
|
WriteFunction(fileFunctions, 1, cursor); |
||||||
|
break; |
||||||
|
|
||||||
|
default: |
||||||
|
Console.WriteLine($"{cursor.Kind} {cursor}"); |
||||||
|
Console.WriteLine(GetSource(unit, cursor.Extent)); |
||||||
|
break; |
||||||
|
} |
||||||
|
return CXChildVisitResult.CXChildVisit_Continue; |
||||||
|
}, default); |
||||||
|
|
||||||
|
fileConstants.WriteLine("}"); |
||||||
|
fileStructs .WriteLine("}"); |
||||||
|
fileFunctions.WriteLine("}"); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private static void WriteMacro(StreamWriter writer, int indent, CXCursor cursor) |
||||||
|
{ |
||||||
|
if (cursor.IsMacroFunctionLike) return; |
||||||
|
var unit = cursor.TranslationUnit; |
||||||
|
var tokens = unit.Tokenize(cursor.Extent).ToArray(); |
||||||
|
if (tokens.Length < 2) return; // No value. |
||||||
|
|
||||||
|
var type = "uint"; |
||||||
|
var name = cursor.Spelling.ToString(); |
||||||
|
if (name is "NULL" or "ECS_VECTOR_T_SIZE" |
||||||
|
or "EcsLastInternalComponentId" |
||||||
|
or "ECS_FUNC_NAME_BACK") return; |
||||||
|
|
||||||
|
var value = GetSource(unit, Range(unit, tokens[1], tokens[^1])); |
||||||
|
if (value is not [ '(', .., ')']) return; |
||||||
|
if (value.Contains('\\')) value = value.Replace("\\\n", "").Replace(" ", ""); |
||||||
|
if (value.Contains("ull")) { value = value.Replace("ull", "ul"); type = "ulong"; } |
||||||
|
if (name == "ECS_MAX_COMPONENT_ID") value = value.Replace("(uint32_t)", "(uint)"); |
||||||
|
|
||||||
|
WriteComment(writer, indent, cursor); |
||||||
|
WriteIndent(writer, indent).WriteLine($"public const {type} {name} = {value};"); |
||||||
|
} |
||||||
|
|
||||||
|
private static void WriteEnum(StreamWriter writer, int indent, CXCursor cursor) |
||||||
|
{ |
||||||
|
WriteComment(writer, indent, cursor); |
||||||
|
|
||||||
|
WriteIndent(writer, indent).WriteLine($"public {cursor.Type}"); |
||||||
|
WriteIndent(writer, indent).WriteLine("{"); |
||||||
|
|
||||||
|
cursor.VisitChildren((value, _, _) => { |
||||||
|
WriteComment(writer, indent + 1, value); |
||||||
|
WriteIndent(writer, indent + 1).WriteLine($"{value},"); |
||||||
|
return CXChildVisitResult.CXChildVisit_Continue; |
||||||
|
}, default); |
||||||
|
|
||||||
|
WriteIndent(writer, indent).WriteLine("}"); |
||||||
|
} |
||||||
|
|
||||||
|
private static void WriteStruct(StreamWriter writer, int indent, CXCursor cursor, |
||||||
|
string? name = null, bool noComment = false) |
||||||
|
{ |
||||||
|
if (!noComment) WriteComment(writer, indent, cursor); |
||||||
|
|
||||||
|
if (cursor.Kind == CXCursorKind.CXCursor_UnionDecl) |
||||||
|
WriteIndent(writer, indent).WriteLine("[StructLayout(LayoutKind.Explicit)]"); |
||||||
|
|
||||||
|
name ??= cursor.Type.ToString(); |
||||||
|
if (name.StartsWith("struct ")) name = name[("struct ".Length)..]; |
||||||
|
WriteIndent(writer, indent).Write($"public struct {name}"); |
||||||
|
|
||||||
|
var hasFields = false; // For creating a shorthand struct definition that doesn't take up 3 lines. |
||||||
|
cursor.VisitChildren((field, _, _) => { |
||||||
|
// Nested struct and union declarations will be handled when field is written. |
||||||
|
if (field.Kind is CXCursorKind.CXCursor_StructDecl |
||||||
|
or CXCursorKind.CXCursor_UnionDecl) |
||||||
|
return CXChildVisitResult.CXChildVisit_Continue; |
||||||
|
|
||||||
|
if (field.Kind is not CXCursorKind.CXCursor_FieldDecl) |
||||||
|
throw new NotSupportedException(); |
||||||
|
|
||||||
|
if (!hasFields) { |
||||||
|
writer.WriteLine(); |
||||||
|
WriteIndent(writer, indent).WriteLine("{"); |
||||||
|
hasFields = true; |
||||||
|
} |
||||||
|
|
||||||
|
if (cursor.Kind == CXCursorKind.CXCursor_UnionDecl) |
||||||
|
WriteIndent(writer, indent).WriteLine("[FieldOffset(0)]"); |
||||||
|
|
||||||
|
WriteComment(writer, indent + 1, field); |
||||||
|
WriteIndent(writer, indent + 1); |
||||||
|
|
||||||
|
var name = field.DisplayName.ToString(); |
||||||
|
if (IsReservedKeyword(name)) name = $"@{name}"; |
||||||
|
|
||||||
|
if (field.Type.Declaration.IsAnonymous) { |
||||||
|
writer.WriteLine($"public _{field.DisplayName} {name};"); |
||||||
|
WriteStruct(writer, indent + 1, field.Type.Declaration, |
||||||
|
name: $"_{field.DisplayName}", noComment: true); |
||||||
|
} else if (field.Type.kind == CXTypeKind.CXType_ConstantArray) { |
||||||
|
writer.WriteLine($"public fixed {field.Type.ArrayElementType} {name}[{field.Type.ArraySize}];"); |
||||||
|
} else { |
||||||
|
var type = GetTypeString(field.Type, out var isConst); |
||||||
|
if (isConst) writer.Write($"[Const] "); |
||||||
|
writer.WriteLine($"public {type} {name};"); |
||||||
|
} |
||||||
|
|
||||||
|
return CXChildVisitResult.CXChildVisit_Continue; |
||||||
|
}, default); |
||||||
|
if (!hasFields) writer.WriteLine(" { }"); |
||||||
|
else WriteIndent(writer, indent).WriteLine("}"); |
||||||
|
} |
||||||
|
|
||||||
|
private static void WriteFunction(StreamWriter writer, int indent, CXCursor cursor) |
||||||
|
{ |
||||||
|
WriteComment(writer, indent, cursor); |
||||||
|
|
||||||
|
var returnType = GetTypeString(cursor.ReturnType, out var returnIsConst); |
||||||
|
if (returnIsConst) WriteIndent(writer, indent).WriteLine("[return: Const]"); |
||||||
|
WriteIndent(writer, indent).WriteLine("[DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]"); |
||||||
|
WriteIndent(writer, indent).Write($"public static extern {returnType} {cursor.Spelling}("); |
||||||
|
|
||||||
|
for (var i = 0; i < cursor.NumArguments; i++) { |
||||||
|
var arg = cursor.GetArgument((uint)i); |
||||||
|
if (i > 0) writer.Write(", "); |
||||||
|
|
||||||
|
var argType = GetTypeString(arg.Type, out var argIsConst); |
||||||
|
if (argIsConst) writer.Write("[Const] "); |
||||||
|
var name = arg.DisplayName.ToString(); |
||||||
|
if (IsReservedKeyword(name)) name = $"@{name}"; |
||||||
|
writer.Write($"{argType} {name}"); |
||||||
|
} |
||||||
|
|
||||||
|
writer.WriteLine(");"); |
||||||
|
} |
||||||
|
|
||||||
|
private static void WriteComment(StreamWriter writer, int indent, CXCursor cursor) |
||||||
|
{ |
||||||
|
var comment = cursor.ParsedComment; |
||||||
|
if (comment.Kind == CXCommentKind.CXComment_Null) return; |
||||||
|
if (comment.Kind != CXCommentKind.CXComment_FullComment) throw new NotSupportedException(); |
||||||
|
|
||||||
|
var children = Children(comment).ToArray(); |
||||||
|
var paragraphs = children |
||||||
|
.TakeWhile(c => c.Kind == CXCommentKind.CXComment_Paragraph) |
||||||
|
.Select(GetCommentText).Where(p => p != null).ToArray(); |
||||||
|
var @params = children |
||||||
|
.Where (c => c.Kind == CXCommentKind.CXComment_ParamCommand) |
||||||
|
.Select(c => (c.ParamCommandComment_ParamName, GetCommentText(Children(c).Single()))).ToArray(); |
||||||
|
var @return = children |
||||||
|
.Where (c => c.Kind == CXCommentKind.CXComment_BlockCommand) |
||||||
|
.Where (c => c.BlockCommandComment_CommandName.ToString() == "return") |
||||||
|
.Select(c => GetCommentText(Children(c).Single())).FirstOrDefault(); |
||||||
|
|
||||||
|
if (paragraphs.Length > 1) { |
||||||
|
WriteIndent(writer, indent).WriteLine($"/// <summary>"); |
||||||
|
foreach (var paragraph in paragraphs) |
||||||
|
WriteIndent(writer, indent).WriteLine($"/// <p> {paragraph} </p>"); |
||||||
|
WriteIndent(writer, indent).WriteLine($"/// </summary>"); |
||||||
|
} else if (paragraphs.Length == 1) |
||||||
|
WriteIndent(writer, indent).WriteLine($"/// <summary> {paragraphs[0]} </summary>"); |
||||||
|
|
||||||
|
foreach (var (name, text) in @params) |
||||||
|
WriteIndent(writer, indent).WriteLine($$"""/// <param name="{{ name }}"> {{ text }} </param>"""); |
||||||
|
|
||||||
|
if (@return != null) |
||||||
|
WriteIndent(writer, indent).WriteLine($$"""/// <returns> {{ @return }} </returns>"""); |
||||||
|
|
||||||
|
foreach (var child in Children(comment)) |
||||||
|
switch (child.Kind) { |
||||||
|
case CXCommentKind.CXComment_Paragraph: |
||||||
|
case CXCommentKind.CXComment_ParamCommand: |
||||||
|
case CXCommentKind.CXComment_BlockCommand when child.BlockCommandComment_CommandName.ToString() == "return": |
||||||
|
break; |
||||||
|
default: |
||||||
|
WriteIndent(writer, indent); |
||||||
|
writer.WriteLine($"//// {child.Kind}"); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
static IEnumerable<CXComment> Children(CXComment parent) |
||||||
|
=> Enumerable.Range(0, (int)parent.NumChildren).Select(i => parent.GetChild((uint)i)); |
||||||
|
|
||||||
|
static string? GetCommentText(CXComment paragraph) |
||||||
|
{ |
||||||
|
if (paragraph.Kind != CXCommentKind.CXComment_Paragraph) throw new NotSupportedException(); |
||||||
|
var sb = new StringBuilder(); |
||||||
|
foreach (var part in Children(paragraph)) { |
||||||
|
if (part.Kind != CXCommentKind.CXComment_Text) throw new NotSupportedException(); |
||||||
|
var str = part.TextComment_Text.ToString().Trim(); |
||||||
|
if (str == "") continue; |
||||||
|
if (sb.Length > 0) sb.Append(' '); |
||||||
|
sb.Append(str); |
||||||
|
} |
||||||
|
if (sb.Length == 0) return null; |
||||||
|
sb.Replace("<", "<").Replace(">", ">"); |
||||||
|
if (sb[^1] != '.') sb.Append('.'); |
||||||
|
return sb.ToString(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static StreamWriter WriteIndent(StreamWriter writer, int indent) |
||||||
|
{ |
||||||
|
for (var i = 0; i < indent; i++) |
||||||
|
writer.Write('\t'); |
||||||
|
return writer; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private static CXSourceRange Range(CXTranslationUnit unit, CXToken start, CXToken end) |
||||||
|
=> CXSourceRange.Create(start.GetExtent(unit).Start, end.GetExtent(unit).End); |
||||||
|
|
||||||
|
private static string GetTypeString(CXType type, out bool isConst) |
||||||
|
{ |
||||||
|
isConst = false; |
||||||
|
switch (type) { |
||||||
|
case { kind: CXTypeKind.CXType_Pointer, |
||||||
|
PointeeType: { kind: CXTypeKind.CXType_FunctionProto } funcType }: |
||||||
|
var resultType = GetTypeString(funcType.ResultType, out _); |
||||||
|
var argTypes = Enumerable.Range(0, funcType.NumArgTypes) |
||||||
|
.Select(i => funcType.GetArgType((uint)i)) |
||||||
|
.Select(a => GetTypeString(a, out _)) |
||||||
|
.ToArray(); |
||||||
|
return $"delegate* unmanaged<{string.Join(", ", argTypes)}, {resultType}>"; |
||||||
|
|
||||||
|
case { kind: CXTypeKind.CXType_Pointer, |
||||||
|
PointeeType: { kind: CXTypeKind.CXType_Elaborated, |
||||||
|
Declaration.IsDefined: false} }: |
||||||
|
return "void*"; |
||||||
|
|
||||||
|
case { kind: CXTypeKind.CXType_Pointer }: |
||||||
|
return GetTypeString(type.PointeeType, out isConst) + "*"; |
||||||
|
|
||||||
|
case { kind: CXTypeKind.CXType_VariableArray |
||||||
|
or CXTypeKind.CXType_IncompleteArray }: |
||||||
|
return GetTypeString(type.ArrayElementType, out isConst) + "[]"; |
||||||
|
|
||||||
|
case { kind: CXTypeKind.CXType_Record }: |
||||||
|
throw new NotSupportedException(); |
||||||
|
|
||||||
|
case { kind: CXTypeKind.CXType_Elaborated }: |
||||||
|
var name = type.Declaration.ToString(); |
||||||
|
if (name == "") throw new Exception(); |
||||||
|
return name; |
||||||
|
|
||||||
|
case { kind: CXTypeKind.CXType_FunctionProto }: |
||||||
|
throw new NotSupportedException(); |
||||||
|
|
||||||
|
default: |
||||||
|
name = type.ToString(); |
||||||
|
if (name == "") throw new Exception(); |
||||||
|
if (type.IsConstQualified) { |
||||||
|
if (!name.StartsWith("const ")) throw new Exception(); |
||||||
|
name = name[("const ".Length)..]; |
||||||
|
isConst = true; |
||||||
|
} |
||||||
|
if (name.Contains(' ')) throw new Exception(); |
||||||
|
if (TypeAliases.TryGetValue(name, out var alias)) name = alias; |
||||||
|
return name; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static string GetSource(CXTranslationUnit unit, CXSourceRange range) |
||||||
|
{ |
||||||
|
range.Start.GetFileLocation(out var startFile, out _, out _, out var start); |
||||||
|
range.End .GetFileLocation(out var endFile , out _, out _, out var end); |
||||||
|
if (startFile != endFile) return string.Empty; |
||||||
|
return Encoding.UTF8.GetString( |
||||||
|
unit.GetFileContents(startFile, out _) |
||||||
|
.Slice((int)start, (int)(end - start))); |
||||||
|
} |
||||||
|
|
||||||
|
// See https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ |
||||||
|
// Reserved keywords are unlikely to change in future C# versions, as they'd break |
||||||
|
// existing programs. New ones are instead added as contextual keywords. |
||||||
|
private static bool IsReservedKeyword(string str) |
||||||
|
=> str is "abstract" or "as" or "base" or "bool" or "break" or "byte" |
||||||
|
or "case" or "catch" or "char" or "checked" or "class" |
||||||
|
or "const" or "continue" or "decimal" or "default" |
||||||
|
or "delegate" or "do" or "double" or "else" or "enum" |
||||||
|
or "event" or "explicit" or "extern" or "false" or "finally" |
||||||
|
or "fixed" or "float" or "for" or "foreach" or "goto" or "if" |
||||||
|
or "implicit" or "in" or "int" or "interface" or "internal" |
||||||
|
or "is" or "lock" or "long" or "namespace" or "new" or "null" |
||||||
|
or "object" or "operator" or "out" or "override" or "params" |
||||||
|
or "private" or "protected" or "public" or "readonly" or "ref" |
||||||
|
or "return" or "sbyte" or "sealed" or "short" or"sizeof" |
||||||
|
or "stackalloc" or "static" or "string" or "struct" or "switch" |
||||||
|
or "this" or "throw" or "true" or "try" or "typeof" or "uint" |
||||||
|
or "ulong" or "unchecked" or "unsafe" or "ushort" or "using" |
||||||
|
or "virtual" or "void" or "volatile" or "while"; |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<OutputType>Exe</OutputType> |
||||||
|
<LangVersion>preview</LangVersion> |
||||||
|
<TargetFramework>net7.0</TargetFramework> |
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> |
||||||
|
<ImplicitUsings>disable</ImplicitUsings> |
||||||
|
<Nullable>enable</Nullable> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<RuntimeIdentifier>ubuntu.22.04-x64</RuntimeIdentifier> |
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="ClangSharp" Version="15.0.2" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
</Project> |
@ -0,0 +1,182 @@ |
|||||||
|
// <auto-generated> |
||||||
|
// Generated by gaemstone.ECS.BindGen c661367 |
||||||
|
// Time: 2023-01-09 18:48:29Z |
||||||
|
// Flecs version: v3.1.3 |
||||||
|
// </auto-generated> |
||||||
|
|
||||||
|
#pragma warning disable CS8981 |
||||||
|
public static partial class flecs |
||||||
|
{ |
||||||
|
public const uint ECS_ID_CACHE_SIZE = (32); |
||||||
|
public const uint ECS_TERM_DESC_CACHE_SIZE = (16); |
||||||
|
public const uint ECS_OBSERVER_DESC_EVENT_COUNT_MAX = (8); |
||||||
|
public const uint ECS_VARIABLE_COUNT_MAX = (64); |
||||||
|
public const uint EcsWorldQuitWorkers = (1u << 0); |
||||||
|
public const uint EcsWorldReadonly = (1u << 1); |
||||||
|
public const uint EcsWorldQuit = (1u << 2); |
||||||
|
public const uint EcsWorldFini = (1u << 3); |
||||||
|
public const uint EcsWorldMeasureFrameTime = (1u << 4); |
||||||
|
public const uint EcsWorldMeasureSystemTime = (1u << 5); |
||||||
|
public const uint EcsWorldMultiThreaded = (1u << 6); |
||||||
|
public const uint EcsOsApiHighResolutionTimer = (1u << 0); |
||||||
|
public const uint EcsOsApiLogWithColors = (1u << 1); |
||||||
|
public const uint EcsOsApiLogWithTimeStamp = (1u << 2); |
||||||
|
public const uint EcsOsApiLogWithTimeDelta = (1u << 3); |
||||||
|
public const uint EcsEntityObserved = (1u << 31); |
||||||
|
public const uint EcsEntityObservedId = (1u << 30); |
||||||
|
public const uint EcsEntityObservedTarget = (1u << 29); |
||||||
|
public const uint EcsEntityObservedAcyclic = (1u << 28); |
||||||
|
public const uint EcsIdOnDeleteRemove = (1u << 0); |
||||||
|
public const uint EcsIdOnDeleteDelete = (1u << 1); |
||||||
|
public const uint EcsIdOnDeletePanic = (1u << 2); |
||||||
|
public const uint EcsIdOnDeleteMask = (EcsIdOnDeletePanic|EcsIdOnDeleteRemove|EcsIdOnDeleteDelete); |
||||||
|
public const uint EcsIdOnDeleteObjectRemove = (1u << 3); |
||||||
|
public const uint EcsIdOnDeleteObjectDelete = (1u << 4); |
||||||
|
public const uint EcsIdOnDeleteObjectPanic = (1u << 5); |
||||||
|
public const uint EcsIdOnDeleteObjectMask = (EcsIdOnDeleteObjectPanic|EcsIdOnDeleteObjectRemove|EcsIdOnDeleteObjectDelete); |
||||||
|
public const uint EcsIdExclusive = (1u << 6); |
||||||
|
public const uint EcsIdDontInherit = (1u << 7); |
||||||
|
public const uint EcsIdAcyclic = (1u << 8); |
||||||
|
public const uint EcsIdTag = (1u << 9); |
||||||
|
public const uint EcsIdWith = (1u << 10); |
||||||
|
public const uint EcsIdUnion = (1u << 11); |
||||||
|
public const uint EcsIdHasOnAdd = (1u << 15); |
||||||
|
public const uint EcsIdHasOnRemove = (1u << 16); |
||||||
|
public const uint EcsIdHasOnSet = (1u << 17); |
||||||
|
public const uint EcsIdHasUnSet = (1u << 18); |
||||||
|
public const uint EcsIdEventMask = (EcsIdHasOnAdd|EcsIdHasOnRemove|EcsIdHasOnSet|EcsIdHasUnSet); |
||||||
|
public const uint EcsIdMarkedForDelete = (1u << 30); |
||||||
|
public const uint EcsIterIsValid = (1u << 0u); |
||||||
|
public const uint EcsIterIsFilter = (1u << 1u); |
||||||
|
public const uint EcsIterIsInstanced = (1u << 2u); |
||||||
|
public const uint EcsIterHasShared = (1u << 3u); |
||||||
|
public const uint EcsIterTableOnly = (1u << 4u); |
||||||
|
public const uint EcsIterEntityOptional = (1u << 5u); |
||||||
|
public const uint EcsIterNoResults = (1u << 6u); |
||||||
|
public const uint EcsIterIgnoreThis = (1u << 7u); |
||||||
|
public const uint EcsIterMatchVar = (1u << 8u); |
||||||
|
public const uint EcsEventTableOnly = (1u << 8u); |
||||||
|
public const uint EcsEventNoOnSet = (1u << 16u); |
||||||
|
public const uint EcsFilterMatchThis = (1u << 1u); |
||||||
|
public const uint EcsFilterMatchOnlyThis = (1u << 2u); |
||||||
|
public const uint EcsFilterMatchPrefab = (1u << 3u); |
||||||
|
public const uint EcsFilterMatchDisabled = (1u << 4u); |
||||||
|
public const uint EcsFilterMatchEmptyTables = (1u << 5u); |
||||||
|
public const uint EcsFilterMatchAnything = (1u << 6u); |
||||||
|
public const uint EcsFilterIsFilter = (1u << 7u); |
||||||
|
public const uint EcsFilterIsInstanced = (1u << 8u); |
||||||
|
public const uint EcsFilterPopulate = (1u << 9u); |
||||||
|
public const uint EcsTableHasBuiltins = (1u << 1u); |
||||||
|
public const uint EcsTableIsPrefab = (1u << 2u); |
||||||
|
public const uint EcsTableHasIsA = (1u << 3u); |
||||||
|
public const uint EcsTableHasChildOf = (1u << 4u); |
||||||
|
public const uint EcsTableHasPairs = (1u << 5u); |
||||||
|
public const uint EcsTableHasModule = (1u << 6u); |
||||||
|
public const uint EcsTableIsDisabled = (1u << 7u); |
||||||
|
public const uint EcsTableHasCtors = (1u << 8u); |
||||||
|
public const uint EcsTableHasDtors = (1u << 9u); |
||||||
|
public const uint EcsTableHasCopy = (1u << 10u); |
||||||
|
public const uint EcsTableHasMove = (1u << 11u); |
||||||
|
public const uint EcsTableHasUnion = (1u << 12u); |
||||||
|
public const uint EcsTableHasToggle = (1u << 13u); |
||||||
|
public const uint EcsTableHasOverrides = (1u << 14u); |
||||||
|
public const uint EcsTableHasOnAdd = (1u << 15u); |
||||||
|
public const uint EcsTableHasOnRemove = (1u << 16u); |
||||||
|
public const uint EcsTableHasOnSet = (1u << 17u); |
||||||
|
public const uint EcsTableHasUnSet = (1u << 18u); |
||||||
|
public const uint EcsTableHasObserved = (1u << 20u); |
||||||
|
public const uint EcsTableMarkedForDelete = (1u << 30u); |
||||||
|
public const uint EcsTableHasLifecycle = (EcsTableHasCtors | EcsTableHasDtors); |
||||||
|
public const uint EcsTableIsComplex = (EcsTableHasLifecycle | EcsTableHasUnion | EcsTableHasToggle); |
||||||
|
public const uint EcsTableHasAddActions = (EcsTableHasIsA | EcsTableHasUnion | EcsTableHasCtors | EcsTableHasOnAdd | EcsTableHasOnSet); |
||||||
|
public const uint EcsTableHasRemoveActions = (EcsTableHasIsA | EcsTableHasDtors | EcsTableHasOnRemove | EcsTableHasUnSet); |
||||||
|
public const uint EcsQueryHasRefs = (1u << 1u); |
||||||
|
public const uint EcsQueryIsSubquery = (1u << 2u); |
||||||
|
public const uint EcsQueryIsOrphaned = (1u << 3u); |
||||||
|
public const uint EcsQueryHasOutColumns = (1u << 4u); |
||||||
|
public const uint EcsQueryHasMonitor = (1u << 5u); |
||||||
|
public const uint EcsAperiodicEmptyTables = (1u << 1u); |
||||||
|
public const uint EcsAperiodicComponentMonitors = (1u << 2u); |
||||||
|
public const uint EcsAperiodicEmptyQueries = (1u << 4u); |
||||||
|
public const uint ecs_world_t_magic = (0x65637377); |
||||||
|
public const uint ecs_stage_t_magic = (0x65637373); |
||||||
|
public const uint ecs_query_t_magic = (0x65637371); |
||||||
|
public const uint ecs_rule_t_magic = (0x65637375); |
||||||
|
public const uint ecs_table_t_magic = (0x65637374); |
||||||
|
public const uint ecs_filter_t_magic = (0x65637366); |
||||||
|
public const uint ecs_trigger_t_magic = (0x65637372); |
||||||
|
public const uint ecs_observer_t_magic = (0x65637362); |
||||||
|
public const uint ECS_ROW_MASK = (0x0FFFFFFFu); |
||||||
|
public const uint ECS_ROW_FLAGS_MASK = (~ECS_ROW_MASK); |
||||||
|
public const ulong ECS_ID_FLAGS_MASK = (0xFFul << 60); |
||||||
|
public const ulong ECS_ENTITY_MASK = (0xFFFFFFFFul); |
||||||
|
public const ulong ECS_GENERATION_MASK = (0xFFFFul << 32); |
||||||
|
public const uint ECS_COMPONENT_MASK = (~ECS_ID_FLAGS_MASK); |
||||||
|
public const uint FLECS_SPARSE_CHUNK_SIZE = (4096); |
||||||
|
public const uint ECS_STRBUF_ELEMENT_SIZE = (511); |
||||||
|
public const uint ECS_STRBUF_MAX_LIST_DEPTH = (32); |
||||||
|
public const uint EcsSelf = (1u << 1); |
||||||
|
public const uint EcsUp = (1u << 2); |
||||||
|
public const uint EcsDown = (1u << 3); |
||||||
|
public const uint EcsTraverseAll = (1u << 4); |
||||||
|
public const uint EcsCascade = (1u << 5); |
||||||
|
public const uint EcsParent = (1u << 6); |
||||||
|
public const uint EcsIsVariable = (1u << 7); |
||||||
|
public const uint EcsIsEntity = (1u << 8); |
||||||
|
public const uint EcsFilter = (1u << 9); |
||||||
|
public const uint EcsTraverseFlags = (EcsUp|EcsDown|EcsTraverseAll|EcsSelf|EcsCascade|EcsParent); |
||||||
|
public const uint flecs_iter_cache_ids = (1u << 0u); |
||||||
|
public const uint flecs_iter_cache_columns = (1u << 1u); |
||||||
|
public const uint flecs_iter_cache_sources = (1u << 2u); |
||||||
|
public const uint flecs_iter_cache_sizes = (1u << 3u); |
||||||
|
public const uint flecs_iter_cache_ptrs = (1u << 4u); |
||||||
|
public const uint flecs_iter_cache_match_indices = (1u << 5u); |
||||||
|
public const uint flecs_iter_cache_variables = (1u << 6u); |
||||||
|
public const uint flecs_iter_cache_all = (255); |
||||||
|
public const uint ECS_HI_COMPONENT_ID = (256); |
||||||
|
public const uint ECS_MAX_COMPONENT_ID = (~((uint)(ECS_ID_FLAGS_MASK >> 32))); |
||||||
|
public const uint ECS_MAX_RECURSION = (512); |
||||||
|
public const uint ECS_MAX_TOKEN_SIZE = (256); |
||||||
|
public const ulong ECS_ID_FLAG_BIT = (1ul << 63); |
||||||
|
public const uint EcsFirstUserComponentId = (32); |
||||||
|
public const uint EcsFirstUserEntityId = (ECS_HI_COMPONENT_ID + 128); |
||||||
|
public const uint ECS_INVALID_OPERATION = (1); |
||||||
|
public const uint ECS_INVALID_PARAMETER = (2); |
||||||
|
public const uint ECS_CONSTRAINT_VIOLATED = (3); |
||||||
|
public const uint ECS_OUT_OF_MEMORY = (4); |
||||||
|
public const uint ECS_OUT_OF_RANGE = (5); |
||||||
|
public const uint ECS_UNSUPPORTED = (6); |
||||||
|
public const uint ECS_INTERNAL_ERROR = (7); |
||||||
|
public const uint ECS_ALREADY_DEFINED = (8); |
||||||
|
public const uint ECS_MISSING_OS_API = (9); |
||||||
|
public const uint ECS_OPERATION_FAILED = (10); |
||||||
|
public const uint ECS_INVALID_CONVERSION = (11); |
||||||
|
public const uint ECS_ID_IN_USE = (12); |
||||||
|
public const uint ECS_CYCLE_DETECTED = (13); |
||||||
|
public const uint ECS_LEAK_DETECTED = (14); |
||||||
|
public const uint ECS_INCONSISTENT_NAME = (20); |
||||||
|
public const uint ECS_NAME_IN_USE = (21); |
||||||
|
public const uint ECS_NOT_A_COMPONENT = (22); |
||||||
|
public const uint ECS_INVALID_COMPONENT_SIZE = (23); |
||||||
|
public const uint ECS_INVALID_COMPONENT_ALIGNMENT = (24); |
||||||
|
public const uint ECS_COMPONENT_NOT_REGISTERED = (25); |
||||||
|
public const uint ECS_INCONSISTENT_COMPONENT_ID = (26); |
||||||
|
public const uint ECS_INCONSISTENT_COMPONENT_ACTION = (27); |
||||||
|
public const uint ECS_MODULE_UNDEFINED = (28); |
||||||
|
public const uint ECS_MISSING_SYMBOL = (29); |
||||||
|
public const uint ECS_ALREADY_IN_USE = (30); |
||||||
|
public const uint ECS_ACCESS_VIOLATION = (40); |
||||||
|
public const uint ECS_COLUMN_INDEX_OUT_OF_RANGE = (41); |
||||||
|
public const uint ECS_COLUMN_IS_NOT_SHARED = (42); |
||||||
|
public const uint ECS_COLUMN_IS_SHARED = (43); |
||||||
|
public const uint ECS_COLUMN_TYPE_MISMATCH = (45); |
||||||
|
public const uint ECS_INVALID_WHILE_READONLY = (70); |
||||||
|
public const uint ECS_LOCKED_STORAGE = (71); |
||||||
|
public const uint ECS_INVALID_FROM_WORKER = (72); |
||||||
|
public const uint ECS_REST_DEFAULT_PORT = (27750); |
||||||
|
public const uint ECS_STAT_WINDOW = (60); |
||||||
|
public const uint ECS_MEMBER_DESC_CACHE_SIZE = (32); |
||||||
|
public const uint ECS_META_MAX_SCOPE_DEPTH = (32); |
||||||
|
public const uint ECS_HTTP_HEADER_COUNT_MAX = (32); |
||||||
|
public const uint ECS_HTTP_QUERY_PARAM_COUNT_MAX = (32); |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,171 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Runtime.CompilerServices; |
|
||||||
using System.Runtime.InteropServices; |
|
||||||
using System.Text; |
|
||||||
using System.Threading; |
|
||||||
using static flecs_hub.flecs.Runtime; |
|
||||||
|
|
||||||
namespace gaemstone.Utility; |
|
||||||
|
|
||||||
public interface IAllocator |
|
||||||
{ |
|
||||||
nint Allocate(int byteCount); |
|
||||||
void Free(nint pointer); |
|
||||||
} |
|
||||||
|
|
||||||
public unsafe static class AllocatorExtensions |
|
||||||
{ |
|
||||||
public static Span<T> Allocate<T>(this IAllocator allocator, int count) where T : unmanaged |
|
||||||
=> new((void*)allocator.Allocate(sizeof(T) * count), count); |
|
||||||
public static void Free<T>(this IAllocator allocator, Span<T> span) where T : unmanaged |
|
||||||
=> allocator.Free((nint)Unsafe.AsPointer(ref span[0])); |
|
||||||
|
|
||||||
public static Span<T> AllocateCopy<T>(this IAllocator allocator, ReadOnlySpan<T> orig) where T : unmanaged |
|
||||||
{ var copy = allocator.Allocate<T>(orig.Length); orig.CopyTo(copy); return copy; } |
|
||||||
|
|
||||||
public static ref T Allocate<T>(this IAllocator allocator) where T : unmanaged |
|
||||||
=> ref Unsafe.AsRef<T>((void*)allocator.Allocate(sizeof(T))); |
|
||||||
public static void Free<T>(this IAllocator allocator, ref T value) where T : unmanaged |
|
||||||
=> allocator.Free((nint)Unsafe.AsPointer(ref value)); |
|
||||||
|
|
||||||
public static CString AllocateCString(this IAllocator allocator, string? value) |
|
||||||
{ |
|
||||||
if (value == null) return default; |
|
||||||
var bytes = Encoding.UTF8.GetByteCount(value); |
|
||||||
var span = allocator.Allocate<byte>(bytes + 1); |
|
||||||
Encoding.UTF8.GetBytes(value, span); |
|
||||||
span[^1] = 0; // In case the allocated span is not cleared. |
|
||||||
return new((nint)Unsafe.AsPointer(ref span[0])); |
|
||||||
} |
|
||||||
|
|
||||||
public static CString AllocateCString(this IAllocator allocator, ReadOnlySpan<byte> utf8) |
|
||||||
{ |
|
||||||
var copy = allocator.Allocate<byte>(utf8.Length + 1); |
|
||||||
utf8.CopyTo(copy); |
|
||||||
copy[^1] = 0; // In case the allocated span is not cleared. |
|
||||||
return new((nint)Unsafe.AsPointer(ref copy[0])); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static class TempAllocator |
|
||||||
{ |
|
||||||
public const int Capacity = 1024 * 1024; // 1 MB |
|
||||||
private static readonly ThreadLocal<ArenaAllocator> _allocator |
|
||||||
= new(() => new(Capacity)); |
|
||||||
|
|
||||||
public static ResetOnDispose Use() |
|
||||||
{ |
|
||||||
var allocator = _allocator.Value!; |
|
||||||
return new(allocator, allocator.Used); |
|
||||||
} |
|
||||||
|
|
||||||
public sealed class ResetOnDispose |
|
||||||
: IAllocator |
|
||||||
, IDisposable |
|
||||||
{ |
|
||||||
private readonly ArenaAllocator _allocator; |
|
||||||
private readonly int _start; |
|
||||||
|
|
||||||
public ResetOnDispose(ArenaAllocator allocator, int start) |
|
||||||
{ _allocator = allocator; _start = start; } |
|
||||||
|
|
||||||
// TODO: Print warning in finalizer if Dispose wasn't called manually. |
|
||||||
|
|
||||||
// IAllocator implementation |
|
||||||
public nint Allocate(int byteCount) => _allocator.Allocate(byteCount); |
|
||||||
public void Free(nint pointer) { /* Do nothing. */ } |
|
||||||
|
|
||||||
// IDisposable implementation |
|
||||||
public void Dispose() => _allocator.Reset(_start); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public class GlobalHeapAllocator |
|
||||||
: IAllocator |
|
||||||
{ |
|
||||||
public static GlobalHeapAllocator Instance { get; } = new(); |
|
||||||
|
|
||||||
public nint Allocate(int byteCount) |
|
||||||
=> Marshal.AllocHGlobal(byteCount); |
|
||||||
public void Free(nint pointer) |
|
||||||
=> Marshal.FreeHGlobal(pointer); |
|
||||||
} |
|
||||||
|
|
||||||
public class ArenaAllocator |
|
||||||
: IAllocator |
|
||||||
, IDisposable |
|
||||||
{ |
|
||||||
private nint _buffer; |
|
||||||
public int Capacity { get; private set; } |
|
||||||
public int Used { get; private set; } = 0; |
|
||||||
|
|
||||||
public ArenaAllocator(int capacity) |
|
||||||
{ |
|
||||||
if (capacity <= 0) throw new ArgumentOutOfRangeException(nameof(capacity)); |
|
||||||
_buffer = Marshal.AllocHGlobal(capacity); |
|
||||||
Capacity = capacity; |
|
||||||
} |
|
||||||
|
|
||||||
public void Dispose() |
|
||||||
{ |
|
||||||
Marshal.FreeHGlobal(_buffer); |
|
||||||
_buffer = default; |
|
||||||
Capacity = 0; |
|
||||||
} |
|
||||||
|
|
||||||
public nint Allocate(int byteCount) |
|
||||||
{ |
|
||||||
if (_buffer == default) throw new ObjectDisposedException(nameof(ArenaAllocator)); |
|
||||||
if (Used + byteCount > Capacity) throw new InvalidOperationException( |
|
||||||
$"Cannot allocate more than {Capacity} bytes with this {nameof(ArenaAllocator)}"); |
|
||||||
var ptr = _buffer + Used; |
|
||||||
Used += byteCount; |
|
||||||
return ptr; |
|
||||||
} |
|
||||||
|
|
||||||
public void Free(nint pointer) |
|
||||||
{ /* Do nothing. */ } |
|
||||||
|
|
||||||
public unsafe void Reset(int start = 0) |
|
||||||
{ |
|
||||||
if (start > Used) throw new ArgumentOutOfRangeException(nameof(start)); |
|
||||||
new Span<byte>((void*)(_buffer + start), Used - start).Clear(); |
|
||||||
Used = start; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public class RingAllocator |
|
||||||
: IAllocator |
|
||||||
, IDisposable |
|
||||||
{ |
|
||||||
private nint _buffer; |
|
||||||
private int _current = 0; |
|
||||||
public int Capacity { get; private set; } |
|
||||||
|
|
||||||
public RingAllocator(int capacity) |
|
||||||
{ |
|
||||||
if (capacity <= 0) throw new ArgumentOutOfRangeException(nameof(capacity)); |
|
||||||
_buffer = Marshal.AllocHGlobal(capacity); |
|
||||||
Capacity = capacity; |
|
||||||
} |
|
||||||
|
|
||||||
public void Dispose() |
|
||||||
{ |
|
||||||
Marshal.FreeHGlobal(_buffer); |
|
||||||
_buffer = default; |
|
||||||
Capacity = 0; |
|
||||||
} |
|
||||||
|
|
||||||
public nint Allocate(int byteCount) |
|
||||||
{ |
|
||||||
if (_buffer == default) throw new ObjectDisposedException(nameof(RingAllocator)); |
|
||||||
if (byteCount > Capacity) throw new ArgumentOutOfRangeException(nameof(byteCount)); |
|
||||||
if (_current + byteCount > Capacity) _current = 0; |
|
||||||
var ptr = _buffer + _current; |
|
||||||
_current += byteCount; |
|
||||||
return ptr; |
|
||||||
} |
|
||||||
|
|
||||||
public void Free(nint pointer) |
|
||||||
{ /* Do nothing. */ } |
|
||||||
} |
|
@ -1,34 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Runtime.InteropServices; |
|
||||||
using static flecs_hub.flecs; |
|
||||||
using static flecs_hub.flecs.Runtime; |
|
||||||
|
|
||||||
namespace gaemstone.Utility; |
|
||||||
|
|
||||||
public unsafe static class CStringExtensions |
|
||||||
{ |
|
||||||
public static CString Empty { get; } = (CString)""; |
|
||||||
public static CString ETX { get; } = (CString)"\x3"; // TODO: Temporary, until flecs supports Empty. |
|
||||||
|
|
||||||
public static unsafe byte[]? FlecsToBytes(this CString str) |
|
||||||
{ |
|
||||||
if (str.IsNull) return null; |
|
||||||
var pointer = (byte*)(nint)str; |
|
||||||
// Find length of the string by locating the NUL character. |
|
||||||
var length = 0; while (true) if (pointer[length++] == 0) break; |
|
||||||
// Create span over the region, NUL included, copy it into an array. |
|
||||||
return new Span<byte>(pointer, length).ToArray(); |
|
||||||
} |
|
||||||
|
|
||||||
public static byte[]? FlecsToBytesAndFree(this CString str) |
|
||||||
{ var result = str.FlecsToBytes(); str.FlecsFree(); return result; } |
|
||||||
|
|
||||||
public static string? FlecsToString(this CString str) |
|
||||||
=> Marshal.PtrToStringUTF8(str); |
|
||||||
|
|
||||||
public static string? FlecsToStringAndFree(this CString str) |
|
||||||
{ var result = str.FlecsToString(); str.FlecsFree(); return result; } |
|
||||||
|
|
||||||
public static void FlecsFree(this CString str) |
|
||||||
{ if (!str.IsNull) ecs_os_get_api().free_.Data.Pointer((void*)(nint)str); } |
|
||||||
} |
|
@ -1,30 +0,0 @@ |
|||||||
using System.Collections.Generic; |
|
||||||
|
|
||||||
namespace gaemstone.Utility; |
|
||||||
|
|
||||||
public static class CallbackContextHelper |
|
||||||
{ |
|
||||||
private static readonly Dictionary<nint, object> _contexts = new(); |
|
||||||
private static nint _counter = 0; |
|
||||||
|
|
||||||
public static nint Create<T>(T context) where T : notnull |
|
||||||
{ |
|
||||||
lock (_contexts) { |
|
||||||
var id = _counter++; |
|
||||||
_contexts.Add(id, context); |
|
||||||
return id; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static T Get<T>(nint id) |
|
||||||
{ |
|
||||||
lock (_contexts) |
|
||||||
return (T)_contexts[id]; |
|
||||||
} |
|
||||||
|
|
||||||
public static void Free(nint id) |
|
||||||
{ |
|
||||||
lock (_contexts) |
|
||||||
_contexts.Remove(id); |
|
||||||
} |
|
||||||
} |
|
@ -1,26 +0,0 @@ |
|||||||
using System; |
|
||||||
using System.Diagnostics; |
|
||||||
using System.Runtime.InteropServices; |
|
||||||
|
|
||||||
namespace gaemstone.Utility; |
|
||||||
|
|
||||||
public class FlecsException |
|
||||||
: Exception |
|
||||||
{ |
|
||||||
public FlecsException() : base() { } |
|
||||||
public FlecsException(string message) : base(message) { } |
|
||||||
} |
|
||||||
|
|
||||||
public class FlecsAbortException |
|
||||||
: FlecsException |
|
||||||
{ |
|
||||||
private readonly string _stackTrace = new StackTrace(2, true).ToString(); |
|
||||||
public override string? StackTrace => _stackTrace; |
|
||||||
|
|
||||||
private FlecsAbortException() |
|
||||||
: base("Abort was called by flecs") { } |
|
||||||
|
|
||||||
[UnmanagedCallersOnly] |
|
||||||
internal static void Callback() |
|
||||||
=> throw new FlecsAbortException(); |
|
||||||
} |
|
@ -1,41 +0,0 @@ |
|||||||
using System; |
|
||||||
|
|
||||||
namespace gaemstone.Utility; |
|
||||||
|
|
||||||
public static class SpanExtensions |
|
||||||
{ |
|
||||||
public static T? GetOrNull<T>(this Span<T> span, int index) |
|
||||||
where T : struct => GetOrNull((ReadOnlySpan<T>)span, index); |
|
||||||
public static T? GetOrNull<T>(this ReadOnlySpan<T> span, int index) |
|
||||||
where T : struct => (index >= 0 && index < span.Length) ? span[index] : null; |
|
||||||
|
|
||||||
|
|
||||||
public static ReadOnlySpanSplitEnumerator<T> Split<T>(this ReadOnlySpan<T> span, T splitOn) |
|
||||||
where T : IEquatable<T> => new(span, splitOn); |
|
||||||
|
|
||||||
public ref struct ReadOnlySpanSplitEnumerator<T> |
|
||||||
where T : IEquatable<T> |
|
||||||
{ |
|
||||||
private readonly ReadOnlySpan<T> _span; |
|
||||||
private readonly T _splitOn; |
|
||||||
private int _index = -1; |
|
||||||
private int _end = -1; |
|
||||||
|
|
||||||
public ReadOnlySpanSplitEnumerator(ReadOnlySpan<T> span, T splitOn) |
|
||||||
{ _span = span; _splitOn = splitOn; } |
|
||||||
|
|
||||||
public ReadOnlySpanSplitEnumerator<T> GetEnumerator() => this; |
|
||||||
|
|
||||||
public ReadOnlySpan<T> Current |
|
||||||
=> (_end >= 0) && (_end <= _span.Length) |
|
||||||
? _span[_index.._end] : throw new InvalidOperationException(); |
|
||||||
|
|
||||||
public bool MoveNext() |
|
||||||
{ |
|
||||||
if (_end == _span.Length) return false; |
|
||||||
_end++; _index = _end; |
|
||||||
while (_end < _span.Length && !_span[_end].Equals(_splitOn)) _end++; |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue