Skip to content

Commit cf953c3

Browse files
Merge pull request #43 from BeanCheeseBurrito/faster-each
Update to flecs 4.0.1 and improve .Each() iteration
2 parents 8589d56 + 7328703 commit cf953c3

File tree

246 files changed

+43085
-3453
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

246 files changed

+43085
-3453
lines changed

src/Flecs.NET.Bindings/Flecs.NET.Bindings.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<IsPackable>true</IsPackable>
1111
<IncludeContentInPack>true</IncludeContentInPack>
1212

13-
<Version>4.0.0</Version>
13+
<Version>4.0.1</Version>
1414
<Title Condition="'$(Configuration)' == 'Debug'">Flecs.NET.Bindings.Debug</Title>
1515
<Title Condition="'$(Configuration)' == 'Release'">Flecs.NET.Bindings.Release</Title>
1616
<Authors>BeanCheeseBurrito</Authors>

src/Flecs.NET.Bindings/Flecs.g.cs

Lines changed: 113 additions & 57 deletions
Large diffs are not rendered by default.

src/Flecs.NET.Codegen/Generators/IIterable.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public static string GenerateExtensions(Type type, int i)
103103
public {{Generator.GetInvokerReturnType(callback)}} {{Generator.GetInvokerName(callback)}}({{Generator.GetCallbackType(callback, i)}} callback)
104104
{
105105
{{Generator.GetTypeName(Type.TypeHelper, i)}}.AssertReferenceTypes({{(Generator.GetCallbackIsUnmanaged(callback) ? "false" : "true")}});
106+
{{Generator.GetTypeName(Type.TypeHelper, i)}}.AssertSparseTypes(Ecs.GetIterableWorld(ref this), {{(Generator.GetCallbackIsIter(callback) ? "false" : "true")}});
106107
{{Generator.GetInvokerReturn(callback)}}Invoker.{{Generator.GetInvokerName(callback)}}(ref this, callback);
107108
}
108109
""");

src/Flecs.NET.Codegen/Generators/Invoker.cs

Lines changed: 95 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Diagnostics.CodeAnalysis;
34
using System.Linq;
@@ -43,7 +44,7 @@ private static string GenerateIterIteratorInvokers(int i)
4344
public static void Iter<{{Generator.TypeParameters[i]}}>(Iter it, {{Generator.GetCallbackType(callback, i)}} callback)
4445
{
4546
Ecs.TableLock(it);
46-
callback(it, {{Generator.GetCallbackArguments(i, callback)}});
47+
callback(it, {{Generator.GetCallbackArguments(callback, i)}});
4748
Ecs.TableUnlock(it);
4849
}
4950
""");
@@ -74,19 +75,45 @@ private static string GenerateEachIteratorInvokers(int i)
7475
{
7576
{{Generator.GetCallbackCountVariable(callback)}}
7677
77-
{{Generator.IterPointerVariables[i]}}
78-
{{Generator.IterStepVariables[i]}}
78+
{{Generator.FieldDataVariables[i]}}
79+
IterationTechnique flags = it.GetIterationTechnique({{i + 1}});
7980
8081
Ecs.TableLock(it);
81-
82-
for (int i = 0; i < count; i++, {{Generator.IterPointerIncrements[i]}})
83-
callback({{Generator.GetCallbackSteppedArguments(i, callback)}});
82+
83+
if ({{Generator.ContainsReferenceTypes[i]}})
84+
{
85+
if (flags == IterationTechnique.None)
86+
{{IterationTechnique.Managed}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
87+
else if (flags == IterationTechnique.Shared)
88+
{{IterationTechnique.SharedManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
89+
else if (flags == IterationTechnique.Sparse)
90+
{{IterationTechnique.SparseManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
91+
else if (flags == (IterationTechnique.Sparse | IterationTechnique.Shared))
92+
{{IterationTechnique.SparseSharedManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
93+
}
94+
else
95+
{
96+
if (flags == IterationTechnique.None)
97+
{{IterationTechnique.Unmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
98+
else if (flags == IterationTechnique.Shared)
99+
{{IterationTechnique.SharedUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
100+
else if (flags == IterationTechnique.Sparse)
101+
{{IterationTechnique.SparseUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
102+
else if (flags == (IterationTechnique.Sparse | IterationTechnique.Shared))
103+
{{IterationTechnique.SparseSharedUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
104+
}
84105
85106
Ecs.TableUnlock(it);
107+
108+
return;
109+
110+
{{GenerateEachInvokerIterators(callback, i)}}
86111
}
87112
""");
88113

89114
return $$"""
115+
using System;
116+
using System.Runtime.CompilerServices;
90117
using Flecs.NET.Utilities;
91118
using static Flecs.NET.Bindings.flecs;
92119
@@ -112,29 +139,47 @@ private static string GenerateFindIteratorInvokers(int i)
112139
{
113140
{{Generator.GetCallbackCountVariable(callback)}}
114141
115-
{{Generator.IterPointerVariables[i]}}
116-
{{Generator.IterStepVariables[i]}}
142+
{{Generator.FieldDataVariables[i]}}
143+
IterationTechnique flags = it.GetIterationTechnique({{i + 1}});
117144
118145
Ecs.TableLock(it);
119146
120147
Entity result = default;
121-
122-
for (int i = 0; i < count; i++, {{Generator.IterPointerIncrements[i]}})
148+
149+
if ({{Generator.ContainsReferenceTypes[i]}})
123150
{
124-
if (!callback({{Generator.GetCallbackSteppedArguments(i, callback)}}))
125-
continue;
126-
127-
result = new Entity(it.Handle->world, it.Handle->entities[i]);
128-
break;
151+
if (flags == IterationTechnique.None)
152+
result = {{IterationTechnique.Managed}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
153+
else if (flags == IterationTechnique.Shared)
154+
result = {{IterationTechnique.SharedManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
155+
else if (flags == IterationTechnique.Sparse)
156+
result = {{IterationTechnique.SparseManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
157+
else if (flags == (IterationTechnique.Sparse | IterationTechnique.Shared))
158+
result = {{IterationTechnique.SparseSharedManaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
159+
}
160+
else
161+
{
162+
if (flags == IterationTechnique.None)
163+
result = {{IterationTechnique.Unmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
164+
else if (flags == IterationTechnique.Shared)
165+
result = {{IterationTechnique.SharedUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
166+
else if (flags == IterationTechnique.Sparse)
167+
result = {{IterationTechnique.SparseUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
168+
else if (flags == (IterationTechnique.Sparse | IterationTechnique.Shared))
169+
result = {{IterationTechnique.SparseSharedUnmanaged}}(it, count, callback, {{Generator.FieldDataRefs[i]}});
129170
}
130171
131172
Ecs.TableUnlock(it);
132173
133174
return result;
175+
176+
{{GenerateFindInvokerIterators(callback, i)}}
134177
}
135178
""");
136179

137180
return $$"""
181+
using System;
182+
using System.Runtime.CompilerServices;
138183
using Flecs.NET.Utilities;
139184
using static Flecs.NET.Bindings.flecs;
140185
@@ -147,6 +192,39 @@ public static unsafe partial class Invoker
147192
""";
148193
}
149194

195+
private static string GenerateEachInvokerIterators(Callback callback, int i)
196+
{
197+
IEnumerable<string> invokerIterators = Enum.GetValues(typeof(IterationTechnique)).Cast<IterationTechnique>().Select((IterationTechnique iterationTechnique) => $$"""
198+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
199+
static void {{iterationTechnique}}(Iter it, int count, {{Generator.GetCallbackType(callback, i)}} callback, {{Generator.FieldDataParameters[i]}})
200+
{
201+
for (int i = 0; i < count; i++)
202+
callback({{Generator.GetCallbackArguments(callback, iterationTechnique, i)}});
203+
}
204+
""");
205+
206+
return string.Join(Separator.DoubleNewLine, invokerIterators);
207+
}
208+
209+
private static string GenerateFindInvokerIterators(Callback callback, int i)
210+
{
211+
IEnumerable<string> invokerIterators = Enum.GetValues(typeof(IterationTechnique)).Cast<IterationTechnique>().Select((IterationTechnique iterationTechnique) => $$"""
212+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
213+
static Entity {{iterationTechnique}}(Iter it, int count, {{Generator.GetCallbackType(callback, i)}} callback, {{Generator.FieldDataParameters[i]}})
214+
{
215+
for (int i = 0; i < count; i++)
216+
{
217+
if (callback({{Generator.GetCallbackArguments(callback, iterationTechnique, i)}}))
218+
return new Entity(it.Handle->world, it.Handle->entities[i]);
219+
}
220+
221+
return default;
222+
}
223+
""");
224+
225+
return string.Join(Separator.DoubleNewLine, invokerIterators);
226+
}
227+
150228
private static string GenerateIterIterableInvokers(int i)
151229
{
152230
IEnumerable<string> invokers = Generator.CallbacksIter.Select((Callback callback) => $$"""
@@ -279,7 +357,7 @@ public static string GenerateFetchComponentInvokers(int i)
279357
bool hasComponents = Ecs.GetPointers<{{Generator.TypeParameters[i]}}>(world, entity, record, table, pointers);
280358
281359
if (hasComponents)
282-
callback({{Generator.GetCallbackArguments(i, callback)}});
360+
callback({{Generator.GetCallbackArguments(callback, i)}});
283361
284362
ecs_{{Generator.GetInvokerName(callback).ToLower()}}_end(record);
285363
@@ -347,7 +425,7 @@ public static string GenerateFetchComponentInvokers(int i)
347425
Ecs.EnsurePointers<{{Generator.TypeParameters[i]}}>(world, entity, pointers);
348426
}
349427
350-
callback({{Generator.GetCallbackArguments(i, callback)}});
428+
callback({{Generator.GetCallbackArguments(callback, i)}});
351429
352430
if (!world.IsDeferred())
353431
Ecs.TableUnlock(world, table);

src/Flecs.NET.Codegen/Generators/IterIterable.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ public override int GetHashCode()
172172
// IIterableBase Interface
173173
public unsafe partial struct {{Generator.GetTypeName(Type.IterIterable, i)}} : IIterableBase
174174
{
175+
/// <inheritdoc cref="IterIterable.World"/>
176+
public ref ecs_world_t* World => ref _iterIterable.World;
177+
175178
/// <inheritdoc cref="IterIterable.GetIter(ecs_world_t*)"/>
176179
[MethodImpl(MethodImplOptions.AggressiveInlining)]
177180
public ecs_iter_t GetIter(ecs_world_t* world = null)

src/Flecs.NET.Codegen/Generators/NodeBuilder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public static string GenerateExtensions(Type builderType, Type returnType, int i
1717
public {{Generator.GetTypeName(returnType, i)}} {{Generator.GetInvokerName(callback)}}({{Generator.GetCallbackType(callback, i)}} callback)
1818
{
1919
{{Generator.GetTypeName(Type.TypeHelper, i)}}.AssertReferenceTypes({{(Generator.GetCallbackIsUnmanaged(callback) ? "false" : "true")}});
20+
{{Generator.GetTypeName(Type.TypeHelper, i)}}.AssertSparseTypes(World, {{(Generator.GetCallbackIsIter(callback) ? "false" : "true")}});
2021
return {{(Generator.GetCallbackIsRun(callback) ? "SetRun" : "SetCallback")}}({{(Generator.GetCallbackIsDelegate(callback) ? string.Empty : "(IntPtr)")}}callback, Pointers<{{Generator.TypeParameters[i]}}>.{{callback}}).Build();
2122
}
2223
""");

src/Flecs.NET.Codegen/Generators/PageIterable.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ public override int GetHashCode()
8585
// IIterableBase Interface
8686
public unsafe partial struct {{Generator.GetTypeName(Type.PageIterable, i)}} : IIterableBase
8787
{
88+
/// <inheritdoc cref="PageIterable.World"/>
89+
public ref ecs_world_t* World => ref _pageIterable.World;
90+
8891
/// <inheritdoc cref="PageIterable.GetIter(ecs_world_t*)"/>
8992
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9093
public ecs_iter_t GetIter(ecs_world_t* world = null)

src/Flecs.NET.Codegen/Generators/Query.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ public World RealWorld()
221221
// IIterableBase Interface
222222
public unsafe partial struct {{Generator.GetTypeName(Type.Query, i)}} : IIterableBase
223223
{
224+
/// <inheritdoc cref="IIterableBase.World"/>
225+
ref ecs_world_t* IIterableBase.World => ref Ecs.GetIterableWorld(ref _query);
226+
224227
/// <inheritdoc cref="Query.GetIter(ecs_world_t*)"/>
225228
[MethodImpl(MethodImplOptions.AggressiveInlining)]
226229
public ecs_iter_t GetIter(ecs_world_t* world = null)

src/Flecs.NET.Codegen/Generators/TypeHelper.cs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,29 +27,35 @@ public static string GenerateTypeHelper(int i)
2727
using System.Diagnostics.CodeAnalysis;
2828
using System.Linq;
2929
using System.Runtime.CompilerServices;
30+
using Flecs.NET.Utilities;
31+
32+
using static Flecs.NET.Bindings.flecs;
3033
3134
namespace Flecs.NET.Core;
3235
3336
[SuppressMessage("ReSharper", "StaticMemberInGenericType")]
34-
internal static partial class {{Generator.GetTypeName(Type.TypeHelper, i)}}
37+
internal static unsafe partial class {{Generator.GetTypeName(Type.TypeHelper, i)}}
3538
{
3639
private static string[]? _typeNames;
3740
public static string[] TypeNames => _typeNames ??= [ {{Generator.TypeFullNames[i]}} ];
3841
3942
public static readonly int Tags = {{Generator.Tags[i]}};
4043
public static readonly int ReferenceTypes = {{Generator.ReferenceTypes[i]}};
4144
45+
private static string GetTypeListString(int fields)
46+
{
47+
return string.Join(", ", Enumerable.Range(0, {{i + 1}})
48+
.Where(i => (fields & (1 << i)) != 0)
49+
.Select(i => TypeNames[i]));
50+
}
51+
4252
[Conditional("DEBUG")]
4353
public static void AssertNoTags()
4454
{
4555
if (Tags == 0)
4656
return;
4757
48-
string tags = string.Join(", ", Enumerable.Range(0, {{i + 1}})
49-
.Where(i => (Tags & (1 << i)) != 0)
50-
.Select(i => TypeNames[i]));
51-
52-
Ecs.Error($"Cannot use zero-sized structs as generic type arguments for this struct. Remove the following type arguments: {tags}");
58+
Ecs.Error($"Cannot use zero-sized structs as generic type arguments for this struct. Remove the following type arguments: {GetTypeListString(Tags)}");
5359
}
5460
5561
[Conditional("DEBUG")]
@@ -58,11 +64,21 @@ public static void AssertReferenceTypes(bool allowReferenceTypes)
5864
if (allowReferenceTypes || ReferenceTypes == 0)
5965
return;
6066
61-
string referenceTypes = string.Join(", ", Enumerable.Range(0, {{i + 1}})
62-
.Where(i => (ReferenceTypes & (1 << i)) != 0)
63-
.Select(i => TypeNames[i]));
67+
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)}");
68+
}
6469
65-
Ecs.Error($"Cannot use managed types as generic type arguments for callback signatures that retrieve pointers or spans. Remove the following type arguments: {referenceTypes}");
70+
[Conditional("DEBUG")]
71+
public static void AssertSparseTypes(ecs_world_t* world, bool allowSparseTypes)
72+
{
73+
if (allowSparseTypes)
74+
return;
75+
76+
int sparseTypes = {{Generator.SparseBitField[i]}};
77+
78+
if (sparseTypes == 0)
79+
return;
80+
81+
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)}");
6682
}
6783
}
6884
""";

src/Flecs.NET.Codegen/Generators/WorkerIterable.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ public override int GetHashCode()
8585
// IIterableBase Interface
8686
public unsafe partial struct {{Generator.GetTypeName(Type.WorkerIterable, i)}} : IIterableBase
8787
{
88+
/// <inheritdoc cref="WorkerIterable.World"/>
89+
public ref ecs_world_t* World => ref _workerIterable.World;
90+
8891
/// <inheritdoc cref="WorkerIterable.GetIter(ecs_world_t*)"/>
8992
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9093
public ecs_iter_t GetIter(ecs_world_t* world = null)

0 commit comments

Comments
 (0)