Skip to content

Commit

Permalink
Merge pull request #43 from BeanCheeseBurrito/faster-each
Browse files Browse the repository at this point in the history
Update to flecs 4.0.1 and improve .Each() iteration
  • Loading branch information
BeanCheeseBurrito authored Oct 6, 2024
2 parents 8589d56 + 7328703 commit cf953c3
Show file tree
Hide file tree
Showing 246 changed files with 43,085 additions and 3,453 deletions.
2 changes: 1 addition & 1 deletion src/Flecs.NET.Bindings/Flecs.NET.Bindings.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<IsPackable>true</IsPackable>
<IncludeContentInPack>true</IncludeContentInPack>

<Version>4.0.0</Version>
<Version>4.0.1</Version>
<Title Condition="'$(Configuration)' == 'Debug'">Flecs.NET.Bindings.Debug</Title>
<Title Condition="'$(Configuration)' == 'Release'">Flecs.NET.Bindings.Release</Title>
<Authors>BeanCheeseBurrito</Authors>
Expand Down
170 changes: 113 additions & 57 deletions src/Flecs.NET.Bindings/Flecs.g.cs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/Flecs.NET.Codegen/Generators/IIterable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
""");
Expand Down
112 changes: 95 additions & 17 deletions src/Flecs.NET.Codegen/Generators/Invoker.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
Expand Down Expand Up @@ -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);
}
""");
Expand Down Expand Up @@ -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;

Expand All @@ -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;

Expand All @@ -147,6 +192,39 @@ public static unsafe partial class Invoker
""";
}

private static string GenerateEachInvokerIterators(Callback callback, int i)
{
IEnumerable<string> invokerIterators = Enum.GetValues(typeof(IterationTechnique)).Cast<IterationTechnique>().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<string> invokerIterators = Enum.GetValues(typeof(IterationTechnique)).Cast<IterationTechnique>().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<string> invokers = Generator.CallbacksIter.Select((Callback callback) => $$"""
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions src/Flecs.NET.Codegen/Generators/IterIterable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ public override int GetHashCode()
// IIterableBase Interface
public unsafe partial struct {{Generator.GetTypeName(Type.IterIterable, i)}} : IIterableBase
{
/// <inheritdoc cref="IterIterable.World"/>
public ref ecs_world_t* World => ref _iterIterable.World;
/// <inheritdoc cref="IterIterable.GetIter(ecs_world_t*)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ecs_iter_t GetIter(ecs_world_t* world = null)
Expand Down
1 change: 1 addition & 0 deletions src/Flecs.NET.Codegen/Generators/NodeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
""");
Expand Down
3 changes: 3 additions & 0 deletions src/Flecs.NET.Codegen/Generators/PageIterable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ public override int GetHashCode()
// IIterableBase Interface
public unsafe partial struct {{Generator.GetTypeName(Type.PageIterable, i)}} : IIterableBase
{
/// <inheritdoc cref="PageIterable.World"/>
public ref ecs_world_t* World => ref _pageIterable.World;
/// <inheritdoc cref="PageIterable.GetIter(ecs_world_t*)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ecs_iter_t GetIter(ecs_world_t* world = null)
Expand Down
3 changes: 3 additions & 0 deletions src/Flecs.NET.Codegen/Generators/Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ public World RealWorld()
// IIterableBase Interface
public unsafe partial struct {{Generator.GetTypeName(Type.Query, i)}} : IIterableBase
{
/// <inheritdoc cref="IIterableBase.World"/>
ref ecs_world_t* IIterableBase.World => ref Ecs.GetIterableWorld(ref _query);
/// <inheritdoc cref="Query.GetIter(ecs_world_t*)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ecs_iter_t GetIter(ecs_world_t* world = null)
Expand Down
36 changes: 26 additions & 10 deletions src/Flecs.NET.Codegen/Generators/TypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,35 @@ 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]}} ];
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")]
Expand All @@ -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)}");
}
}
""";
Expand Down
3 changes: 3 additions & 0 deletions src/Flecs.NET.Codegen/Generators/WorkerIterable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ public override int GetHashCode()
// IIterableBase Interface
public unsafe partial struct {{Generator.GetTypeName(Type.WorkerIterable, i)}} : IIterableBase
{
/// <inheritdoc cref="WorkerIterable.World"/>
public ref ecs_world_t* World => ref _workerIterable.World;
/// <inheritdoc cref="WorkerIterable.GetIter(ecs_world_t*)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ecs_iter_t GetIter(ecs_world_t* world = null)
Expand Down
15 changes: 15 additions & 0 deletions src/Flecs.NET.Codegen/Helpers/CallbackParameters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Flecs.NET.Codegen.Helpers;

public enum CallbackParameters
{
IterField,
IterSpan,
IterPointer,
EachRef,
EachEntityRef,
EachIterRef,
EachPointer,
EachEntityPointer,
EachIterPointer,
ReadRef
}
Loading

0 comments on commit cf953c3

Please sign in to comment.