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]