diff --git a/src/Flecs.NET.Bindings/Flecs.NET.Bindings.csproj b/src/Flecs.NET.Bindings/Flecs.NET.Bindings.csproj index d0308683..e898054b 100644 --- a/src/Flecs.NET.Bindings/Flecs.NET.Bindings.csproj +++ b/src/Flecs.NET.Bindings/Flecs.NET.Bindings.csproj @@ -10,7 +10,7 @@ true true - 4.0.0 + 4.0.1 Flecs.NET.Bindings.Debug Flecs.NET.Bindings.Release BeanCheeseBurrito diff --git a/src/Flecs.NET.Bindings/Flecs.g.cs b/src/Flecs.NET.Bindings/Flecs.g.cs index a78d92db..a18efd0f 100644 --- a/src/Flecs.NET.Bindings/Flecs.g.cs +++ b/src/Flecs.NET.Bindings/Flecs.g.cs @@ -202,9 +202,6 @@ public static unsafe partial class flecs [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_entity_from_json", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern byte* ecs_entity_from_json(ecs_world_t* world, ulong entity, byte* json, ecs_from_json_desc_t* desc); - [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_entity_from_json_legacy", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern byte* ecs_entity_from_json_legacy(ecs_world_t* world, ulong entity, byte* json, ecs_from_json_desc_t* desc); - [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_entity_init", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern ulong ecs_entity_init(ecs_world_t* world, ecs_entity_desc_t* desc); @@ -223,32 +220,35 @@ public static unsafe partial class flecs [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_exists", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern byte ecs_exists(ecs_world_t* world, ulong entity); + [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_field_at_w_size", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] + public static extern void* ecs_field_at_w_size(ecs_iter_t* it, System.IntPtr size, byte index, int row); + [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_field_column", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern int ecs_field_column(ecs_iter_t* it, int index); + public static extern int ecs_field_column(ecs_iter_t* it, byte index); [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_field_id", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern ulong ecs_field_id(ecs_iter_t* it, int index); + public static extern ulong ecs_field_id(ecs_iter_t* it, byte index); [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_field_is_readonly", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern byte ecs_field_is_readonly(ecs_iter_t* it, int index); + public static extern byte ecs_field_is_readonly(ecs_iter_t* it, byte index); [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_field_is_self", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern byte ecs_field_is_self(ecs_iter_t* it, int index); + public static extern byte ecs_field_is_self(ecs_iter_t* it, byte index); [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_field_is_set", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern byte ecs_field_is_set(ecs_iter_t* it, int index); + public static extern byte ecs_field_is_set(ecs_iter_t* it, byte index); [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_field_is_writeonly", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern byte ecs_field_is_writeonly(ecs_iter_t* it, int index); + public static extern byte ecs_field_is_writeonly(ecs_iter_t* it, byte index); [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_field_size", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern System.IntPtr ecs_field_size(ecs_iter_t* it, int index); + public static extern System.IntPtr ecs_field_size(ecs_iter_t* it, byte index); [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_field_src", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern ulong ecs_field_src(ecs_iter_t* it, int index); + public static extern ulong ecs_field_src(ecs_iter_t* it, byte index); [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_field_w_size", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern void* ecs_field_w_size(ecs_iter_t* it, System.IntPtr size, int index); + public static extern void* ecs_field_w_size(ecs_iter_t* it, System.IntPtr size, byte index); [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_fini", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern int ecs_fini(ecs_world_t* world); @@ -1348,6 +1348,9 @@ public static unsafe partial class flecs [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_table_count", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern int ecs_table_count(ecs_table_t* table); + [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_table_entities", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] + public static extern ulong* ecs_table_entities(ecs_table_t* table); + [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_table_find", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern ecs_table_t* ecs_table_find(ecs_world_t* world, ulong* ids, int id_count); @@ -1384,6 +1387,9 @@ public static unsafe partial class flecs [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_table_remove_id", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern ecs_table_t* ecs_table_remove_id(ecs_world_t* world, ecs_table_t* table, ulong id); + [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_table_size", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] + public static extern int ecs_table_size(ecs_table_t* table); + [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_table_str", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern byte* ecs_table_str(ecs_world_t* world, ecs_table_t* table); @@ -1558,12 +1564,6 @@ public static unsafe partial class flecs [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_world_from_json_file", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern byte* ecs_world_from_json_file(ecs_world_t* world, byte* filename, ecs_from_json_desc_t* desc); - [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_world_from_json_file_legacy", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern byte* ecs_world_from_json_file_legacy(ecs_world_t* world, byte* filename, ecs_from_json_desc_t* desc); - - [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_world_from_json_legacy", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] - public static extern byte* ecs_world_from_json_legacy(ecs_world_t* world, byte* json, ecs_from_json_desc_t* desc); - [System.Runtime.InteropServices.DllImport(BindgenInternal.DllImportPath, EntryPoint = "ecs_world_stats_copy_last", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern void ecs_world_stats_copy_last(ecs_world_stats_t* dst, ecs_world_stats_t* src); @@ -2864,7 +2864,7 @@ public partial struct ecs_each_iter_t : System.IEquatable public int columns; - public void* ptrs; + public ecs_table_record_t* trs; public bool Equals(ecs_each_iter_t other) { @@ -4370,8 +4370,6 @@ public partial struct ecs_iter_t : System.IEquatable public ulong* entities; - public void** ptrs; - public int* sizes; public ecs_table_t* table; @@ -4382,7 +4380,7 @@ public partial struct ecs_iter_t : System.IEquatable public ecs_var_t* variables; - public int* columns; + public ecs_table_record_t** trs; public ulong* sources; @@ -4390,11 +4388,11 @@ public partial struct ecs_iter_t : System.IEquatable public ulong group_id; - public int field_count; - public uint set_fields; - public uint shared_fields; + public uint ref_fields; + + public uint row_fields; public uint up_fields; @@ -4406,11 +4404,13 @@ public partial struct ecs_iter_t : System.IEquatable public int event_cur; - public ecs_query_t* query; + public byte field_count; + + public byte term_index; - public int term_index; + public byte variable_count; - public int variable_count; + public ecs_query_t* query; public byte** variable_names; @@ -4720,6 +4720,8 @@ public partial struct ecs_member_t : System.IEquatable public ulong unit; + public byte use_offset; + public ecs_member_value_range_t range; public ecs_member_value_range_t error_range; @@ -5326,7 +5328,7 @@ public partial struct ecs_observer_desc_t : System.IEquatable public uint flags; - public short var_count; + public byte var_count; public byte term_count; @@ -6421,6 +6423,8 @@ public partial struct ecs_query_t : System.IEquatable public uint read_fields; + public uint row_fields; + public uint shared_readonly_fields; public uint set_fields; @@ -8162,46 +8166,50 @@ public override int GetHashCode() } } - public partial struct ecs_table_cache_iter_t : System.IEquatable + public partial struct ecs_table_cache_hdr_t : System.IEquatable { - public ecs_table_cache_hdr_t* cur; + public ecs_table_cache_t* cache; + + public ecs_table_t* table; + + public ecs_table_cache_hdr_t* prev; public ecs_table_cache_hdr_t* next; - public ecs_table_cache_hdr_t* next_list; + public byte empty; - public partial struct ecs_table_cache_hdr_t : System.IEquatable + public partial struct ecs_table_cache_t : System.IEquatable { - public bool Equals(ecs_table_cache_hdr_t other) + public bool Equals(ecs_table_cache_t other) { - fixed (ecs_table_cache_hdr_t* __self = &this) + fixed (ecs_table_cache_t* __self = &this) { - return System.MemoryExtensions.SequenceEqual(new System.ReadOnlySpan((byte*)__self, sizeof(ecs_table_cache_hdr_t)), new System.ReadOnlySpan((byte*)&other, sizeof(ecs_table_cache_hdr_t))); + return System.MemoryExtensions.SequenceEqual(new System.ReadOnlySpan((byte*)__self, sizeof(ecs_table_cache_t)), new System.ReadOnlySpan((byte*)&other, sizeof(ecs_table_cache_t))); } } public override bool Equals(object? obj) { - return obj is ecs_table_cache_hdr_t other && Equals(other); + return obj is ecs_table_cache_t other && Equals(other); } - public static bool operator ==(ecs_table_cache_hdr_t left, ecs_table_cache_hdr_t right) + public static bool operator ==(ecs_table_cache_t left, ecs_table_cache_t right) { return left.Equals(right); } - public static bool operator !=(ecs_table_cache_hdr_t left, ecs_table_cache_hdr_t right) + public static bool operator !=(ecs_table_cache_t left, ecs_table_cache_t right) { return !(left == right); } public override int GetHashCode() { - fixed (ecs_table_cache_hdr_t* __self = &this) + fixed (ecs_table_cache_t* __self = &this) { #if NET6_0_OR_GREATER System.HashCode hash = new System.HashCode(); - hash.AddBytes(new System.ReadOnlySpan((byte*)__self, sizeof(ecs_table_cache_hdr_t))); + hash.AddBytes(new System.ReadOnlySpan((byte*)__self, sizeof(ecs_table_cache_t))); return hash.ToHashCode(); #else return base.GetHashCode(); @@ -8210,6 +8218,52 @@ public override int GetHashCode() } } + public bool Equals(ecs_table_cache_hdr_t other) + { + fixed (ecs_table_cache_hdr_t* __self = &this) + { + return System.MemoryExtensions.SequenceEqual(new System.ReadOnlySpan((byte*)__self, sizeof(ecs_table_cache_hdr_t)), new System.ReadOnlySpan((byte*)&other, sizeof(ecs_table_cache_hdr_t))); + } + } + + public override bool Equals(object? obj) + { + return obj is ecs_table_cache_hdr_t other && Equals(other); + } + + public static bool operator ==(ecs_table_cache_hdr_t left, ecs_table_cache_hdr_t right) + { + return left.Equals(right); + } + + public static bool operator !=(ecs_table_cache_hdr_t left, ecs_table_cache_hdr_t right) + { + return !(left == right); + } + + public override int GetHashCode() + { + fixed (ecs_table_cache_hdr_t* __self = &this) + { +#if NET6_0_OR_GREATER + System.HashCode hash = new System.HashCode(); + hash.AddBytes(new System.ReadOnlySpan((byte*)__self, sizeof(ecs_table_cache_hdr_t))); + return hash.ToHashCode(); +#else + return base.GetHashCode(); +#endif + } + } + } + + public partial struct ecs_table_cache_iter_t : System.IEquatable + { + public ecs_table_cache_hdr_t* cur; + + public ecs_table_cache_hdr_t* next; + + public ecs_table_cache_hdr_t* next_list; + public bool Equals(ecs_table_cache_iter_t other) { fixed (ecs_table_cache_iter_t* __self = &this) @@ -8296,6 +8350,14 @@ public override int GetHashCode() public partial struct ecs_table_record_t : System.IEquatable { + public ecs_table_cache_hdr_t hdr; + + public short index; + + public short count; + + public short column; + public bool Equals(ecs_table_record_t other) { fixed (ecs_table_record_t* __self = &this) @@ -8434,7 +8496,7 @@ public partial struct ecs_term_t : System.IEquatable public short oper; - public short field_index; + public byte field_index; public ushort flags_; @@ -10252,6 +10314,8 @@ public partial struct EcsMember : System.IEquatable public int offset; + public byte use_offset; + public bool Equals(EcsMember other) { fixed (EcsMember* __self = &this) @@ -11852,6 +11916,8 @@ public enum ecs_type_kind_t : uint public const uint EcsIdIsSparse = 16777216; + public const uint EcsIdIsTransitive = 16384; + public const uint EcsIdIsUnion = 33554432; public const uint EcsIdMarkedForDelete = 1073741824; @@ -11924,12 +11990,8 @@ public enum ecs_type_kind_t : uint public const uint EcsIterTrivialSearch = 256; - public const uint EcsIterTrivialSearchNoData = 512; - public const uint EcsIterTrivialTest = 2048; - public const uint EcsIterTrivialTestNoData = 4096; - public const int EcsIterYield = -1; public const uint EcsObserverBypassQuery = 32; @@ -11970,8 +12032,6 @@ public enum ecs_type_kind_t : uint public const uint EcsQueryHasScopes = 131072; - public const uint EcsQueryHasSparseThis = 67108864; - public const uint EcsQueryHasTableThisVar = 33554432; public const uint EcsQueryIsCacheable = 16777216; @@ -11992,8 +12052,6 @@ public enum ecs_type_kind_t : uint public const uint EcsQueryMatchWildcards = 16384; - public const uint EcsQueryNoData = 16; - public const uint EcsQueryTableOnly = 128; public const ulong EcsSelf = 9223372036854775808; @@ -12082,8 +12140,6 @@ public enum ecs_type_kind_t : uint public const uint EcsTermMatchAnySrc = 2; - public const uint EcsTermNoData = 64; - public const ulong EcsTermRefFlags = 18374686479671623680; public const uint EcsTermReflexive = 8; @@ -12124,14 +12180,14 @@ public enum ecs_type_kind_t : uint public const int flecs_iter_cache_all = 255; - public const uint flecs_iter_cache_columns = 2; - public const uint flecs_iter_cache_ids = 1; public const uint flecs_iter_cache_ptrs = 8; public const uint flecs_iter_cache_sources = 4; + public const uint flecs_iter_cache_trs = 2; + public const uint flecs_iter_cache_variables = 16; public const int FLECS_QUERY_SCOPE_NESTING_MAX = 8; @@ -12148,13 +12204,13 @@ public enum ecs_type_kind_t : uint public const int FLECS_VARIABLE_COUNT_MAX = 64; - public const string FLECS_VERSION = "4.0.0"; + public const string FLECS_VERSION = "4.0.1"; public const int FLECS_VERSION_MAJOR = 4; public const int FLECS_VERSION_MINOR = 0; - public const int FLECS_VERSION_PATCH = 0; + public const int FLECS_VERSION_PATCH = 1; private static void* ECS_AUTO_OVERRIDE_Ptr; diff --git a/src/Flecs.NET.Codegen/Generators/IIterable.cs b/src/Flecs.NET.Codegen/Generators/IIterable.cs index 01475e62..d6fd3aa2 100644 --- a/src/Flecs.NET.Codegen/Generators/IIterable.cs +++ b/src/Flecs.NET.Codegen/Generators/IIterable.cs @@ -103,6 +103,7 @@ public static string GenerateExtensions(Type type, int i) public {{Generator.GetInvokerReturnType(callback)}} {{Generator.GetInvokerName(callback)}}({{Generator.GetCallbackType(callback, i)}} callback) { {{Generator.GetTypeName(Type.TypeHelper, i)}}.AssertReferenceTypes({{(Generator.GetCallbackIsUnmanaged(callback) ? "false" : "true")}}); + {{Generator.GetTypeName(Type.TypeHelper, i)}}.AssertSparseTypes(Ecs.GetIterableWorld(ref this), {{(Generator.GetCallbackIsIter(callback) ? "false" : "true")}}); {{Generator.GetInvokerReturn(callback)}}Invoker.{{Generator.GetInvokerName(callback)}}(ref this, callback); } """); diff --git a/src/Flecs.NET.Codegen/Generators/Invoker.cs b/src/Flecs.NET.Codegen/Generators/Invoker.cs index b90556b8..85933c7e 100644 --- a/src/Flecs.NET.Codegen/Generators/Invoker.cs +++ b/src/Flecs.NET.Codegen/Generators/Invoker.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -43,7 +44,7 @@ private static string GenerateIterIteratorInvokers(int i) public static void Iter<{{Generator.TypeParameters[i]}}>(Iter it, {{Generator.GetCallbackType(callback, i)}} callback) { Ecs.TableLock(it); - callback(it, {{Generator.GetCallbackArguments(i, callback)}}); + callback(it, {{Generator.GetCallbackArguments(callback, i)}}); Ecs.TableUnlock(it); } """); @@ -74,19 +75,45 @@ private static string GenerateEachIteratorInvokers(int i) { {{Generator.GetCallbackCountVariable(callback)}} - {{Generator.IterPointerVariables[i]}} - {{Generator.IterStepVariables[i]}} + {{Generator.FieldDataVariables[i]}} + IterationTechnique flags = it.GetIterationTechnique({{i + 1}}); Ecs.TableLock(it); - - for (int i = 0; i < count; i++, {{Generator.IterPointerIncrements[i]}}) - callback({{Generator.GetCallbackSteppedArguments(i, callback)}}); + + if ({{Generator.ContainsReferenceTypes[i]}}) + { + if (flags == IterationTechnique.None) + {{IterationTechnique.Managed}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == IterationTechnique.Shared) + {{IterationTechnique.SharedManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == IterationTechnique.Sparse) + {{IterationTechnique.SparseManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == (IterationTechnique.Sparse | IterationTechnique.Shared)) + {{IterationTechnique.SparseSharedManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + } + else + { + if (flags == IterationTechnique.None) + {{IterationTechnique.Unmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == IterationTechnique.Shared) + {{IterationTechnique.SharedUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == IterationTechnique.Sparse) + {{IterationTechnique.SparseUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == (IterationTechnique.Sparse | IterationTechnique.Shared)) + {{IterationTechnique.SparseSharedUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + } Ecs.TableUnlock(it); + + return; + + {{GenerateEachInvokerIterators(callback, i)}} } """); return $$""" + using System; + using System.Runtime.CompilerServices; using Flecs.NET.Utilities; using static Flecs.NET.Bindings.flecs; @@ -112,29 +139,47 @@ private static string GenerateFindIteratorInvokers(int i) { {{Generator.GetCallbackCountVariable(callback)}} - {{Generator.IterPointerVariables[i]}} - {{Generator.IterStepVariables[i]}} + {{Generator.FieldDataVariables[i]}} + IterationTechnique flags = it.GetIterationTechnique({{i + 1}}); Ecs.TableLock(it); Entity result = default; - - for (int i = 0; i < count; i++, {{Generator.IterPointerIncrements[i]}}) + + if ({{Generator.ContainsReferenceTypes[i]}}) { - if (!callback({{Generator.GetCallbackSteppedArguments(i, callback)}})) - continue; - - result = new Entity(it.Handle->world, it.Handle->entities[i]); - break; + if (flags == IterationTechnique.None) + result = {{IterationTechnique.Managed}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == IterationTechnique.Shared) + result = {{IterationTechnique.SharedManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == IterationTechnique.Sparse) + result = {{IterationTechnique.SparseManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == (IterationTechnique.Sparse | IterationTechnique.Shared)) + result = {{IterationTechnique.SparseSharedManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + } + else + { + if (flags == IterationTechnique.None) + result = {{IterationTechnique.Unmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == IterationTechnique.Shared) + result = {{IterationTechnique.SharedUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == IterationTechnique.Sparse) + result = {{IterationTechnique.SparseUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); + else if (flags == (IterationTechnique.Sparse | IterationTechnique.Shared)) + result = {{IterationTechnique.SparseSharedUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}}); } Ecs.TableUnlock(it); return result; + + {{GenerateFindInvokerIterators(callback, i)}} } """); return $$""" + using System; + using System.Runtime.CompilerServices; using Flecs.NET.Utilities; using static Flecs.NET.Bindings.flecs; @@ -147,6 +192,39 @@ public static unsafe partial class Invoker """; } + private static string GenerateEachInvokerIterators(Callback callback, int i) + { + IEnumerable invokerIterators = Enum.GetValues(typeof(IterationTechnique)).Cast().Select((IterationTechnique iterationTechnique) => $$""" + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static void {{iterationTechnique}}(Iter it, int count, {{Generator.GetCallbackType(callback, i)}} callback, {{Generator.FieldDataParameters[i]}}) + { + for (int i = 0; i < count; i++) + callback({{Generator.GetCallbackArguments(callback, iterationTechnique, i)}}); + } + """); + + return string.Join(Separator.DoubleNewLine, invokerIterators); + } + + private static string GenerateFindInvokerIterators(Callback callback, int i) + { + IEnumerable invokerIterators = Enum.GetValues(typeof(IterationTechnique)).Cast().Select((IterationTechnique iterationTechnique) => $$""" + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static Entity {{iterationTechnique}}(Iter it, int count, {{Generator.GetCallbackType(callback, i)}} callback, {{Generator.FieldDataParameters[i]}}) + { + for (int i = 0; i < count; i++) + { + if (callback({{Generator.GetCallbackArguments(callback, iterationTechnique, i)}})) + return new Entity(it.Handle->world, it.Handle->entities[i]); + } + + return default; + } + """); + + return string.Join(Separator.DoubleNewLine, invokerIterators); + } + private static string GenerateIterIterableInvokers(int i) { IEnumerable invokers = Generator.CallbacksIter.Select((Callback callback) => $$""" @@ -279,7 +357,7 @@ public static string GenerateFetchComponentInvokers(int i) bool hasComponents = Ecs.GetPointers<{{Generator.TypeParameters[i]}}>(world, entity, record, table, pointers); if (hasComponents) - callback({{Generator.GetCallbackArguments(i, callback)}}); + callback({{Generator.GetCallbackArguments(callback, i)}}); ecs_{{Generator.GetInvokerName(callback).ToLower()}}_end(record); @@ -347,7 +425,7 @@ public static string GenerateFetchComponentInvokers(int i) Ecs.EnsurePointers<{{Generator.TypeParameters[i]}}>(world, entity, pointers); } - callback({{Generator.GetCallbackArguments(i, callback)}}); + callback({{Generator.GetCallbackArguments(callback, i)}}); if (!world.IsDeferred()) Ecs.TableUnlock(world, table); diff --git a/src/Flecs.NET.Codegen/Generators/IterIterable.cs b/src/Flecs.NET.Codegen/Generators/IterIterable.cs index 2416d837..94e7139d 100644 --- a/src/Flecs.NET.Codegen/Generators/IterIterable.cs +++ b/src/Flecs.NET.Codegen/Generators/IterIterable.cs @@ -172,6 +172,9 @@ public override int GetHashCode() // IIterableBase Interface public unsafe partial struct {{Generator.GetTypeName(Type.IterIterable, i)}} : IIterableBase { + /// + public ref ecs_world_t* World => ref _iterIterable.World; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ecs_iter_t GetIter(ecs_world_t* world = null) diff --git a/src/Flecs.NET.Codegen/Generators/NodeBuilder.cs b/src/Flecs.NET.Codegen/Generators/NodeBuilder.cs index 584d2081..992a711c 100644 --- a/src/Flecs.NET.Codegen/Generators/NodeBuilder.cs +++ b/src/Flecs.NET.Codegen/Generators/NodeBuilder.cs @@ -17,6 +17,7 @@ public static string GenerateExtensions(Type builderType, Type returnType, int i public {{Generator.GetTypeName(returnType, i)}} {{Generator.GetInvokerName(callback)}}({{Generator.GetCallbackType(callback, i)}} callback) { {{Generator.GetTypeName(Type.TypeHelper, i)}}.AssertReferenceTypes({{(Generator.GetCallbackIsUnmanaged(callback) ? "false" : "true")}}); + {{Generator.GetTypeName(Type.TypeHelper, i)}}.AssertSparseTypes(World, {{(Generator.GetCallbackIsIter(callback) ? "false" : "true")}}); return {{(Generator.GetCallbackIsRun(callback) ? "SetRun" : "SetCallback")}}({{(Generator.GetCallbackIsDelegate(callback) ? string.Empty : "(IntPtr)")}}callback, Pointers<{{Generator.TypeParameters[i]}}>.{{callback}}).Build(); } """); diff --git a/src/Flecs.NET.Codegen/Generators/PageIterable.cs b/src/Flecs.NET.Codegen/Generators/PageIterable.cs index 9a7c820d..c04bfd94 100644 --- a/src/Flecs.NET.Codegen/Generators/PageIterable.cs +++ b/src/Flecs.NET.Codegen/Generators/PageIterable.cs @@ -85,6 +85,9 @@ public override int GetHashCode() // IIterableBase Interface public unsafe partial struct {{Generator.GetTypeName(Type.PageIterable, i)}} : IIterableBase { + /// + public ref ecs_world_t* World => ref _pageIterable.World; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ecs_iter_t GetIter(ecs_world_t* world = null) diff --git a/src/Flecs.NET.Codegen/Generators/Query.cs b/src/Flecs.NET.Codegen/Generators/Query.cs index 76ba875d..c844ad31 100644 --- a/src/Flecs.NET.Codegen/Generators/Query.cs +++ b/src/Flecs.NET.Codegen/Generators/Query.cs @@ -221,6 +221,9 @@ public World RealWorld() // IIterableBase Interface public unsafe partial struct {{Generator.GetTypeName(Type.Query, i)}} : IIterableBase { + /// + ref ecs_world_t* IIterableBase.World => ref Ecs.GetIterableWorld(ref _query); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ecs_iter_t GetIter(ecs_world_t* world = null) diff --git a/src/Flecs.NET.Codegen/Generators/TypeHelper.cs b/src/Flecs.NET.Codegen/Generators/TypeHelper.cs index 548ab4b7..13a1699c 100644 --- a/src/Flecs.NET.Codegen/Generators/TypeHelper.cs +++ b/src/Flecs.NET.Codegen/Generators/TypeHelper.cs @@ -27,11 +27,14 @@ public static string GenerateTypeHelper(int i) using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; + using Flecs.NET.Utilities; + + using static Flecs.NET.Bindings.flecs; namespace Flecs.NET.Core; [SuppressMessage("ReSharper", "StaticMemberInGenericType")] - internal static partial class {{Generator.GetTypeName(Type.TypeHelper, i)}} + internal static unsafe partial class {{Generator.GetTypeName(Type.TypeHelper, i)}} { private static string[]? _typeNames; public static string[] TypeNames => _typeNames ??= [ {{Generator.TypeFullNames[i]}} ]; @@ -39,17 +42,20 @@ internal static partial class {{Generator.GetTypeName(Type.TypeHelper, i)}} public static readonly int Tags = {{Generator.Tags[i]}}; public static readonly int ReferenceTypes = {{Generator.ReferenceTypes[i]}}; + private static string GetTypeListString(int fields) + { + return string.Join(", ", Enumerable.Range(0, {{i + 1}}) + .Where(i => (fields & (1 << i)) != 0) + .Select(i => TypeNames[i])); + } + [Conditional("DEBUG")] public static void AssertNoTags() { if (Tags == 0) return; - string tags = string.Join(", ", Enumerable.Range(0, {{i + 1}}) - .Where(i => (Tags & (1 << i)) != 0) - .Select(i => TypeNames[i])); - - Ecs.Error($"Cannot use zero-sized structs as generic type arguments for this struct. Remove the following type arguments: {tags}"); + Ecs.Error($"Cannot use zero-sized structs as generic type arguments for this struct. Remove the following type arguments: {GetTypeListString(Tags)}"); } [Conditional("DEBUG")] @@ -58,11 +64,21 @@ public static void AssertReferenceTypes(bool allowReferenceTypes) if (allowReferenceTypes || ReferenceTypes == 0) return; - string referenceTypes = string.Join(", ", Enumerable.Range(0, {{i + 1}}) - .Where(i => (ReferenceTypes & (1 << i)) != 0) - .Select(i => TypeNames[i])); + Ecs.Error($"Cannot use managed types as generic type arguments for callback signatures that retrieve pointers or spans. Remove the following type arguments: {GetTypeListString(ReferenceTypes)}"); + } - Ecs.Error($"Cannot use managed types as generic type arguments for callback signatures that retrieve pointers or spans. Remove the following type arguments: {referenceTypes}"); + [Conditional("DEBUG")] + public static void AssertSparseTypes(ecs_world_t* world, bool allowSparseTypes) + { + if (allowSparseTypes) + return; + + int sparseTypes = {{Generator.SparseBitField[i]}}; + + if (sparseTypes == 0) + return; + + Ecs.Error($"Cannot use sparse components as generic type arguments for this struct when using .Iter() to iterate because sparse fields must be obtained with Iter.FieldAt(). Use .Each()/.Run() to iterate or remove the following types from the list: {GetTypeListString(sparseTypes)}"); } } """; diff --git a/src/Flecs.NET.Codegen/Generators/WorkerIterable.cs b/src/Flecs.NET.Codegen/Generators/WorkerIterable.cs index ee60c28b..9081e710 100644 --- a/src/Flecs.NET.Codegen/Generators/WorkerIterable.cs +++ b/src/Flecs.NET.Codegen/Generators/WorkerIterable.cs @@ -85,6 +85,9 @@ public override int GetHashCode() // IIterableBase Interface public unsafe partial struct {{Generator.GetTypeName(Type.WorkerIterable, i)}} : IIterableBase { + /// + public ref ecs_world_t* World => ref _workerIterable.World; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ecs_iter_t GetIter(ecs_world_t* world = null) diff --git a/src/Flecs.NET.Codegen/Helpers/CallbackParameters.cs b/src/Flecs.NET.Codegen/Helpers/CallbackParameters.cs new file mode 100644 index 00000000..755494e9 --- /dev/null +++ b/src/Flecs.NET.Codegen/Helpers/CallbackParameters.cs @@ -0,0 +1,15 @@ +namespace Flecs.NET.Codegen.Helpers; + +public enum CallbackParameters +{ + IterField, + IterSpan, + IterPointer, + EachRef, + EachEntityRef, + EachIterRef, + EachPointer, + EachEntityPointer, + EachIterPointer, + ReadRef +} diff --git a/src/Flecs.NET.Codegen/Helpers/Generator.cs b/src/Flecs.NET.Codegen/Helpers/Generator.cs index 3414de51..388eb46b 100644 --- a/src/Flecs.NET.Codegen/Helpers/Generator.cs +++ b/src/Flecs.NET.Codegen/Helpers/Generator.cs @@ -12,111 +12,43 @@ public static class Generator #region Type Parameters - // Generates "T0, T1, T2, ..." public static readonly string[] TypeParameters = CacheJoinedStrings(Separator.Comma, i => $"T{i}"); - // Generates "T0, T1, T2, ..." - public static readonly string[] TypeParametersUnderscored = CacheJoinedStrings(Separator.Comma, i => $"T_{i}"); - - // Generates "ref T0, ref T1, ref T2, ..." public static readonly string[] RefTypeParameters = CacheJoinedStrings(Separator.Comma, i => $"ref T{i}"); - - // Generates "Field, Field, Field $"Field"); - - // Generates "Span, Span, Span $"Span"); - - // Generates "T0*, T1*, T2*, ..." public static readonly string[] PointerTypeParameters = CacheJoinedStrings(Separator.Comma, i => $"T{i}*"); - - // Generates "T0 t0, T1 t1, T2 t2, ..." - public static readonly string[] Parameters = CacheJoinedStrings(Separator.Comma, i => $"T{i} t{i}"); - - // Generates "ref T0 t0, ref T1 t1, ref T2 t2, ..." public static readonly string[] RefParameters = CacheJoinedStrings(Separator.Comma, i => $"ref T{i} t{i}"); - - // Generates "Field t0, Field t1, Field t2, ..." public static readonly string[] FieldParameters = CacheJoinedStrings(Separator.Comma, i => $"Field t{i}"); - - // Generates "Span t0, Span t1, Span t2, ..." public static readonly string[] SpanParameters = CacheJoinedStrings(Separator.Comma, i => $"Span t{i}"); - - // Generates "T0* t0, T1* t1, T2* t2, ..." public static readonly string[] PointerParameters = CacheJoinedStrings(Separator.Comma, i => $"T{i}* t{i}"); - - // Generates "ref readonly t0, ref readonly T1 t1, ref readonly T2 t2, ..." public static readonly string[] RefReadOnlyParameters = CacheJoinedStrings(Separator.Comma, i => $"ref readonly T{i} t{i}"); - // Generates "where T0 : unmanaged where T1 : unmanaged where T2 : unmanaged..." - public static readonly string[] TypeConstraints = CacheJoinedStrings(Separator.Space, i => $"where T{i} : unmanaged"); - - // Generates "where T0_ : unmanaged, T0 where T1_ : unmanaged, T1 where T2_ : unmanaged, T2..." - public static readonly string[] TypeConstraintsUnderScored = CacheJoinedStrings(Separator.Space, i => $"where T_{i} : unmanaged, T{i}"); - #endregion #region Callback Delegates public const string RunCallbackDelegate = "Ecs.RunCallback"; - public const string IterCallbackDelegate = "Ecs.IterCallback"; - - public const string EachEntityCallbackDelegate = "Ecs.EachEntityCallback"; - - public const string EachIterCallbackDelegate = "Ecs.EachIterCallback"; - - // Generates "Ecs.IterFieldCallback" public static readonly string[] IterFieldCallbackDelegate = CacheStrings(i => $"Ecs.IterFieldCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.IterSpanCallback" public static readonly string[] IterSpanCallbackDelegate = CacheStrings(i => $"Ecs.IterSpanCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.IterPointerCallback" public static readonly string[] IterPointerCallbackDelegate = CacheStrings(i => $"Ecs.IterPointerCallback<{TypeParameters[i]}>"); - // Generates "Ecs.EachRefCallback" public static readonly string[] EachRefCallbackDelegate = CacheStrings(i => $"Ecs.EachRefCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.EachEntityRefCallback" public static readonly string[] EachEntityRefCallbackDelegate = CacheStrings(i => $"Ecs.EachEntityRefCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.EachIterRefCallback" public static readonly string[] EachIterRefCallbackDelegate = CacheStrings(i => $"Ecs.EachIterRefCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.EachPointerCallback" public static readonly string[] EachPointerCallbackDelegate = CacheStrings(i => $"Ecs.EachPointerCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.EachEntityPointerCallback" public static readonly string[] EachEntityPointerCallbackDelegate = CacheStrings(i => $"Ecs.EachEntityPointerCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.EachIterPointerCallback" public static readonly string[] EachIterPointerCallbackDelegate = CacheStrings(i => $"Ecs.EachIterPointerCallback<{TypeParameters[i]}>"); - // Generates "Ecs.FindRefCallback" public static readonly string[] FindRefCallbackDelegate = CacheStrings(i => $"Ecs.FindRefCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.FindEntityRefCallback" public static readonly string[] FindEntityRefCallbackDelegate = CacheStrings(i => $"Ecs.FindEntityRefCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.FindIterRefCallback" public static readonly string[] FindIterRefCallbackDelegate = CacheStrings(i => $"Ecs.FindIterRefCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.FindPointerCallback" public static readonly string[] FindPointerCallbackDelegate = CacheStrings(i => $"Ecs.FindPointerCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.FindEntityPointerCallback" public static readonly string[] FindEntityPointerCallbackDelegate = CacheStrings(i => $"Ecs.FindEntityPointerCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.FindIterPointerCallback" public static readonly string[] FindIterPointerCallbackDelegate = CacheStrings(i => $"Ecs.FindIterPointerCallback<{TypeParameters[i]}>"); - // Generates "Ecs.ReadRefCallback" public static readonly string[] ReadRefCallbackDelegate = CacheStrings(i => $"Ecs.ReadRefCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.WriteRefCallback" public static readonly string[] WriteRefCallbackDelegate = CacheStrings(i => $"Ecs.WriteRefCallback<{TypeParameters[i]}>"); - - // Generates "Ecs.InsertRefCallback" public static readonly string[] InsertRefCallbackDelegate = CacheStrings(i => $"Ecs.InsertRefCallback<{TypeParameters[i]}>"); #endregion @@ -125,120 +57,40 @@ public static class Generator public const string RunCallbackPointer = "delegate*"; - public const string IterCallbackPointer = "delegate*"; - - public const string EachEntityCallbackPointer = "delegate*"; - - public const string EachIterCallbackPointer = "delegate*"; - - // Generates "delegate*, Field, Field, void>" public static readonly string[] IterFieldCallbackPointer = CacheStrings(i => $"delegate*"); - - // Generates "delegate*, Span, Span, void>" public static readonly string[] IterSpanCallbackPointer = CacheStrings(i => $"delegate*"); - - // Generates "delegate*" public static readonly string[] IterPointerCallbackPointer = CacheStrings(i => $"delegate*"); - // Generates "delegate*" public static readonly string[] EachRefCallbackPointer = CacheStrings(i => $"delegate*<{RefTypeParameters[i]}, void>"); - - // Generates "delegate*" public static readonly string[] EachEntityRefCallbackPointer = CacheStrings(i => $"delegate*"); - - // Generates "delegate*" public static readonly string[] EachIterRefCallbackPointer = CacheStrings(i => $"delegate*"); - - // Generates "delegate*" public static readonly string[] EachPointerCallbackPointer = CacheStrings(i => $"delegate*<{PointerTypeParameters[i]}, void>"); - - // Generates "delegate*" public static readonly string[] EachEntityPointerCallbackPointer = CacheStrings(i => $"delegate*"); - - // Generates "delegate*" public static readonly string[] EachIterPointerCallbackPointer = CacheStrings(i => $"delegate*"); - // Generates "delegate*" public static readonly string[] FindRefCallbackPointer = CacheStrings(i => $"delegate*<{RefTypeParameters[i]}, bool>"); - - // Generates "delegate*" public static readonly string[] FindEntityRefCallbackPointer = CacheStrings(i => $"delegate*"); - - // Generates "delegate*" public static readonly string[] FindIterRefCallbackPointer = CacheStrings(i => $"delegate*"); - - // Generates "delegate*" public static readonly string[] FindPointerCallbackPointer = CacheStrings(i => $"delegate*<{PointerTypeParameters[i]}, bool>"); - - // Generates "delegate*" public static readonly string[] FindEntityPointerCallbackPointer = CacheStrings(i => $"delegate*"); - - // Generates "delegate*" public static readonly string[] FindIterPointerCallbackPointer = CacheStrings(i => $"delegate*"); #endregion #region Invoker - // Generates "byte* pointer0 = (byte*)it.GetPointer(0); byte* pointer1 = (byte*)it.GetPointer(1);..." - public static readonly string[] IterPointerVariables = CacheJoinedStrings(Separator.Space, i => $"byte* pointer{i} = (byte*)it.GetPointer({i});"); - - // Generates "int step0 = it.Step(0); int step1 = it.Step(1);..." - public static readonly string[] IterStepVariables = CacheJoinedStrings(Separator.Space, i => $"int step{i} = it.Step({i});"); - - // Generates "pointer0 = &pointer0[step0], pointer1 = &pointer1[step1]..." - public static readonly string[] IterPointerIncrements = CacheJoinedStrings(Separator.Comma, i => $"pointer{i} = &pointer{i}[step{i}]"); + public static readonly string[] FieldDataVariables = CacheJoinedStrings(Separator.Space, i => $"FieldData field{i} = it.GetFieldData({i});"); + public static readonly string[] FieldDataParameters = CacheJoinedStrings(Separator.Comma, i => $"ref FieldData field{i}"); + public static readonly string[] FieldDataRefs = CacheJoinedStrings(Separator.Comma, i => $"ref field{i}"); #endregion #region Invoker Callback Arguments - // Generates "it.Field(0), it.Field(1), it.Field(2)..." public static readonly string[] IterFieldArguments = CacheJoinedStrings(Separator.Comma, i => $"it.Field({i})"); - - // Generates "it.GetSpan(0), it.GetSpan(1), it.GetSpan(2)..." public static readonly string[] IterSpanArguments = CacheJoinedStrings(Separator.Comma, i => $"it.GetSpan({i})"); - - // Generates "it.GetPointer(0), it.GetPointer(1), it.GetPointer(2)..." public static readonly string[] IterPointerArguments = CacheJoinedStrings(Separator.Comma, i => $"it.GetPointer({i})"); - // Generates "ref Managed.GetTypeRef(&pointer0[i]), ref Managed.GetTypeRef(&pointer1[i]), ref Managed.GetTypeRef(&pointer2[i])..." - public static readonly string[] EachRefArguments = CacheJoinedStrings(Separator.Comma, i => $"ref Managed.GetTypeRef(&pointer{i}[i])"); - - // Generates "new Entity(it.Handle->world, it.Handle->entities[i]), ref Managed.GetTypeRef(&pointer0[i]), ref Managed.GetTypeRef(&pointer1[i]), ref Managed.GetTypeRef(&pointer2[i])" - public static readonly string[] EachEntityRefArguments = CacheStrings(i => $"new Entity(it.Handle->world, it.Handle->entities[i]), {EachRefArguments[i]}"); - - // Generates "it, i, ref Managed.GetTypeRef(&pointer0[i]), ref Managed.GetTypeRef(&pointer1[i]), ref Managed.GetTypeRef(&pointer2[i])" - public static readonly string[] EachIterRefArguments = CacheStrings(i => $"it, i, {EachRefArguments[i]}"); - - // Generates "&pointer0[i], &pointer1[i], &pointer2[i]..." - public static readonly string[] EachPointerArguments = CacheJoinedStrings(Separator.Comma, i => $"&pointer{i}[i]"); - - // Generates "new Entity(it.Handle->world, it.Handle->entities[i]), pointer0[i], &pointer1[i], &pointer2[i]" - public static readonly string[] EachEntityPointerArguments = CacheStrings(i => $"new Entity(it.Handle->world, it.Handle->entities[i]), {EachPointerArguments[i]}"); - - // Generates "it, i, pointer0[i], &pointer1[i], &pointer2[i]" - public static readonly string[] EachIterPointerArguments = CacheStrings(i => $"it, i, {EachPointerArguments[i]}"); - - // Generates "ref Managed.GetTypeRef(&pointer0[i * step0]), ref Managed.GetTypeRef(&pointer1[i * step1]), ref Managed.GetTypeRef(&pointer2[i * step2])..." - public static readonly string[] EachRefSteppedArguments = CacheJoinedStrings(Separator.Comma, i => $"ref Managed.GetTypeRef(pointer{i})"); - - // Generates "new Entity(it.Handle->world, it.Handle->entities[i]), ref Managed.GetTypeRef(&pointer0[i * step0]), ref Managed.GetTypeRef(&pointer1[i * step1]), ref Managed.GetTypeRef(&pointer2[i * step2])" - public static readonly string[] EachEntityRefSteppedArguments = CacheStrings(i => $"new Entity(it.Handle->world, it.Handle->entities[i]), {EachRefSteppedArguments[i]}"); - - // Generates "it, i, ref Managed.GetTypeRef(&pointer0[i * step0]), ref Managed.GetTypeRef(&pointer1[i * step1]), ref Managed.GetTypeRef(&pointer2[i * step2])" - public static readonly string[] EachIterRefSteppedArguments = CacheStrings(i => $"it, i, {EachRefSteppedArguments[i]}"); - - // Generates "&pointer0[i * step0], &pointer1[i * step1], &pointer2[i * step2]..." - public static readonly string[] EachPointerSteppedArguments = CacheJoinedStrings(Separator.Comma, i => $"(T{i}*)pointer{i}"); - - // Generates "new Entity(it.Handle->world, it.Handle->entities[i]), &pointer0[i * step0], &pointer1[i * step1], &pointer2[i * step2]..." - public static readonly string[] EachEntityPointerSteppedArguments = CacheStrings(i => $"new Entity(it.Handle->world, it.Handle->entities[i]), {EachPointerSteppedArguments[i]}"); - - // Generates "it, i, &pointer0[i * step0], &pointer1[i * step1], &pointer2[i * step2]..." - public static readonly string[] EachIterPointerSteppedArguments = CacheStrings(i => $"it, i, {EachPointerSteppedArguments[i]}"); - - // Generates "ref Managed.GetTypeRef(&pointers[0]), ref Managed.GetTypeRef(&pointers[0])" public static readonly string[] ReadRefArguments = CacheJoinedStrings(Separator.Comma, i => $"ref Managed.GetTypeRef(pointers[{i}])"); public static readonly string[] WriteRefArguments = ReadRefArguments; public static readonly string[] InsertRefArguments = ReadRefArguments; @@ -247,45 +99,38 @@ public static class Generator #region Entity Component Callbacks - // Generates "Type.Id(world), Type.Id(world), Type.Id(world)..." public static readonly string[] TypeIdList = CacheJoinedStrings(Separator.Comma, i => $"Type.Id(world)"); - // Generates "ecs_table_get_column_index(realWorld, table, ids[0]), ecs_table_get_column_index(realWorld, table, ids[1])..." public static readonly string[] ColumnList = CacheJoinedStrings(Separator.Comma, i => $"ecs_table_get_column_index(realWorld, table, ids[{i}])"); - // Generates "ulong* ids = stackalloc ulong[] { Type.Id(world), Type.Id(world) };" public static readonly string[] IdsArray = CacheStrings(i => $"ulong* ids = stackalloc ulong[] {{ {TypeIdList[i]} }};"); - // Generates "int* columns = stackalloc int[] { ecs_table_get_column_index(realWorld, table, ids[0]), ecs_table_get_column_index(realWorld, table, ids[1]) };" public static readonly string[] ColumnsArray = CacheStrings(i => $"int* columns = stackalloc int[] {{ {ColumnList[i]} }};"); - // Generates "ptrs[0] = ecs_ensure_id(world, e, Type.Id(world)); ptrs[1] = ecs_ensure_id(world, e, Type.Id(world));" public static readonly string[] EnsurePointers = CacheJoinedStrings(Separator.Space, i => $"ptrs[{i}] = ecs_ensure_id(world, e, Type.Id(world));"); - // Generates "ecs_modified_id(world, id, ids[0]); ecs_modified_id(world, id, ids[1]);..." public static readonly string[] ModifiedChain = CacheJoinedStrings(Separator.Space, i => $"ecs_modified_id(world, entity, ids[{i}]);"); #endregion #region Type Helpers - // Generates "(Type.IsTag ? 1 << 0 : 0) | (Type.IsTag ? 1 << 1 : 0)..." public static readonly string[] Tags = CacheJoinedStrings(Separator.BitwiseOr, i => $"(Type.IsTag ? 1 << {i} : 0)"); - // Generates "(RuntimeHelpers.IsReferenceOrContainsReferences() ? 1 << 0 : 0) | (RuntimeHelpers.IsReferenceOrContainsReferences() ? 1 << 1 : 0)..." public static readonly string[] ReferenceTypes = CacheJoinedStrings(Separator.BitwiseOr, i => $"(RuntimeHelpers.IsReferenceOrContainsReferences() ? 1 << {i} : 0)"); - // Generates "Type.FullName, Type.Fullname..." public static readonly string[] TypeFullNames = CacheJoinedStrings(Separator.Comma, i => $"Type.FullName"); + public static readonly string[] SparseBitField = CacheJoinedStrings(Separator.BitwiseOr, i => $"(ecs_has_id(world, Type.Id(world), Ecs.Sparse) == Utils.True ? 1 << {i} : 0)"); + + public static readonly string[] ContainsReferenceTypes = CacheJoinedStrings(Separator.Or, i => $"RuntimeHelpers.IsReferenceOrContainsReferences()"); + #endregion #region Misc - // Generates ".With.With().With()..." public static readonly string[] WithChain = CacheJoinedStrings(Separator.None, i => $".With()"); - // Generates "The T0 component type. The T1 component type. The T2 component type...." public static readonly string[] XmlTypeParameters = CacheJoinedStrings(Separator.Space, i => $"The T{i} component type."); #endregion @@ -547,38 +392,115 @@ Callback.FindEntityPointerCallbackPointer or }; } - public static string GetCallbackArguments(int i, Callback callback) + public static bool GetCallbackIsIter(Callback callback) { return callback switch { - Callback.IterFieldCallbackDelegate or Callback.IterFieldCallbackPointer => IterFieldArguments[i], - Callback.IterSpanCallbackDelegate or Callback.IterSpanCallbackPointer => IterSpanArguments[i], - Callback.IterPointerCallbackDelegate or Callback.IterPointerCallbackPointer => IterPointerArguments[i], - Callback.EachRefCallbackDelegate or Callback.EachRefCallbackPointer or Callback.FindRefCallbackDelegate or Callback.FindRefCallbackPointer => EachRefArguments[i], - Callback.EachEntityRefCallbackDelegate or Callback.EachEntityRefCallbackPointer or Callback.FindEntityRefCallbackDelegate or Callback.FindEntityRefCallbackPointer => EachEntityRefArguments[i], - Callback.EachIterRefCallbackDelegate or Callback.EachIterRefCallbackPointer or Callback.FindIterRefCallbackDelegate or Callback.FindIterRefCallbackPointer => EachIterRefArguments[i], - Callback.EachPointerCallbackDelegate or Callback.EachPointerCallbackPointer or Callback.FindPointerCallbackDelegate or Callback.FindPointerCallbackPointer => EachPointerArguments[i], - Callback.EachEntityPointerCallbackDelegate or Callback.EachEntityPointerCallbackPointer or Callback.FindEntityPointerCallbackDelegate or Callback.FindEntityPointerCallbackPointer => EachEntityPointerArguments[i], - Callback.EachIterPointerCallbackDelegate or Callback.EachIterPointerCallbackPointer or Callback.FindIterPointerCallbackDelegate or Callback.FindIterPointerCallbackPointer => EachIterPointerArguments[i], - Callback.ReadRefCallbackDelegate or Callback.WriteRefCallbackDelegate or Callback.InsertRefCallbackDelegate => ReadRefArguments[i], - _ => throw new ArgumentOutOfRangeException(nameof(callback), callback, null) + Callback.IterFieldCallbackDelegate or + Callback.IterFieldCallbackPointer or + Callback.IterSpanCallbackDelegate or + Callback.IterSpanCallbackPointer or + Callback.IterPointerCallbackDelegate or + Callback.IterPointerCallbackPointer => true, + _ => false }; } - public static string GetCallbackSteppedArguments(int i, Callback callback) + public static CallbackParameters GetCallbackParameters(Callback callback) { return callback switch { - Callback.EachRefCallbackDelegate or Callback.EachRefCallbackPointer or Callback.FindRefCallbackDelegate or Callback.FindRefCallbackPointer => EachRefSteppedArguments[i], - Callback.EachEntityRefCallbackDelegate or Callback.EachEntityRefCallbackPointer or Callback.FindEntityRefCallbackDelegate or Callback.FindEntityRefCallbackPointer => EachEntityRefSteppedArguments[i], - Callback.EachIterRefCallbackDelegate or Callback.EachIterRefCallbackPointer or Callback.FindIterRefCallbackDelegate or Callback.FindIterRefCallbackPointer => EachIterRefSteppedArguments[i], - Callback.EachPointerCallbackDelegate or Callback.EachPointerCallbackPointer or Callback.FindPointerCallbackDelegate or Callback.FindPointerCallbackPointer => EachPointerSteppedArguments[i], - Callback.EachEntityPointerCallbackDelegate or Callback.EachEntityPointerCallbackPointer or Callback.FindEntityPointerCallbackDelegate or Callback.FindEntityPointerCallbackPointer => EachEntityPointerSteppedArguments[i], - Callback.EachIterPointerCallbackDelegate or Callback.EachIterPointerCallbackPointer or Callback.FindIterPointerCallbackDelegate or Callback.FindIterPointerCallbackPointer => EachIterPointerSteppedArguments[i], + Callback.IterFieldCallbackDelegate or + Callback.IterFieldCallbackPointer => CallbackParameters.IterField, + + Callback.IterSpanCallbackDelegate or + Callback.IterSpanCallbackPointer => CallbackParameters.IterSpan, + + Callback.IterPointerCallbackDelegate or + Callback.IterPointerCallbackPointer => CallbackParameters.IterPointer, + + Callback.EachRefCallbackDelegate or + Callback.EachRefCallbackPointer or + Callback.FindRefCallbackDelegate or + Callback.FindRefCallbackPointer => CallbackParameters.EachRef, + + Callback.EachEntityRefCallbackDelegate or + Callback.EachEntityRefCallbackPointer or + Callback.FindEntityRefCallbackDelegate or + Callback.FindEntityRefCallbackPointer => CallbackParameters.EachEntityRef, + + Callback.EachIterRefCallbackDelegate or + Callback.EachIterRefCallbackPointer or + Callback.FindIterRefCallbackDelegate or + Callback.FindIterRefCallbackPointer => CallbackParameters.EachIterRef, + + Callback.EachPointerCallbackDelegate or + Callback.EachPointerCallbackPointer or + Callback.FindPointerCallbackDelegate or + Callback.FindPointerCallbackPointer => CallbackParameters.EachPointer, + + Callback.EachEntityPointerCallbackDelegate or + Callback.EachEntityPointerCallbackPointer or + Callback.FindEntityPointerCallbackDelegate or + Callback.FindEntityPointerCallbackPointer => CallbackParameters.EachEntityPointer, + + Callback.EachIterPointerCallbackDelegate or + Callback.EachIterPointerCallbackPointer or + Callback.FindIterPointerCallbackDelegate or + Callback.FindIterPointerCallbackPointer => CallbackParameters.EachIterPointer, + + Callback.ReadRefCallbackDelegate or + Callback.WriteRefCallbackDelegate or + Callback.InsertRefCallbackDelegate => CallbackParameters.ReadRef, + _ => throw new ArgumentOutOfRangeException(nameof(callback), callback, null) }; } + public static string GetCallbackArguments(Callback callback, int i) + { + return GetCallbackParameters(callback) switch + { + CallbackParameters.IterField => IterFieldArguments[i], + CallbackParameters.IterSpan => IterSpanArguments[i], + CallbackParameters.IterPointer => IterPointerArguments[i], + CallbackParameters.ReadRef => ReadRefArguments[i], + _ => throw new ArgumentOutOfRangeException(nameof(callback)) + }; + } + + public static string GetCallbackArguments(Callback parameters, IterationTechnique iterationTechnique, int i) + { + return GetCallbackParameters(parameters) switch + { + CallbackParameters.EachRef => $"{GetEachRefArguments(iterationTechnique, i)}", + CallbackParameters.EachPointer => $"{GetEachPointerArguments(iterationTechnique, i)}", + CallbackParameters.EachEntityRef => $"new Entity(it.Handle->world, it.Handle->entities[i]), {GetEachRefArguments(iterationTechnique, i)}", + CallbackParameters.EachEntityPointer => $"new Entity(it.Handle->world, it.Handle->entities[i]), {GetEachPointerArguments(iterationTechnique, i)}", + CallbackParameters.EachIterRef => $"it, i, {GetEachRefArguments(iterationTechnique, i)}", + CallbackParameters.EachIterPointer => $"it, i, {GetEachPointerArguments(iterationTechnique, i)}", + _ => throw new ArgumentOutOfRangeException(nameof(parameters), parameters, null) + }; + } + + public static readonly string[][] EachPointerArguments = typeof(IterationTechnique).GetEnumNames() + .Select((str) => CacheJoinedStrings(Separator.Comma, i => $"field{i}.Pointer{str}(i)")) + .ToArray(); + + public static readonly string[][] EachRefArguments = typeof(IterationTechnique).GetEnumNames() + .Select((str) => CacheJoinedStrings(Separator.Comma, i => $"ref field{i}.Ref{str}(i)")) + .ToArray(); + + public static string GetEachPointerArguments(IterationTechnique type, int i) + { + return EachPointerArguments[(int)type][i]; + } + + public static string GetEachRefArguments(IterationTechnique type, int i) + { + return EachRefArguments[(int)type][i]; + } + public static string GetCallbackCountVariable(Callback callback) { return callback switch diff --git a/src/Flecs.NET.Codegen/Helpers/IterationTechnique.cs b/src/Flecs.NET.Codegen/Helpers/IterationTechnique.cs new file mode 100644 index 00000000..b6a53024 --- /dev/null +++ b/src/Flecs.NET.Codegen/Helpers/IterationTechnique.cs @@ -0,0 +1,14 @@ +namespace Flecs.NET.Codegen.Helpers; + +public enum IterationTechnique +{ + Unmanaged, + SharedUnmanaged, + SparseUnmanaged, + SparseSharedUnmanaged, + + Managed, + SharedManaged, + SparseManaged, + SparseSharedManaged +} diff --git a/src/Flecs.NET.Codegen/Helpers/Separator.cs b/src/Flecs.NET.Codegen/Helpers/Separator.cs index aecaee5f..55af70db 100644 --- a/src/Flecs.NET.Codegen/Helpers/Separator.cs +++ b/src/Flecs.NET.Codegen/Helpers/Separator.cs @@ -7,6 +7,7 @@ public static class Separator public const string Space = " "; public const string NewLine = "\n"; public const string DoubleNewLine = "\n\n"; + public const string And = " && "; public const string Or = " || "; public const string BitwiseOr = " | "; } diff --git a/src/Flecs.NET.Examples/Observers/YieldExisting.cs b/src/Flecs.NET.Examples/Observers/YieldExisting.cs index 0a849cb0..ff2e274a 100644 --- a/src/Flecs.NET.Examples/Observers/YieldExisting.cs +++ b/src/Flecs.NET.Examples/Observers/YieldExisting.cs @@ -1,9 +1,6 @@ // Observers can enable a "YieldExisting" feature that upon creation of the // observer produces events for all entities that match the observer query. The // feature is only implemented for the builtin EcsOnAdd and EcsOnSet events. -// -// Custom events can also implement behavior for YieldExisting by adding the -// Iterable component to the event (see EcsIterable for more details). using Flecs.NET.Core; diff --git a/src/Flecs.NET.Native/Flecs.NET.Native.csproj b/src/Flecs.NET.Native/Flecs.NET.Native.csproj index 5346c0cb..7668c50d 100644 --- a/src/Flecs.NET.Native/Flecs.NET.Native.csproj +++ b/src/Flecs.NET.Native/Flecs.NET.Native.csproj @@ -10,7 +10,7 @@ true false - 4.0.0 + 4.0.1 Flecs.NET.Native.Debug Flecs.NET.Native.Release BeanCheeseBurrito diff --git a/src/Flecs.NET.Native/build.zig b/src/Flecs.NET.Native/build.zig index f109527a..97be1b05 100644 --- a/src/Flecs.NET.Native/build.zig +++ b/src/Flecs.NET.Native/build.zig @@ -20,7 +20,7 @@ pub fn compileFlecs(options: anytype, b: *Build, lib_type: LibType) void { }; lib.linkLibC(); - lib.addCSourceFile(.{ .file = b.path("../../submodules/flecs/flecs.c"), .flags = &.{} }); + lib.addCSourceFile(.{ .file = b.path("../../submodules/flecs/flecs.c"), .flags = &.{"-fno-sanitize=undefined"} }); lib.defineCMacro(if (options.optimize == .Debug) "FLECS_DEBUG" else "FLECS_NDEBUG", null); if (options.soft_assert) { diff --git a/src/Flecs.NET.Tests/CSharp/Core/QueryTests.cs b/src/Flecs.NET.Tests/CSharp/Core/QueryTests.cs index bcffc7e6..0d619519 100644 --- a/src/Flecs.NET.Tests/CSharp/Core/QueryTests.cs +++ b/src/Flecs.NET.Tests/CSharp/Core/QueryTests.cs @@ -798,7 +798,7 @@ private void EachManagedClass() Assert.True(query.IsTrue()); Assert.Equal(5, query.Count()); - query.Each(static (Iter _, int i, ref ManagedClass component) => + query.Each(static (Iter _, int _, ref ManagedClass component) => { Assert.Equal(10, component.Value); }); @@ -816,10 +816,178 @@ private void EachManagedStruct() Assert.True(query.IsTrue()); Assert.Equal(5, query.Count()); - query.Each(static (Iter it, int i, ref ManagedStruct component) => + query.Each(static (Iter _, int _, ref ManagedStruct component) => { Assert.Equal(10, component.Value); }); } + + [Fact] + private void EachSharedUnmanaged() + { + using World world = World.Create(); + + world.Component().Entity.Add(Ecs.OnInstantiate, Ecs.Inherit); + + using Query query = world.Query(); + + Entity prefab = world.Prefab() + .Set(new UnmanagedComponent(10)) + .Set(new SharedComponent(20)); + + for (int i = 0; i < 5; i++) + world.Entity().IsA(prefab); + + Assert.True(query.IsTrue()); + Assert.Equal(5, query.Count()); + + query.Each(static (Iter it, int _, ref UnmanagedComponent c1, ref SharedComponent c2) => + { + Assert.Equal(IterationTechnique.Shared, it.GetIterationTechnique(2)); + Assert.Equal(10, c1.Value); + Assert.Equal(20, c2.Value); + }); + } + + [Fact] + private void EachSharedManaged() + { + using World world = World.Create(); + + world.Component().Entity.Add(Ecs.OnInstantiate, Ecs.Inherit); + + using Query query = world.Query(); + + Entity prefab = world.Prefab() + .Set(new ManagedComponent(10)) + .Set(new SharedComponent(20)); + + for (int i = 0; i < 5; i++) + world.Entity().IsA(prefab); + + Assert.True(query.IsTrue()); + Assert.Equal(5, query.Count()); + + query.Each(static (Iter it, int _, ref ManagedComponent c1, ref SharedComponent c2) => + { + Assert.Equal(IterationTechnique.Shared, it.GetIterationTechnique(2)); + Assert.Equal(10, c1.Value); + Assert.Equal(20, c2.Value); + }); + } + + [Fact] + private void EachSparseUnmanaged() + { + using World world = World.Create(); + + world.Component().Entity.Add(Ecs.Sparse); + + using Query query = world.Query(); + + Entity prefab = world.Prefab() + .Set(new UnmanagedComponent(10)) + .Set(new SparseComponent(20)); + + for (int i = 0; i < 5; i++) + world.Entity().IsA(prefab); + + Assert.True(query.IsTrue()); + Assert.Equal(5, query.Count()); + + query.Each(static (Iter it, int _, ref UnmanagedComponent c1, ref SparseComponent c2) => + { + Assert.Equal(IterationTechnique.Sparse, it.GetIterationTechnique(2)); + Assert.Equal(10, c1.Value); + Assert.Equal(20, c2.Value); + }); + } + + [Fact] + private void EachSparseManaged() + { + using World world = World.Create(); + + world.Component().Entity.Add(Ecs.Sparse); + + using Query query = world.Query(); + + Entity prefab = world.Prefab() + .Set(new ManagedComponent(10)) + .Set(new SparseComponent(20)); + + for (int i = 0; i < 5; i++) + world.Entity().IsA(prefab); + + Assert.True(query.IsTrue()); + Assert.Equal(5, query.Count()); + + query.Each(static (Iter it, int _, ref ManagedComponent c1, ref SparseComponent c2) => + { + Assert.Equal(IterationTechnique.Sparse, it.GetIterationTechnique(2)); + Assert.Equal(10, c1.Value); + Assert.Equal(20, c2.Value); + }); + } + + [Fact] + private void EachSparseSharedUnmanaged() + { + using World world = World.Create(); + + world.Component().Entity.Add(Ecs.Sparse); + world.Component().Entity.Add(Ecs.OnInstantiate, Ecs.Inherit); + + using Query query = world.Query(); + + Entity prefab = world.Prefab() + .Set(new UnmanagedComponent(10)) + .Set(new SparseComponent(20)) + .Set(new SharedComponent(30)); + + for (int i = 0; i < 5; i++) + world.Entity().IsA(prefab); + + Assert.True(query.IsTrue()); + Assert.Equal(5, query.Count()); + + query.Each(static (Iter it, int _, ref UnmanagedComponent c1, ref SparseComponent c2, ref SharedComponent c3) => + { + Assert.Equal(IterationTechnique.Sparse | IterationTechnique.Shared, it.GetIterationTechnique(3)); + Assert.Equal(10, c1.Value); + Assert.Equal(20, c2.Value); + Assert.Equal(30, c3.Value); + }); + } + + [Fact] + private void EachSparseSharedManaged() + { + using World world = World.Create(); + + world.Component().Entity.Add(Ecs.Sparse); + world.Component().Entity.Add(Ecs.OnInstantiate, Ecs.Inherit); + + using Query query = world.Query(); + + Entity prefab = world.Prefab() + .Set(new ManagedComponent(10)) + .Set(new SparseComponent(20)) + .Set(new SharedComponent(30)); + + for (int i = 0; i < 5; i++) + world.Entity().IsA(prefab); + + Assert.True(query.IsTrue()); + Assert.Equal(5, query.Count()); + + query.Each(static (Iter it, int _, ref ManagedComponent c1, ref SparseComponent c2, ref SharedComponent c3) => + { + Assert.Equal(IterationTechnique.Sparse | IterationTechnique.Shared, it.GetIterationTechnique(3)); + Assert.Equal(10, c1.Value); + Assert.Equal(20, c2.Value); + Assert.Equal(30, c3.Value); + }); + } } } diff --git a/src/Flecs.NET.Tests/CSharp/Core/TypeRegistrationTests.cs b/src/Flecs.NET.Tests/CSharp/Core/TypeRegistrationTests.cs index 2fb9c493..13385080 100644 --- a/src/Flecs.NET.Tests/CSharp/Core/TypeRegistrationTests.cs +++ b/src/Flecs.NET.Tests/CSharp/Core/TypeRegistrationTests.cs @@ -85,7 +85,7 @@ private void TypeEnum(bool scoped) Assert.True(green.Has(EcsConstant, Ecs.Wildcard)); Assert.True(blue.Has(EcsConstant, Ecs.Wildcard)); } - + [Fact] private void ComponentStructReflection() { @@ -97,14 +97,14 @@ private void ComponentStructReflection() Assert.True(world.Entity(posComponent).Has()); Assert.Equal(typeof(Position), world.Entity(posComponent).Get()); } - + [Fact] private void ComponentClassReflection() { using World world = World.Create(); world.Component(); - Entity entity = world.Entity("Test").Set(new ManagedComponent()); + Entity entity = world.Entity("Test").Set(new ManagedComponent(1)); Id comp = entity.Table().Type().Get(0); Assert.True(world.Entity(comp).Has()); Assert.Equal(typeof(ManagedComponent), world.Entity(comp).Get()); diff --git a/src/Flecs.NET.Tests/Cpp/ObserverTests.cs b/src/Flecs.NET.Tests/Cpp/ObserverTests.cs index 304ee7d4..930d1ac4 100644 --- a/src/Flecs.NET.Tests/Cpp/ObserverTests.cs +++ b/src/Flecs.NET.Tests/Cpp/ObserverTests.cs @@ -870,6 +870,29 @@ private void OnSetWithDeferSet() Assert.Equal(1, count); } + [Fact] + private void OnSetWithSetSetSparse() + { + using World world = World.Create(); + + world.Component().Entity.Add(Ecs.Sparse); + + int count = 0; + + world.Observer() + .Event(Ecs.OnSet) + .Each((Entity _, ref Position _) => + { + count++; + }); + + Entity e = world.Entity(); + Assert.Equal(0, count); + + e.Set(new Position(10, 20)); + Assert.Equal(1, count); + } + [Fact] private void OnAddSingleton() { diff --git a/src/Flecs.NET.Tests/Cpp/QueryTests.cs b/src/Flecs.NET.Tests/Cpp/QueryTests.cs index 083e851b..458fcd72 100644 --- a/src/Flecs.NET.Tests/Cpp/QueryTests.cs +++ b/src/Flecs.NET.Tests/Cpp/QueryTests.cs @@ -566,7 +566,7 @@ private void FindWithEntity() } [Fact] - private void Action() + private void Run() { using World world = World.Create(); @@ -600,7 +600,7 @@ private void Action() } [Fact] - private void ActionConst() + private void RunConst() { using World world = World.Create(); @@ -634,7 +634,7 @@ private void ActionConst() } [Fact] - private void ActionShared() + private void RunShared() { using World world = World.Create(); @@ -688,7 +688,7 @@ private void ActionShared() } [Fact] - private void ActionOptional() + private void RunOptional() { using World world = World.Create(); @@ -757,6 +757,40 @@ private void ActionOptional() Assert.Equal(81, p->Y); } + [Fact] + private void RunSparse() + { + using World world = World.Create(); + + world.Component().Entity.Add(Ecs.Sparse); + world.Component(); + + Entity entity = world.Entity() + .Set(new Position(10, 20)) + .Set(new Velocity(1, 2)); + + Query q = world.Query(); + + q.Run((Iter it) => + { + while (it.Next()) + { + Field v = it.Field(1); + + foreach (int i in it) + { + ref Position p = ref it.FieldAt(0, i); + p.X += v[i].X; + p.Y += v[i].Y; + } + } + }); + + Position* p = entity.GetPtr(); + Assert.Equal(11, p->X); + Assert.Equal(22, p->Y); + } + [Fact] private void Each() { @@ -912,6 +946,31 @@ private void EachOptional() Assert.Equal(81, p->Y); } + [Fact] + private void EachSparse() + { + using World world = World.Create(); + + world.Component().Entity.Add(Ecs.Sparse); + world.Component(); + + Entity entity = world.Entity() + .Set(new Position(10, 20)) + .Set(new Velocity(1, 2)); + + Query q = world.Query(); + + q.Each((ref Position p, ref Velocity v) => + { + p.X += v.X; + p.Y += v.Y; + }); + + Position* p = entity.GetPtr(); + Assert.Equal(11, p->X); + Assert.Equal(22, p->Y); + } + [Fact] private void Signature() { diff --git a/src/Flecs.NET.Tests/Helpers.cs b/src/Flecs.NET.Tests/Helpers.cs index 2b5e81dd..71741cd3 100644 --- a/src/Flecs.NET.Tests/Helpers.cs +++ b/src/Flecs.NET.Tests/Helpers.cs @@ -29,6 +29,11 @@ public record struct Other(int Value); public record struct Singleton(int Value); public record struct PositionInitialized(float X, float Y); +public record ManagedComponent(int Value); +public record struct UnmanagedComponent(int Value); +public record struct SharedComponent(int Value); +public record struct SparseComponent(int Value); + public record struct ManagedStruct(int Value) { public object Dummy = null!; @@ -40,13 +45,6 @@ public class ManagedClass(int value) public object Dummy = null!; } -public class ManagedComponent -{ - public string Value = null!; - public ManagedComponent Nested = null!; -} - - public struct Base; public struct Prefab; diff --git a/src/Flecs.NET/Core/BindingContext/Functions.cs b/src/Flecs.NET/Core/BindingContext/Functions.cs index 10c5a5c0..37e63c7a 100644 --- a/src/Flecs.NET/Core/BindingContext/Functions.cs +++ b/src/Flecs.NET/Core/BindingContext/Functions.cs @@ -459,522 +459,325 @@ internal static void ManagedCopyCallbackPointer(GCHandle* dst, GCHandle* src, in internal static void OnAddIterFieldCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.IterFieldCallback callback = (Ecs.IterFieldCallback)context->OnAdd.GcHandle.Target!; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Field(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (Ecs.IterFieldCallback)context->OnAdd.GcHandle.Target!); } internal static void OnAddIterFieldCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate*, void> callback = (delegate*, void>)context->OnAdd.Pointer; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Field(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (delegate*, void>)context->OnAdd.Pointer); } internal static void OnAddIterSpanCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.IterSpanCallback callback = (Ecs.IterSpanCallback)context->OnAdd.GcHandle.Target!; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Span(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (Ecs.IterSpanCallback)context->OnAdd.GcHandle.Target!); } internal static void OnAddIterSpanCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate*, void> callback = (delegate*, void>)context->OnAdd.Pointer; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Span(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (delegate*, void>)context->OnAdd.Pointer); } internal static void OnAddIterPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.IterPointerCallback callback = (Ecs.IterPointerCallback)context->OnAdd.GcHandle.Target!; - - for (int i = 0; i < iter->count; i++) - callback(iter, (T0*)iter->ptrs[0]); + Invoker.Iter(iter, (Ecs.IterPointerCallback)context->OnAdd.GcHandle.Target!); } internal static void OnAddIterPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnAdd.Pointer; - - for (int i = 0; i < iter->count; i++) - callback(iter, (T0*)iter->ptrs[0]); + Invoker.Iter(iter, (delegate*)context->OnAdd.Pointer); } internal static void OnAddEachRefCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachRefCallback callback = (Ecs.EachRefCallback)context->OnAdd.GcHandle.Target!; + Invoker.Each(iter, (Ecs.EachRefCallback)context->OnAdd.GcHandle.Target!); - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(ref Managed.GetTypeRef(&pointer[i])); } internal static void OnAddEachRefCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnAdd.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (delegate*)context->OnAdd.Pointer); } internal static void OnAddEachEntityRefCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachEntityRefCallback callback = (Ecs.EachEntityRefCallback)context->OnAdd.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (Ecs.EachEntityRefCallback)context->OnAdd.GcHandle.Target!); } internal static void OnAddEachEntityRefCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnAdd.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (delegate*)context->OnAdd.Pointer); } internal static void OnAddEachIterRefCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachIterRefCallback callback = (Ecs.EachIterRefCallback)context->OnAdd.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (Ecs.EachIterRefCallback)context->OnAdd.GcHandle.Target!); } internal static void OnAddEachIterRefCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnAdd.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (delegate*)context->OnAdd.Pointer); } internal static void OnAddEachPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachPointerCallback callback = (Ecs.EachPointerCallback)context->OnAdd.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(&pointer[i]); + Invoker.Each(iter, (Ecs.EachPointerCallback)context->OnAdd.GcHandle.Target!); } internal static void OnAddEachPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnAdd.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(&pointer[i]); + Invoker.Each(iter, (delegate*)context->OnAdd.Pointer); } internal static void OnAddEachEntityPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachEntityPointerCallback callback = (Ecs.EachEntityPointerCallback)context->OnAdd.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), &pointer[i]); + Invoker.Each(iter, (Ecs.EachEntityPointerCallback)context->OnAdd.GcHandle.Target!); } internal static void OnAddEachEntityPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnAdd.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), &pointer[i]); + Invoker.Each(iter, (delegate*)context->OnAdd.Pointer); } internal static void OnAddEachIterPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachIterPointerCallback callback = (Ecs.EachIterPointerCallback)context->OnAdd.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, &pointer[i]); + Invoker.Each(iter, (Ecs.EachIterPointerCallback)context->OnAdd.GcHandle.Target!); } internal static void OnAddEachIterPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnAdd.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, &pointer[i]); + Invoker.Each(iter, (delegate*)context->OnAdd.Pointer); } internal static void OnSetIterFieldCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.IterFieldCallback callback = (Ecs.IterFieldCallback)context->OnSet.GcHandle.Target!; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Field(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (Ecs.IterFieldCallback)context->OnSet.GcHandle.Target!); } internal static void OnSetIterFieldCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate*, void> callback = (delegate*, void>)context->OnSet.Pointer; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Field(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (delegate*, void>)context->OnSet.Pointer); } internal static void OnSetIterSpanCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.IterSpanCallback callback = (Ecs.IterSpanCallback)context->OnSet.GcHandle.Target!; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Span(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (Ecs.IterSpanCallback)context->OnSet.GcHandle.Target!); } internal static void OnSetIterSpanCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate*, void> callback = (delegate*, void>)context->OnSet.Pointer; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Span(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (delegate*, void>)context->OnSet.Pointer); } internal static void OnSetIterPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.IterPointerCallback callback = (Ecs.IterPointerCallback)context->OnSet.GcHandle.Target!; - - for (int i = 0; i < iter->count; i++) - callback(iter, (T0*)iter->ptrs[0]); + Invoker.Iter(iter, (Ecs.IterPointerCallback)context->OnSet.GcHandle.Target!); } internal static void OnSetIterPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnSet.Pointer; - - for (int i = 0; i < iter->count; i++) - callback(iter, (T0*)iter->ptrs[0]); + Invoker.Iter(iter, (delegate*)context->OnSet.Pointer); } internal static void OnSetEachRefCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachRefCallback callback = (Ecs.EachRefCallback)context->OnSet.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (Ecs.EachRefCallback)context->OnSet.GcHandle.Target!); } internal static void OnSetEachRefCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnSet.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (delegate*)context->OnSet.Pointer); } internal static void OnSetEachEntityRefCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachEntityRefCallback callback = (Ecs.EachEntityRefCallback)context->OnSet.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (Ecs.EachEntityRefCallback)context->OnSet.GcHandle.Target!); } internal static void OnSetEachEntityRefCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnSet.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (delegate*)context->OnSet.Pointer); } internal static void OnSetEachIterRefCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachIterRefCallback callback = (Ecs.EachIterRefCallback)context->OnSet.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (Ecs.EachIterRefCallback)context->OnSet.GcHandle.Target!); } internal static void OnSetEachIterRefCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnSet.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (delegate*)context->OnSet.Pointer); } internal static void OnSetEachPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachPointerCallback callback = (Ecs.EachPointerCallback)context->OnSet.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(&pointer[i]); + Invoker.Each(iter, (Ecs.EachPointerCallback)context->OnSet.GcHandle.Target!); } internal static void OnSetEachPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnSet.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(&pointer[i]); + Invoker.Each(iter, (delegate*)context->OnSet.Pointer); } internal static void OnSetEachEntityPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachEntityPointerCallback callback = (Ecs.EachEntityPointerCallback)context->OnSet.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), &pointer[i]); + Invoker.Each(iter, (Ecs.EachEntityPointerCallback)context->OnSet.GcHandle.Target!); } internal static void OnSetEachEntityPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnSet.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), &pointer[i]); + Invoker.Each(iter, (delegate*)context->OnSet.Pointer); } internal static void OnSetEachIterPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachIterPointerCallback callback = (Ecs.EachIterPointerCallback)context->OnSet.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, &pointer[i]); + Invoker.Each(iter, (Ecs.EachIterPointerCallback)context->OnSet.GcHandle.Target!); } internal static void OnSetEachIterPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnSet.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, &pointer[i]); + Invoker.Each(iter, (delegate*)context->OnSet.Pointer); } internal static void OnRemoveIterFieldCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.IterFieldCallback callback = (Ecs.IterFieldCallback)context->OnRemove.GcHandle.Target!; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Field(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (Ecs.IterFieldCallback)context->OnRemove.GcHandle.Target!); } internal static void OnRemoveIterFieldCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate*, void> callback = (delegate*, void>)context->OnRemove.Pointer; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Field(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (delegate*, void>)context->OnRemove.Pointer); } internal static void OnRemoveIterSpanCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.IterSpanCallback callback = (Ecs.IterSpanCallback)context->OnRemove.GcHandle.Target!; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Span(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (Ecs.IterSpanCallback)context->OnRemove.GcHandle.Target!); } internal static void OnRemoveIterSpanCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate*, void> callback = (delegate*, void>)context->OnRemove.Pointer; - - for (int i = 0; i < iter->count; i++) - callback(iter, new Span(iter->ptrs[0], iter->count)); + Invoker.Iter(iter, (delegate*, void>)context->OnRemove.Pointer); } internal static void OnRemoveIterPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.IterPointerCallback callback = (Ecs.IterPointerCallback)context->OnRemove.GcHandle.Target!; - - for (int i = 0; i < iter->count; i++) - callback(iter, (T0*)iter->ptrs[0]); + Invoker.Iter(iter, (Ecs.IterPointerCallback)context->OnRemove.GcHandle.Target!); } internal static void OnRemoveIterPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnRemove.Pointer; - - for (int i = 0; i < iter->count; i++) - callback(iter, (T0*)iter->ptrs[0]); + Invoker.Iter(iter, (delegate*)context->OnRemove.Pointer); } internal static void OnRemoveEachRefCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachRefCallback callback = (Ecs.EachRefCallback)context->OnRemove.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (Ecs.EachRefCallback)context->OnRemove.GcHandle.Target!); } internal static void OnRemoveEachRefCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnRemove.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (delegate*)context->OnRemove.Pointer); } internal static void OnRemoveEachEntityRefCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachEntityRefCallback callback = (Ecs.EachEntityRefCallback)context->OnRemove.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (Ecs.EachEntityRefCallback)context->OnRemove.GcHandle.Target!); } internal static void OnRemoveEachEntityRefCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnRemove.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (delegate*)context->OnRemove.Pointer); } internal static void OnRemoveEachIterRefCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachIterRefCallback callback = (Ecs.EachIterRefCallback)context->OnRemove.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (Ecs.EachIterRefCallback)context->OnRemove.GcHandle.Target!); } internal static void OnRemoveEachIterRefCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnRemove.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, ref Managed.GetTypeRef(&pointer[i])); + Invoker.Each(iter, (delegate*)context->OnRemove.Pointer); } internal static void OnRemoveEachPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachPointerCallback callback = (Ecs.EachPointerCallback)context->OnRemove.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(&pointer[i]); + Invoker.Each(iter, (Ecs.EachPointerCallback)context->OnRemove.GcHandle.Target!); } internal static void OnRemoveEachPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnRemove.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(&pointer[i]); + Invoker.Each(iter, (delegate*)context->OnRemove.Pointer); } internal static void OnRemoveEachEntityPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachEntityPointerCallback callback = (Ecs.EachEntityPointerCallback)context->OnRemove.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), &pointer[i]); + Invoker.Each(iter, (Ecs.EachEntityPointerCallback)context->OnRemove.GcHandle.Target!); } internal static void OnRemoveEachEntityPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnRemove.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Entity(iter->world, iter->entities[i]), &pointer[i]); + Invoker.Each(iter, (delegate*)context->OnRemove.Pointer); } internal static void OnRemoveEachIterPointerCallbackDelegate(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - Ecs.EachIterPointerCallback callback = (Ecs.EachIterPointerCallback)context->OnRemove.GcHandle.Target!; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, &pointer[i]); + Invoker.Each(iter, (Ecs.EachIterPointerCallback)context->OnRemove.GcHandle.Target!); } internal static void OnRemoveEachIterPointerCallbackPointer(ecs_iter_t* iter) { TypeHooksContext* context = (TypeHooksContext*)iter->callback_ctx; - delegate* callback = (delegate*)context->OnRemove.Pointer; - - T0* pointer = (T0*)iter->ptrs[0]; - for (int i = 0; i < iter->count; i++) - callback(new Iter(iter), i, &pointer[i]); + Invoker.Each(iter, (delegate*)context->OnRemove.Pointer); } } diff --git a/src/Flecs.NET/Core/Ecs/Aliases.cs b/src/Flecs.NET/Core/Ecs/Aliases.cs index 8af26c44..ceebe6a4 100644 --- a/src/Flecs.NET/Core/Ecs/Aliases.cs +++ b/src/Flecs.NET/Core/Ecs/Aliases.cs @@ -644,11 +644,6 @@ public static partial class Ecs /// public const uint QueryMatchEmptyTables = EcsQueryMatchEmptyTables; - /// - /// Query won't provide component data. - /// - public const uint QueryNoData = EcsQueryNoData; - /// /// Query may have unresolved entity identifiers. /// diff --git a/src/Flecs.NET/Core/Ecs/Macros.cs b/src/Flecs.NET/Core/Ecs/Macros.cs index eedd59e4..767852e9 100644 --- a/src/Flecs.NET/Core/Ecs/Macros.cs +++ b/src/Flecs.NET/Core/Ecs/Macros.cs @@ -315,4 +315,10 @@ internal static ref QueryBuilder GetQueryBuilder(ref T queryBuilder) where T { return ref queryBuilder.QueryBuilder; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static ref ecs_world_t* GetIterableWorld(ref T obj) where T : IIterableBase + { + return ref obj.World; + } } diff --git a/src/Flecs.NET/Core/Field.cs b/src/Flecs.NET/Core/Field.cs index c83d5eae..c568064b 100644 --- a/src/Flecs.NET/Core/Field.cs +++ b/src/Flecs.NET/Core/Field.cs @@ -21,11 +21,6 @@ namespace Flecs.NET.Core; /// public int Length { get; } - /// - /// Specifies if the field is shared. - /// - public bool IsShared { get; } - /// /// Specifies if the field pointer is null. /// @@ -36,12 +31,10 @@ namespace Flecs.NET.Core; /// /// /// - /// - public Field(void* data, int length, bool isShared = false) + public Field(void* data, int length) { Data = data; Length = length; - IsShared = isShared; } /// @@ -53,8 +46,7 @@ public ref T this[int index] [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - Ecs.Assert(index < Length, nameof(ECS_COLUMN_INDEX_OUT_OF_RANGE)); - Ecs.Assert(index == 0 || !IsShared, nameof(ECS_INVALID_PARAMETER)); + Ecs.Assert(index >= 0 && index < Length, nameof(ECS_COLUMN_INDEX_OUT_OF_RANGE)); Ecs.Assert(Data != null, nameof(ECS_COLUMN_INDEX_OUT_OF_RANGE)); return ref Managed.GetTypeRef(Data, index); } @@ -110,4 +102,4 @@ public override int GetHashCode() { return !(left == right); } -} \ No newline at end of file +} diff --git a/src/Flecs.NET/Core/FieldData.cs b/src/Flecs.NET/Core/FieldData.cs new file mode 100644 index 00000000..2d7c3112 --- /dev/null +++ b/src/Flecs.NET/Core/FieldData.cs @@ -0,0 +1,130 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Flecs.NET.Utilities; +using static Flecs.NET.Bindings.flecs; + +namespace Flecs.NET.Core; + +internal unsafe struct FieldData() +{ + public T* Pointer; + public ecs_iter_t* Iter; + public byte Index; // Field index. + public bool IsShared; // Is 0 indexed component. + public bool IsSparse; // Is sparse component. + + public FieldData(ecs_iter_t* iter, byte index) : this() + { + Iter = iter; + Index = index; + + if (Utils.IsBitSet(iter->row_fields, index)) + { + IsSparse = true; + } + else + { + Pointer = (T*)ecs_field_w_size(iter, Type.Size, index); + IsShared = iter->sources[index] != 0 || !Utils.IsBitSet(iter->set_fields, index); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly T* PointerUnmanaged(int row) + { + return &Pointer[row]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly T* PointerSharedUnmanaged(int row) + { + return IsShared ? PointerUnmanaged(0) : PointerUnmanaged(row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly T* PointerSparseUnmanaged(int row) + { + return IsSparse ? (T*)ecs_field_at_w_size(Iter, Type.Size, Index, row) : PointerUnmanaged(row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly T* PointerSparseSharedUnmanaged(int row) + { + return IsSparse ? (T*)ecs_field_at_w_size(Iter, Type.Size, Index, row) : PointerSharedUnmanaged(row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly T* PointerManaged(int row) + { + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + return (T*)&((GCHandle*)Pointer)[row]; + + return &Pointer[row]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly T* PointerSharedManaged(int row) + { + return IsShared ? PointerManaged(0) : PointerManaged(row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly T* PointerSparseManaged(int row) + { + return IsSparse ? (T*)ecs_field_at_w_size(Iter, Type.Size, Index, row) : PointerManaged(row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly T* PointerSparseSharedManaged(int row) + { + return IsSparse ? (T*)ecs_field_at_w_size(Iter, Type.Size, Index, row) : PointerSharedManaged(row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ref T RefUnmanaged(int row) + { + return ref *PointerUnmanaged(row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ref T RefSharedUnmanaged(int row) + { + return ref *PointerSharedUnmanaged(row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ref T RefSparseUnmanaged(int row) + { + return ref *PointerSparseUnmanaged(row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ref T RefSparseSharedUnmanaged(int row) + { + return ref *PointerSparseSharedUnmanaged(row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ref T RefManaged(int row) + { + return ref Managed.GetTypeRef(PointerManaged(row)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ref T RefSharedManaged(int row) + { + return ref Managed.GetTypeRef(PointerSharedManaged(row)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ref T RefSparseManaged(int row) + { + return ref Managed.GetTypeRef(PointerSparseManaged(row)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ref T RefSparseSharedManaged(int row) + { + return ref Managed.GetTypeRef(PointerSparseSharedManaged(row)); + } +} diff --git a/src/Flecs.NET/Core/IIterableBase.cs b/src/Flecs.NET/Core/IIterableBase.cs index 88b71ea1..51fd7892 100644 --- a/src/Flecs.NET/Core/IIterableBase.cs +++ b/src/Flecs.NET/Core/IIterableBase.cs @@ -7,6 +7,11 @@ namespace Flecs.NET.Core; /// public unsafe interface IIterableBase { + /// + /// Reference to the world. + /// + public ref ecs_world_t* World { get; } + /// /// Iterate a query. /// diff --git a/src/Flecs.NET/Core/Invoker.cs b/src/Flecs.NET/Core/Invoker.cs index cc05aea1..1f42e02b 100644 --- a/src/Flecs.NET/Core/Invoker.cs +++ b/src/Flecs.NET/Core/Invoker.cs @@ -40,8 +40,6 @@ public static void Each(ecs_iter_t* iter, Ecs.EachEntityCallback callback) { Ecs.Assert(iter->count > 0, "No entities returned, use Iter() or Each() without the entity argument instead."); - iter->flags |= EcsIterCppEach; - Ecs.TableLock(iter->world, iter->table); for (int i = 0; i < iter->count; i++) @@ -57,8 +55,6 @@ public static void Each(ecs_iter_t* iter, Ecs.EachEntityCallback callback) /// public static void Each(ecs_iter_t* iter, Ecs.EachIterCallback callback) { - iter->flags |= EcsIterCppEach; - Ecs.TableLock(iter->world, iter->table); int count = iter->count == 0 && iter->table == null ? 1 : iter->count; @@ -228,8 +224,6 @@ public static void Each(ecs_iter_t* iter, delegate* callback) { Ecs.Assert(iter->count > 0, "No entities returned, use Iter() or Each() without the entity argument instead."); - iter->flags |= EcsIterCppEach; - Ecs.TableLock(iter->world, iter->table); for (int i = 0; i < iter->count; i++) @@ -245,8 +239,6 @@ public static void Each(ecs_iter_t* iter, delegate* callback) /// public static void Each(ecs_iter_t* iter, delegate* callback) { - iter->flags |= EcsIterCppEach; - Ecs.TableLock(iter->world, iter->table); int count = iter->count == 0 && iter->table == null ? 1 : iter->count; @@ -406,4 +398,4 @@ public static void Run(ref T iterable, delegate* callback) where ecs_iter_t iter = iterable.GetIter(); Run(&iter, callback); } -} \ No newline at end of file +} diff --git a/src/Flecs.NET/Core/Iter.cs b/src/Flecs.NET/Core/Iter.cs index 06f293bf..3e0a4ab8 100644 --- a/src/Flecs.NET/Core/Iter.cs +++ b/src/Flecs.NET/Core/Iter.cs @@ -208,7 +208,7 @@ public Entity Entity(int row) public bool IsSelf(int index) { Ecs.Assert(index < Handle->field_count, "Field index out of range."); - return ecs_field_is_self(Handle, index) == 1; + return ecs_field_is_self(Handle, (byte)index) == 1; } /// @@ -219,7 +219,7 @@ public bool IsSelf(int index) public bool IsSet(int index) { Ecs.Assert(index < Handle->field_count, "Field index out of range."); - return ecs_field_is_set(Handle, index) == 1; + return ecs_field_is_set(Handle, (byte)index) == 1; } /// @@ -230,7 +230,7 @@ public bool IsSet(int index) public bool IsReadonly(int index) { Ecs.Assert(index < Handle->field_count, "Field index out of range."); - return ecs_field_is_readonly(Handle, index) == 1; + return ecs_field_is_readonly(Handle, (byte)index) == 1; } /// @@ -250,7 +250,7 @@ public int FieldCount() public ulong Size(int index) { Ecs.Assert(index < Handle->field_count, "Field index out of range."); - return (ulong)ecs_field_size(Handle, index); + return (ulong)ecs_field_size(Handle, (byte)index); } /// @@ -261,7 +261,7 @@ public ulong Size(int index) public Entity Src(int index) { Ecs.Assert(index < Handle->field_count, "Field index out of range."); - return new Entity(Handle->world, ecs_field_src(Handle, index)); + return new Entity(Handle->world, ecs_field_src(Handle, (byte)index)); } /// @@ -272,7 +272,7 @@ public Entity Src(int index) public Id Id(int index) { Ecs.Assert(index < Handle->field_count, "Field index out of range."); - return new Id(Handle->world, ecs_field_id(Handle, index)); + return new Id(Handle->world, ecs_field_id(Handle, (byte)index)); } /// @@ -284,7 +284,7 @@ public Id Id(int index) public Id Pair(int index) { Ecs.Assert(index < Handle->field_count, "Field index out of range."); - ulong id = ecs_field_id(Handle, index); + ulong id = ecs_field_id(Handle, (byte)index); Ecs.Assert(Ecs.EntityHasIdFlag(id, ECS_PAIR) != 0, nameof(ECS_INVALID_PARAMETER)); return new Id(Handle->world, id); } @@ -297,7 +297,7 @@ public Id Pair(int index) public int ColumnIndex(int index) { Ecs.Assert(index < Handle->field_count, "Field index out of range."); - return ecs_field_column(Handle, index); + return ecs_field_column(Handle, (byte)index); } /// @@ -331,7 +331,9 @@ public Field Field(int index) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref T FieldAt(int index, int row) { - return ref GetField(index)[row]; + return ref Utils.IsBitSet(Handle->row_fields, index) + ? ref GetFieldAt(index, row)[0] + : ref GetField(index)[row]; } /// @@ -456,8 +458,18 @@ public void Fini() internal Field GetField(int index) { AssertField(Handle, index); - bool isShared = ecs_field_is_self(Handle, index) == 0; - return new Field(Handle->ptrs[index], isShared ? 1 : Handle->count, isShared); + + return new Field( + ecs_field_w_size(Handle, Type.Size, (byte)index), + ecs_field_is_self(Handle, (byte)index) == Utils.True ? Handle->count : 1 + ); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Field GetFieldAt(int index, int row) + { + AssertField(Handle, index); + return new Field(ecs_field_at_w_size(Handle, Type.Size, (byte)index, row), 1); } [Conditional("DEBUG")] @@ -676,19 +688,30 @@ internal Span GetSpan(int index) internal T* GetPointer(int index) { AssertField(Handle, index); - return (T*)Handle->ptrs[index]; + return (T*)ecs_field_w_size(Handle, Type.Size, (byte)index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal int Step(int index) + internal FieldData GetFieldData(byte index) { - return (Handle->sources == null || Handle->sources[index] == 0) && (Handle->set_fields & (1 << index)) != 0 && !Type.IsTag ? Type.Size : 0; + AssertField(Handle, index); + return new FieldData(Handle, index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal bool IsLinear() + internal IterationTechnique GetIterationTechnique(int fieldCount) { - return Handle->shared_fields == 0 && Handle->set_fields == (1 << Handle->field_count) - 1; + IterationTechnique flags = default; + + int mask = (1 << fieldCount) - 1; + + if ((Handle->row_fields & mask) != 0) + flags |= IterationTechnique.Sparse; + + if (((Handle->ref_fields & mask) != 0 && Handle->ref_fields != Handle->row_fields) || (Handle->up_fields & mask) != 0 || (Handle->set_fields & mask) != mask) + flags |= IterationTechnique.Shared; + + return flags; } } diff --git a/src/Flecs.NET/Core/IterIterable.cs b/src/Flecs.NET/Core/IterIterable.cs index dfad9f9c..c230b972 100644 --- a/src/Flecs.NET/Core/IterIterable.cs +++ b/src/Flecs.NET/Core/IterIterable.cs @@ -299,6 +299,9 @@ public override int GetHashCode() // IIterableBase Interface public unsafe partial struct IterIterable { + /// + public ref ecs_world_t* World => ref _iter.world; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ecs_iter_t GetIter(ecs_world_t* world = null) diff --git a/src/Flecs.NET/Core/IterationTechnique.cs b/src/Flecs.NET/Core/IterationTechnique.cs new file mode 100644 index 00000000..de6ab49c --- /dev/null +++ b/src/Flecs.NET/Core/IterationTechnique.cs @@ -0,0 +1,22 @@ +using System; + +namespace Flecs.NET.Core; + +[Flags] +internal enum IterationTechnique +{ + /// + /// Indicates default enum value. + /// + None = 0, + + /// + /// Indicates that query contains shared components. + /// + Shared = 1, + + /// + /// Indicates that query contains sparse components. + /// + Sparse = 2 +} diff --git a/src/Flecs.NET/Core/PageIterable.cs b/src/Flecs.NET/Core/PageIterable.cs index 8f031acd..b071bb75 100644 --- a/src/Flecs.NET/Core/PageIterable.cs +++ b/src/Flecs.NET/Core/PageIterable.cs @@ -82,6 +82,9 @@ public override int GetHashCode() // IIterableBase Interface public unsafe partial struct PageIterable { + /// + public ref ecs_world_t* World => ref _iter.world; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ecs_iter_t GetIter(ecs_world_t* world = null) diff --git a/src/Flecs.NET/Core/Query.cs b/src/Flecs.NET/Core/Query.cs index e8f9b5ca..5cfe1d1b 100644 --- a/src/Flecs.NET/Core/Query.cs +++ b/src/Flecs.NET/Core/Query.cs @@ -312,6 +312,9 @@ public World RealWorld() // IIterableBase Interface public unsafe partial struct Query { + /// + ref ecs_world_t* IIterableBase.World => ref _handle->world; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ecs_iter_t GetIter(ecs_world_t* world = null) diff --git a/src/Flecs.NET/Core/WorkerIterable.cs b/src/Flecs.NET/Core/WorkerIterable.cs index 53d5c817..28eefa7b 100644 --- a/src/Flecs.NET/Core/WorkerIterable.cs +++ b/src/Flecs.NET/Core/WorkerIterable.cs @@ -82,6 +82,9 @@ public override int GetHashCode() //IIterableBase Interface public unsafe partial struct WorkerIterable { + /// + public ref ecs_world_t* World => ref _iter.world; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ecs_iter_t GetIter(ecs_world_t* world = null) diff --git a/src/Flecs.NET/Flecs.NET.csproj b/src/Flecs.NET/Flecs.NET.csproj index baa6877b..01c974a9 100644 --- a/src/Flecs.NET/Flecs.NET.csproj +++ b/src/Flecs.NET/Flecs.NET.csproj @@ -20,7 +20,7 @@ true true - 4.0.0 + 4.0.1 Flecs.NET.Debug Flecs.NET.Release BeanCheeseBurrito diff --git a/src/Flecs.NET/Utilities/Utils.cs b/src/Flecs.NET/Utilities/Utils.cs index 80981b8e..8388daa1 100644 --- a/src/Flecs.NET/Utilities/Utils.cs +++ b/src/Flecs.NET/Utilities/Utils.cs @@ -42,47 +42,42 @@ public static bool Bool(byte value) } /// - /// Gets the next power of 2 for the provided number. + /// Checks if specific bit is set. /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int NextPowOf2(int num) + public static bool IsBitSet(int value, int index) { - num--; - num |= num >> 1; - num |= num >> 2; - num |= num >> 4; - num |= num >> 8; - num |= num >> 16; - num++; - - return num; + return (value & (1 << index)) != 0; } /// - /// Tests if 2 readonly refs point to the same object. + /// Checks if specific bit is set. /// - /// - /// - /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool AreSameReadOnlyRefs(in T a, in T b) + public static bool IsBitSet(uint value, int index) { - return Unsafe.AreSame(ref Unsafe.AsRef(in a), ref Unsafe.AsRef(in b)); + return (value & (1 << index)) != 0; } /// - /// Tests if a readonly ref is null. + /// Gets the next power of 2 for the provided number. /// - /// - /// + /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsNullReadOnlyRef(in T obj) + public static int NextPowOf2(int num) { - return Unsafe.IsNullRef(ref Unsafe.AsRef(in obj)); + num--; + num |= num >> 1; + num |= num >> 2; + num |= num >> 4; + num |= num >> 8; + num |= num >> 16; + num++; + + return num; } /// @@ -106,4 +101,4 @@ public static void OsFree(void* data) { OsFree((IntPtr)data); } -} \ No newline at end of file +} diff --git a/submodules/flecs b/submodules/flecs index 1af6e06b..02c8c266 160000 --- a/submodules/flecs +++ b/submodules/flecs @@ -1 +1 @@ -Subproject commit 1af6e06b6b5a220c5ea061ae448bc77494d085e1 +Subproject commit 02c8c2666b22ccce5706c8f16efaf813704fe31e