Skip to content

Commit

Permalink
Breaking changes, introduced Signature. Renamed Group to `Compone…
Browse files Browse the repository at this point in the history
…nt`, moved methods around and several other small changes for improved performance.
  • Loading branch information
genaray committed Jul 22, 2024
1 parent 02bf456 commit c590e64
Show file tree
Hide file tree
Showing 16 changed files with 376 additions and 216 deletions.
52 changes: 52 additions & 0 deletions src/Arch.SourceGen/Fundamentals/Component.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
namespace Arch.SourceGen;

public static class ComponentExtensions
{
public static StringBuilder AppendComponents(this StringBuilder sb, int amount)
{
for (var index = 1; index < amount; index++)
{
sb.AppendComponent(index);
}

return sb;
}

public static StringBuilder AppendComponent(this StringBuilder sb, int amount)
{
var generics = new StringBuilder().GenericWithoutBrackets(amount);
var types = new StringBuilder();
for (var index = 0; index <= amount; index++)
{
types.Append($"Component<T{index}>.ComponentType,");
}

var template =
$$"""
/// <inheritdoc cref="Component"/>
public static class Component<{{generics}}>
{
internal static readonly int Id;
/// <summary>
/// An <see cref="Signature"/> for this given set of components.
/// </summary>
public static readonly Signature Signature;
/// <summary>
/// The hash code for this given set of components.
/// </summary>
public static readonly int Hash;
static Component()
{
Id = Interlocked.Increment(ref Component.Id);
Signature = new Signature(new [] { {{types}} });
Hash = Signature.GetHashCode();
}
}
""";

return sb.AppendLine(template);
}
}
4 changes: 2 additions & 2 deletions src/Arch.SourceGen/Fundamentals/Create.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static StringBuilder AppendCreate(this StringBuilder sb, int amount)
[StructuralChange]
public Entity Create<{{generics}}>({{parameters}})
{
var types = Group<{{generics}}>.Types;
var signature = Component<{{generics}}>.Signature;
// Recycle id or increase
var recycle = RecycledIds.TryDequeue(out var recycledId);
Expand All @@ -40,7 +40,7 @@ public static StringBuilder AppendCreate(this StringBuilder sb, int amount)
var entity = new Entity(recycled.Id, Id);
// Add to archetype & mapping
var archetype = GetOrCreate(types);
var archetype = GetOrCreate(signature);
var createdChunk = archetype.Add(entity, out var slot);
archetype.Set<{{generics}}>(ref slot, {{inParameters}});
Expand Down
52 changes: 0 additions & 52 deletions src/Arch.SourceGen/Fundamentals/Group.cs

This file was deleted.

8 changes: 4 additions & 4 deletions src/Arch.SourceGen/Queries/QueryDescription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static StringBuilder AppendQueryDescriptionWithAll(this StringBuilder sb,
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref QueryDescription WithAll<{{generics}}>()
{
All = Group<{{generics}}>.Types;
All = Component<{{generics}}>.Signature;
_hashCode = -1;
return ref this;
}
Expand Down Expand Up @@ -52,7 +52,7 @@ public static StringBuilder AppendQueryDescriptionWithAny(this StringBuilder sb,
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref QueryDescription WithAny<{{generics}}>()
{
Any = Group<{{generics}}>.Types;
Any = Component<{{generics}}>.Signature;
_hashCode = -1;
return ref this;
}
Expand Down Expand Up @@ -82,7 +82,7 @@ public static StringBuilder AppendQueryDescriptionWithNone(this StringBuilder sb
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref QueryDescription WithNone<{{generics}}>()
{
None = Group<{{generics}}>.Types;
None = Component<{{generics}}>.Signature;
_hashCode = -1;
return ref this;
}
Expand Down Expand Up @@ -112,7 +112,7 @@ public static StringBuilder AppendQueryDescriptionWithExclusive(this StringBuild
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref QueryDescription WithExclusive<{{generics}}>()
{
Exclusive = Group<{{generics}}>.Types;
Exclusive = Component<{{generics}}>.Signature;
_hashCode = -1;
return ref this;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Arch.SourceGen/QueryGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
compileTimeStatics.AppendLine("using System;");
compileTimeStatics.AppendLine("using System.Threading;");
compileTimeStatics.AppendLine("namespace Arch.Core.Utils;");
compileTimeStatics.AppendGroups(25);
compileTimeStatics.AppendComponents(25);

var delegates = new StringBuilder();
delegates.AppendLine("using System;");
Expand All @@ -41,7 +41,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
references.AppendLine("using CommunityToolkit.HighPerformance;");
references.AppendLine("using Arch.Core.Utils;");
references.AppendLine("namespace Arch.Core;");
references.AppendComponents(25);
ReferencesExtensions.AppendComponents(references, 25);
references.AppendEntityComponents(25);

var jobs = new StringBuilder();
Expand Down
6 changes: 3 additions & 3 deletions src/Arch.Tests/ArchetypeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ internal unsafe struct HeavyComponent
[TestFixture]
public sealed class ArchetypeTest
{
private static readonly ComponentType[] _group = { typeof(Transform), typeof(Rotation) };
private static readonly ComponentType[] _otherGroup = { typeof(Transform), typeof(Rotation), typeof(Ai) };
private static readonly ComponentType[] _heavyGroup = { typeof(Transform), typeof(Rotation), typeof(HeavyComponent) };
private static readonly Signature _group = new(typeof(Transform), typeof(Rotation));
private static readonly Signature _otherGroup = new(typeof(Transform), typeof(Rotation), typeof(Ai));
private static readonly Signature _heavyGroup = new(typeof(Transform), typeof(Rotation), typeof(HeavyComponent));

/// <summary>
/// Tests if <see cref="Archetype"/>s and their <see cref="Chunk"/> are created correctly.
Expand Down
1 change: 1 addition & 0 deletions src/Arch.Tests/EnumeratorTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Runtime.InteropServices;
using Arch.Core;
using Arch.Core.Extensions;
using Arch.Core.Utils;
using static NUnit.Framework.Assert;

Expand Down
32 changes: 16 additions & 16 deletions src/Arch/Core/Archetype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public sealed partial class Archetype
/// <summary>
/// The minimum size of a regular L1 cache.
/// </summary>
internal const int BaseSize = 16000; // 16KB Chunk size
internal const int BaseSize = 16_384; // 16KB Chunk size

/// <summary>
/// A lookup array that maps the component id to an index within the component array of a <see cref="Chunk"/> to quickly find the correct array for the component type.
Expand All @@ -134,22 +134,22 @@ public sealed partial class Archetype
/// <summary>
/// Initializes a new instance of the <see cref="Archetype"/> class by a group of components.
/// </summary>
/// <param name="types">The component structure of the <see cref="Arch.Core.Entity"/>'s that can be stored in this <see cref="Archetype"/>.</param>
internal Archetype(ComponentType[] types)
/// <param name="signature">The component structure of the <see cref="Arch.Core.Entity"/>'s that can be stored in this <see cref="Archetype"/>.</param>
internal Archetype(Signature signature)
{
Types = types;
Types = signature;

// Calculations
ChunkSizeInBytes = MinimumRequiredChunkSize(types);
EntitiesPerChunk = CalculateEntitiesPerChunk(types);
ChunkSizeInBytes = MinimumRequiredChunkSize(signature);
EntitiesPerChunk = CalculateEntitiesPerChunk(signature);

// The bitmask/set
BitSet = types.ToBitSet();
_componentIdToArrayIndex = types.ToLookupArray();
BitSet = signature;
_componentIdToArrayIndex = signature.Components.ToLookupArray();

// Setup arrays and mappings
Chunks = ArrayPool<Chunk>.Shared.Rent(1);
Chunks[0] = new Chunk(EntitiesPerChunk, _componentIdToArrayIndex, types);
Chunks[0] = new Chunk(EntitiesPerChunk, _componentIdToArrayIndex, signature);

ChunkCount = 1;
ChunkCapacity = 1;
Expand All @@ -163,6 +163,11 @@ internal Archetype(ComponentType[] types)
/// </summary>
public ComponentType[] Types { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; }

/// <summary>
/// A bitset representation of the <see cref="Types"/> array for fast lookups and queries.
/// </summary>
public BitSet BitSet { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; }

/// <summary>
/// The lookup array used by this <see cref="Archetype"/>, is being passed to all its <see cref="Chunks"/> to save memory.
/// </summary>
Expand All @@ -172,11 +177,6 @@ internal int[] LookupArray
get => _componentIdToArrayIndex;
}

/// <summary>
/// A bitset representation of the <see cref="Types"/> array for fast lookups and queries.
/// </summary>
public BitSet BitSet { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; }

/// <summary>
/// The number of entities that are stored per <see cref="Chunk"/>.
/// </summary>
Expand Down Expand Up @@ -523,7 +523,7 @@ public sealed unsafe partial class Archetype
/// </summary>
/// <param name="types">The component structure of the <see cref="Arch.Core.Entity"/>'s.</param>
/// <returns>The amount of <see cref="Chunk"/>'s required.</returns>
public int MinimumRequiredChunkSize(ComponentType[] types)
public int MinimumRequiredChunkSize(Span<ComponentType> types)
{
var minimumEntities = (sizeof(Entity) + types.ToByteSize()) * MinimumAmountOfEntitiesPerChunk;
return (int)Math.Ceiling((float)minimumEntities / BaseSize) * BaseSize;
Expand All @@ -534,7 +534,7 @@ public int MinimumRequiredChunkSize(ComponentType[] types)
/// </summary>
/// <param name="types">The component structure of the <see cref="Arch.Core.Entity"/>'s.</param>
/// <returns>The amount of <see cref="Arch.Core.Entity"/>'s.</returns>
public int CalculateEntitiesPerChunk(ComponentType[] types)
public int CalculateEntitiesPerChunk(Span<ComponentType> types)
{
return ChunkSizeInBytes / (sizeof(Entity) + types.ToByteSize());
}
Expand Down
5 changes: 3 additions & 2 deletions src/Arch/Core/Chunk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ namespace Arch.Core;
[SkipLocalsInit] // Really a speed improvements? The benchmark only showed a slight improvement
public partial struct Chunk
{

/// <summary>
/// Initializes a new instance of the <see cref="Chunk"/> struct.
/// Automatically creates a lookup array for quick access to internal components.
/// </summary>
/// <param name="capacity">How many entities of the respective component structure fit into this <see cref="Chunk"/>.</param>
/// <param name="types">The respective component structure of all entities in this <see cref="Chunk"/>.</param>
internal Chunk(int capacity, params ComponentType[] types)
internal Chunk(int capacity, Span<ComponentType> types)
: this(capacity, types.ToLookupArray(), types) { }

/// <summary>
Expand All @@ -30,7 +31,7 @@ internal Chunk(int capacity, params ComponentType[] types)
/// <param name="capacity">How many entities of the respective component structure fit into this <see cref="Chunk"/>.</param>
/// <param name="componentIdToArrayIndex">A lookup array which maps the component id to the array index of the component array.</param>
/// <param name="types">The respective component structure of all entities in this <see cref="Chunk"/>.</param>
internal Chunk(int capacity, int[] componentIdToArrayIndex, params ComponentType[] types)
internal Chunk(int capacity, int[] componentIdToArrayIndex, Span<ComponentType> types)
{
// Calculate capacity and init arrays.
Size = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/Arch/Core/EntityInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ internal class EntityInfoStorage
/// </summary>
internal EntityInfoStorage()
{
var cpuL1CacheSize = 16_000;
var cpuL1CacheSize = 16_384;

Versions = new JaggedArray<int>(
cpuL1CacheSize / Unsafe.SizeOf<int>(),
Expand Down
21 changes: 1 addition & 20 deletions src/Arch/Core/Extensions/Internal/BitSetExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,14 @@ namespace Arch.Core.Extensions.Internal;
/// </summary>
internal static class BitSetExtensions
{
// NOTE: Should this be in `TypeExtensions`?
/// <summary>
/// Converts an array of <see cref="ComponentType"/>'s to its <see cref="BitSet"/>.
/// </summary>
/// <param name="types">The array of <see cref="ComponentType"/>'s.</param>
/// <returns>Their newly created <see cref="BitSet"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static BitSet ToBitSet(this ComponentType[] types)
{
if (types.Length == 0)
{
return new BitSet();
}

var bitSet = new BitSet();
bitSet.SetBits(types);

return bitSet;
}

/// <summary>
/// Sets bits in a <see cref="BitSet"/> from the <see cref="ComponentType"/> ids.
/// </summary>
/// <param name="bitSet">The <see cref="BitSet"/>.</param>
/// <param name="types">The <see cref="ComponentType"/>'s array.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void SetBits(this BitSet bitSet, ComponentType[] types)
internal static void SetBits(this BitSet bitSet, Span<ComponentType> types)
{
foreach (var type in types)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Arch/Core/Extensions/Internal/ComponentTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal static class ComponentTypeExtensions
/// <param name="types">The <see cref="ComponentType"/> array.</param>
/// <returns>Their combined byte size.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int ToByteSize(this ComponentType[] types)
internal static int ToByteSize(this Span<ComponentType> types)
{
var size = 0;
foreach (var type in types)
Expand All @@ -35,7 +35,7 @@ internal static int ToByteSize(this ComponentType[] types)
/// <param name="types">The <see cref="ComponentType"/> array.</param>
/// <returns>The lookup array.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int[] ToLookupArray(this ComponentType[] types)
internal static int[] ToLookupArray(this Span<ComponentType> types)
{
// Get maximum component ID.
var max = 0;
Expand Down
Loading

0 comments on commit c590e64

Please sign in to comment.