Skip to content

Commit

Permalink
+ removed runtime allocations when Set/unset
Browse files Browse the repository at this point in the history
  • Loading branch information
andreakarasho committed Jul 12, 2024
1 parent a06228f commit 66926b3
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 84 deletions.
40 changes: 21 additions & 19 deletions src/Archetype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,17 @@ public sealed class Archetype

internal Archetype(
World world,
ImmutableArray<ComponentInfo> components,
ReadOnlySpan<ComponentInfo> components,
ComponentComparer comparer
)
{
_comparer = comparer;
_world = world;
_edgesLeft = new List<EcsEdge>();
_edgesRight = new List<EcsEdge>();
Components = components;
Pairs = components.Where(x => x.ID.IsPair).ToImmutableArray();
Id = Hashing.Calculate(components.AsSpan());
Components = [ .. components];
Pairs = Components.Where(x => x.ID.IsPair).ToImmutableArray();
Id = Hashing.Calculate(Components.AsSpan());
_chunks = new ArchetypeChunk[ARCHETYPE_INITIAL_CAPACITY];
_lookup = new Dictionary<ulong, int>(/*_comparer*/);

Expand All @@ -99,7 +99,7 @@ ComponentComparer comparer
_lookup.Add(components[i].ID, i);
}

_ids = components.Select(s => s.ID).ToArray();
_ids = Components.Select(s => s.ID).ToArray();
}

public World World => _world;
Expand Down Expand Up @@ -165,14 +165,16 @@ private EcsID RemoveByRow(int row)

ref var chunk = ref GetChunk(row);
ref var lastChunk = ref GetChunk(_count);
var removed = chunk.EntityAt(row);
var removed = chunk.EntityAt(row).ID;

if (row < _count)
{
EcsAssert.Assert(lastChunk.EntityAt(_count) != EntityView.Invalid, "Entity is invalid. This should never happen!");
EcsAssert.Assert(lastChunk.EntityAt(_count).ID.IsValid, "Entity is invalid. This should never happen!");

chunk.EntityAt(row) = lastChunk.EntityAt(_count);

var srcIdx = _count & CHUNK_THRESHOLD;
var dstIdx = row & CHUNK_THRESHOLD;
for (var i = 0; i < Components.Length; ++i)
{
if (Components[i].Size <= 0)
Expand All @@ -181,22 +183,22 @@ private EcsID RemoveByRow(int row)
var arrayToBeRemoved = chunk.RawComponentData(i);
var lastValidArray = lastChunk.RawComponentData(i);

Array.Copy(lastValidArray, _count & CHUNK_THRESHOLD, arrayToBeRemoved, row & CHUNK_THRESHOLD, 1);
Array.Copy(lastValidArray, srcIdx, arrayToBeRemoved, dstIdx, 1);

Check warning on line 186 in src/Archetype.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'sourceArray' in 'void Array.Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)'.

Check warning on line 186 in src/Archetype.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'destinationArray' in 'void Array.Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)'.
}

_world.GetRecord(chunk.EntityAt(row)).Row = row;
}

lastChunk.EntityAt(_count) = EntityView.Invalid;

for (var i = 0; i < Components.Length; ++i)
{
if (Components[i].Size <= 0)
continue;

var lastValidArray = lastChunk.RawComponentData(i);
Array.Clear(lastValidArray, _count & CHUNK_THRESHOLD, 1);
}
// lastChunk.EntityAt(_count) = EntityView.Invalid;
//
// for (var i = 0; i < Components.Length; ++i)
// {
// if (Components[i].Size <= 0)
// continue;
//
// var lastValidArray = lastChunk.RawComponentData(i);
// Array.Clear(lastValidArray, _count & CHUNK_THRESHOLD, 1);
// }

lastChunk.Count -= 1;
EcsAssert.Assert(lastChunk.Count >= 0, "Negative chunk count");
Expand All @@ -211,7 +213,7 @@ internal EcsID Remove(ref EcsRecord record)

internal Archetype InsertVertex(
Archetype left,
ImmutableArray<ComponentInfo> components,
ReadOnlySpan<ComponentInfo> components,
EcsID id
)
{
Expand Down
1 change: 0 additions & 1 deletion src/EntityView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ namespace TinyEcs;
#if NET5_0_OR_GREATER
[SkipLocalsInit]
#endif
[StructLayout(LayoutKind.Sequential)]
[DebuggerDisplay("ID: {ID}")]
public readonly struct EntityView : IEquatable<EcsID>, IEquatable<EntityView>
{
Expand Down
4 changes: 2 additions & 2 deletions src/Lookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ internal static class Lookup
{
private static ulong _index = 0;

private static readonly Dictionary<EcsID, Func<int, Array>> _arrayCreator = new ();
private static readonly Dictionary<ulong, Func<int, Array>> _arrayCreator = new ();
private static readonly Dictionary<Type, QueryTerm> _typesConvertion = new();
private static readonly Dictionary<Type, ComponentInfo> _componentInfosByType = new();
private static readonly Dictionary<EcsID, ComponentInfo> _components = new ();
private static readonly Dictionary<ulong, ComponentInfo> _components = new ();
private static readonly Dictionary<Type, EcsID> _unmatchedType = new();


Expand Down
17 changes: 10 additions & 7 deletions src/SparseSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public ref T CreateNew(out ulong id)
id = NewID(count);
}


ref var chunk = ref GetChunk((int)id >> 12);

if (Unsafe.IsNullRef(ref chunk) || chunk.Sparse == null)
Expand Down Expand Up @@ -214,11 +213,11 @@ public void Clear()

_maxID = uint.MinValue;

for (int i = 0; i < _chunks.Length; ++i)
{
ref var chunk = ref _chunks[i];
chunk = ref Unsafe.NullRef<Chunk>();
}
// for (int i = 0; i < _chunks.Length; ++i)
// {
// ref var chunk = ref _chunks[i];
// chunk = ref Unsafe.NullRef<Chunk>();
// }

_chunks = Array.Empty<EntitySparseSet<T>.Chunk>();
_dense.Clear();
Expand Down Expand Up @@ -350,7 +349,11 @@ public ref T AddRef()
if (Count >= Capacity)
EnsureCapacity(Capacity * 2);

return ref _data[Count++];
#if NET
return ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_data), Count++);
#else
return ref Unsafe.Add(ref MemoryMarshal.GetReference(_data.AsSpan()), Count++);
#endif
}

public void EnsureCapacity(int newCapacity)
Expand Down
33 changes: 15 additions & 18 deletions src/World.Deferred.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,33 @@ public sealed partial class World
{
private readonly ConcurrentQueue<DeferredOp> _operations = new();
private WorldState _worldState = new () { State = WorldStateTypes.Normal, Locks = 0 };
private readonly object _worldStateLock = new object();


public bool IsDeferred => _worldState.State == WorldStateTypes.Deferred;



public void BeginDeferred()
{
lock (_worldStateLock)
{
_worldState.State = WorldStateTypes.Deferred;
_worldState.Locks += 1;
}
if (_worldState.State == WorldStateTypes.Merging)
return;

_worldState.State = WorldStateTypes.Deferred;
Interlocked.Increment(ref _worldState.Locks);
}

public void EndDeferred()
{
lock (_worldStateLock)
{
_worldState.Locks -= 1;
if (_worldState.State == WorldStateTypes.Merging)
return;

EcsAssert.Assert(_worldState.Locks >= 0, "begin/end deferred calls mismatch");
Interlocked.Decrement(ref _worldState.Locks);
EcsAssert.Assert(_worldState.Locks >= 0, "begin/end deferred calls mismatch");

if (_worldState.Locks == 0)
{
_worldState.State = WorldStateTypes.Merging;
Merge();
_worldState.State = WorldStateTypes.Normal;
}
if (_worldState.Locks == 0)
{
_worldState.State = WorldStateTypes.Merging;
Merge();
_worldState.State = WorldStateTypes.Normal;
}
}

Expand Down Expand Up @@ -130,7 +127,7 @@ private void DeleteDeferred(EcsID entity)

private void Merge()
{
while (_operations.TryDequeue(out var op))
while (!_operations.IsEmpty && _operations.TryDequeue(out var op))
{
switch (op.Op)
{
Expand Down
10 changes: 1 addition & 9 deletions src/World.Public.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public World(ulong maxComponentId = 256)
_comparer = new ComponentComparer(this);
_archRoot = new Archetype(
this,
ImmutableArray<ComponentInfo>.Empty,
[],
_comparer
);

Expand Down Expand Up @@ -283,9 +283,7 @@ public void Add<T>(EcsID entity) where T : struct
return;
}

BeginDeferred();
_ = AttachComponent(entity, cmp.ID, cmp.Size);
EndDeferred();
}

/// <summary>
Expand All @@ -306,11 +304,9 @@ public void Set<T>(EcsID entity, T component) where T : struct
return;
}

BeginDeferred();
(var raw, var row) = AttachComponent(entity, cmp.ID, cmp.Size);
ref var array = ref Unsafe.As<Array, T[]>(ref raw!);
array[row & Archetype.CHUNK_THRESHOLD] = component;
EndDeferred();
}

/// <summary>
Expand All @@ -327,9 +323,7 @@ public void Add(EcsID entity, EcsID id)
return;
}

BeginDeferred();
_ = AttachComponent(entity, id, 0);
EndDeferred();
}

/// <summary>
Expand All @@ -354,9 +348,7 @@ public void Unset(EcsID entity, EcsID id)
return;
}

BeginDeferred();
DetachComponent(entity, id);
EndDeferred();
}

/// <summary>
Expand Down
8 changes: 0 additions & 8 deletions src/World.Relationship.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ private void CheckSymmetric(EcsID entity, EcsID action, EcsID target)
return;
}

BeginDeferred();
_ = AttachComponent(target, pairId, 0);
EndDeferred();
}
}

Expand Down Expand Up @@ -127,9 +125,7 @@ public void Add<TAction>(EcsID entity, EcsID target)
return;
}

BeginDeferred();
_ = AttachComponent(entity, pairId, act.Size);
EndDeferred();
}

/// <summary>
Expand Down Expand Up @@ -158,11 +154,9 @@ public void Set<TAction>(EcsID entity, TAction action, EcsID target)
return;
}

BeginDeferred();
(var array, var row) = AttachComponent(entity, pairId, act.Size);
ref var cmpArr = ref Unsafe.As<Array, TAction[]>(ref array!);
cmpArr[row & Archetype.CHUNK_THRESHOLD] = action;
EndDeferred();
}

/// <summary>
Expand All @@ -186,9 +180,7 @@ public void Add(EcsID entity, EcsID action, EcsID target)
return;
}

BeginDeferred();
_ = AttachComponent(entity, pairId, 0);
EndDeferred();
}

/// <summary>
Expand Down
Loading

0 comments on commit 66926b3

Please sign in to comment.