Move .csproj and Utility namespace

wip/bindgen
copygirl 1 year ago
parent 46e171940e
commit c6613679cc
  1. 2
      README.md
  2. 23
      gaemstone.ECS.csproj
  3. 2
      src/gaemstone.ECS/EntityBuilder.cs
  4. 2
      src/gaemstone.ECS/EntityPath.cs
  5. 2
      src/gaemstone.ECS/EntityRef.cs
  6. 2
      src/gaemstone.ECS/EntityType.cs
  7. 2
      src/gaemstone.ECS/Filter.cs
  8. 2
      src/gaemstone.ECS/IdRef.cs
  9. 2
      src/gaemstone.ECS/Iterator.cs
  10. 2
      src/gaemstone.ECS/Observer.cs
  11. 2
      src/gaemstone.ECS/Query.cs
  12. 2
      src/gaemstone.ECS/Rule.cs
  13. 2
      src/gaemstone.ECS/System.cs
  14. 2
      src/gaemstone.ECS/Term.cs
  15. 171
      src/gaemstone.ECS/Utility/Allocators.cs
  16. 34
      src/gaemstone.ECS/Utility/CStringExtensions.cs
  17. 30
      src/gaemstone.ECS/Utility/CallbackContextHelper.cs
  18. 26
      src/gaemstone.ECS/Utility/FlecsException.cs
  19. 41
      src/gaemstone.ECS/Utility/SpanExtensions.cs
  20. 2
      src/gaemstone.ECS/World+Lookup.cs
  21. 2
      src/gaemstone.ECS/World.cs
  22. 14
      src/gaemstone.ECS/gaemstone.ECS.csproj

@ -104,7 +104,7 @@ git clone --recurse-submodules https://git.mcft.net/copygirl/gaemstone.ECS.git
git submodule add https://git.mcft.net/copygirl/gaemstone.ECS.git
# To add a reference to this library to your .NET project:
dotnet add reference gaemstone.ECS/gaemstone.ECS.csproj
dotnet add reference gaemstone.ECS/src/gaemstone.ECS/gaemstone.ECS.csproj
# To generate flecs-cs' bindings:
./gaemstone.ECS/src/flecs-cs/library.sh

@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<EnableDefaultItems>false</EnableDefaultItems>
</PropertyGroup>
<ItemGroup>
<Compile Include="src/gaemstone.ECS/**/*.cs" />
<Compile Include="src/gaemstone.Utility/**/*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="src/flecs-cs/src/cs/production/Flecs/Flecs.csproj" />
</ItemGroup>
</Project>

@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -1,6 +1,6 @@
using System.Collections;
using System.Collections.Generic;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -1,5 +1,5 @@
using System;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -2,7 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -1,6 +1,6 @@
using System;
using System.Runtime.InteropServices;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -1,5 +1,5 @@
using System;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -1,7 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -1,6 +1,6 @@
using System;
using System.Runtime.InteropServices;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -1,5 +1,5 @@
using System;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -0,0 +1,171 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using static flecs_hub.flecs.Runtime;
namespace gaemstone.ECS.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. */ }
}

@ -0,0 +1,34 @@
using System;
using System.Runtime.InteropServices;
using static flecs_hub.flecs;
using static flecs_hub.flecs.Runtime;
namespace gaemstone.ECS.Utility;
public unsafe static class CStringExtensions
{
public static CString Empty { get; } = (CString)"";
public static CString ETX { get; } = (CString)"\x3"; // FIXME: 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); }
}

@ -0,0 +1,30 @@
using System.Collections.Generic;
namespace gaemstone.ECS.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);
}
}

@ -0,0 +1,26 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace gaemstone.ECS.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();
}

@ -0,0 +1,41 @@
using System;
namespace gaemstone.ECS.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;
}
}
}

@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -1,5 +1,5 @@
using System;
using gaemstone.Utility;
using gaemstone.ECS.Utility;
using static flecs_hub.flecs;
namespace gaemstone.ECS;

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../flecs-cs/src/cs/production/Flecs/Flecs.csproj" />
</ItemGroup>
</Project>
Loading…
Cancel
Save