Skip to content

Commit a797832

Browse files
release v2.0.1
- [opt] improve iterator performance - [opt] improve ref performance - [opt] improve create entity / add component performance
1 parent 6cf9229 commit a797832

11 files changed

+454
-558
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ riderModule.iml
55
/_ReSharper.Caches/
66
/.idea
77
**/.DS_Store
8+
EasyEcs.sln.DotSettings.user

EasyEcs.Core/Components/ComponentRef.cs

+9-13
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
using System;
2-
31
namespace EasyEcs.Core.Components;
42

53
public readonly struct ComponentRef<T> where T : struct, IComponent
64
{
75
private readonly int _index;
8-
private readonly Type _type;
6+
private readonly byte _bitIndex;
97
private readonly Context _context;
108

11-
public ComponentRef(int index, Context context)
9+
public ComponentRef(int index, byte bitIndex, Context context)
1210
{
1311
_index = index;
14-
_type = typeof(T);
12+
_bitIndex = bitIndex;
1513
_context = context;
1614
}
1715

18-
public ref T Value => ref ((T[])_context.Components[_context.TagRegistry.GetTagBitIndex(_type)])[_index];
16+
public ref T Value => ref ((T[])_context.Components[_bitIndex])[_index];
1917

2018
public static implicit operator T(ComponentRef<T> componentRef)
2119
{
@@ -25,19 +23,17 @@ public static implicit operator T(ComponentRef<T> componentRef)
2523

2624
public readonly struct SingletonComponentRef<T> where T : struct, ISingletonComponent
2725
{
28-
private readonly int _index;
29-
private readonly Type _type;
26+
private readonly byte _bitIndex;
3027
private readonly Context _context;
3128

32-
public SingletonComponentRef(int index, Context context)
29+
public ref T Value => ref ((T[])_context.Components[_bitIndex])[0];
30+
31+
public SingletonComponentRef(byte bitIndex, Context context)
3332
{
34-
_index = index;
35-
_type = typeof(T);
33+
_bitIndex = bitIndex;
3634
_context = context;
3735
}
3836

39-
public ref T Value => ref ((T[])_context.Components[_context.TagRegistry.GetTagBitIndex(_type)])[_index];
40-
4137
public static implicit operator T(SingletonComponentRef<T> componentRef)
4238
{
4339
return componentRef.Value;

EasyEcs.Core/Context.GroupOf.cs

-6
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@ public partial class Context
1313
/// <returns></returns>
1414
public GroupResultEnumerator GroupOf(params Type[] components)
1515
{
16-
var tag = new Tag();
17-
foreach (var component in components)
18-
{
19-
tag.SetBit(TagRegistry.GetTagBitIndex(component));
20-
}
21-
2216
return new GroupResultEnumerator(components, this);
2317
}
2418

EasyEcs.Core/Context.cs

+40-18
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,13 @@ public void AddComponent<T>(Entity entity, Action<ComponentRef<T>> callback = nu
190190
_commandBuffer.AddCommand(new AddComponentCommand(entity.Id, typeof(T),
191191
() =>
192192
{
193-
var arr = (T[])Components[TagRegistry.GetTagBitIndex(typeof(T))];
193+
var idx = TagRegistry.GetTagBitIndex(typeof(T));
194+
var arr = (T[])Components[idx];
194195
ref var compRef = ref arr[entity.Id];
195196
compRef = new T();
196197
try
197198
{
198-
callback?.Invoke(new ComponentRef<T>(entity.Id, this));
199+
callback?.Invoke(new ComponentRef<T>(entity.Id, idx, this));
199200
}
200201
catch (Exception e)
201202
{
@@ -225,12 +226,13 @@ public void AddSingletonComponent<T>(Action<T> callback = null) where T : struct
225226
_commandBuffer.AddCommand(new AddComponentCommand(0, typeof(T),
226227
() =>
227228
{
228-
var arr = (T[])Components[TagRegistry.GetTagBitIndex(typeof(T))];
229+
var idx = TagRegistry.GetTagBitIndex(typeof(T));
230+
var arr = (T[])Components[idx];
229231
var component = new T();
230232
arr[0] = component;
231233
try
232234
{
233-
callback?.Invoke(new SingletonComponentRef<T>(0, this).Value);
235+
callback?.Invoke(new SingletonComponentRef<T>(idx, this));
234236
}
235237
catch (Exception e)
236238
{
@@ -247,10 +249,11 @@ public void AddSingletonComponent<T>(Action<T> callback = null) where T : struct
247249
public SingletonComponentRef<T> GetSingletonComponent<T>() where T : struct, ISingletonComponent
248250
{
249251
ref var entity = ref Entities[0];
250-
if (!entity.Tag.HasBit(TagRegistry.GetTagBitIndex(typeof(T))))
252+
var idx = TagRegistry.GetTagBitIndex(typeof(T));
253+
if (!entity.Tag.HasBit(idx))
251254
throw new InvalidOperationException($"Component {typeof(T)} not found.");
252255

253-
return new SingletonComponentRef<T>(0, this);
256+
return new SingletonComponentRef<T>(idx, this);
254257
}
255258

256259
/// <summary>
@@ -261,9 +264,14 @@ public SingletonComponentRef<T> GetSingletonComponent<T>() where T : struct, ISi
261264
/// <returns></returns>
262265
public bool TryGetSingletonComponent<T>(out SingletonComponentRef<T> value) where T : struct, ISingletonComponent
263266
{
267+
value = default;
264268
ref var entity = ref Entities[0];
265-
value = new SingletonComponentRef<T>(0, this);
266-
return entity.Tag.HasBit(TagRegistry.GetTagBitIndex(typeof(T)));
269+
var idx = TagRegistry.GetTagBitIndex(typeof(T));
270+
if (!entity.Tag.HasBit(idx))
271+
return false;
272+
273+
value = new SingletonComponentRef<T>(idx, this);
274+
return true;
267275
}
268276

269277
/// <summary>
@@ -442,12 +450,14 @@ public async ValueTask DisposeAsync()
442450
{
443451
group.Clear();
444452
}
453+
445454
Groups.Clear();
446455
// clear all components
447456
foreach (var arr in Components)
448457
{
449458
Array.Clear(arr, 0, arr.Length);
450459
}
460+
451461
Components = null;
452462
// clear all systems
453463
_executeSystems.Clear();
@@ -511,11 +521,16 @@ private void ProcessCommandBuffer()
511521
var id = _reusableIds.Count > 0 ? _reusableIds.Dequeue() : _entityIdCounter++;
512522
var entity = new Entity(this, id);
513523
// ensure array size
514-
if (id >= Entities.Length)
524+
int newLen = Math.Max(1, Entities.Length);
525+
int targetLen = id + 1;
526+
while (newLen < targetLen)
527+
{
528+
newLen *= 2;
529+
}
530+
531+
if (Entities.Length < newLen)
515532
{
516-
var arr2 = new Entity[id + 1];
517-
Array.Copy(Entities, arr2, Entities.Length);
518-
Entities = arr2;
533+
Array.Resize(ref Entities, newLen);
519534
}
520535

521536
Entities[id] = entity;
@@ -584,20 +599,27 @@ private void ProcessCommandBuffer()
584599
}
585600

586601
ref Entity entity = ref Entities[addComponentCommand.Id];
602+
byte bitIdx = TagRegistry.GetTagBitIndex(addComponentCommand.ComponentType);
587603

588604
// add to array
589-
var arr = Components[TagRegistry.GetTagBitIndex(addComponentCommand.ComponentType)];
590-
if (arr.Length < entity.Id + 1)
605+
var arr = Components[bitIdx];
606+
int newLen = Math.Max(1, arr.Length);
607+
int targetLen = entity.Id + 1;
608+
while (newLen < targetLen)
609+
{
610+
newLen *= 2;
611+
}
612+
613+
if (arr.Length < newLen)
591614
{
592-
var arr2 = Array.CreateInstance(addComponentCommand.ComponentType, entity.Id + 1);
615+
var arr2 = Array.CreateInstance(addComponentCommand.ComponentType, newLen);
593616
Array.Copy(arr, arr2, arr.Length);
594-
Components[TagRegistry.GetTagBitIndex(addComponentCommand.ComponentType)] = arr2;
617+
Components[bitIdx] = arr2;
595618
}
596619

597620
// set tag
598621
var oldTag = entity.Tag;
599-
entity.Tag.SetBit(
600-
TagRegistry.GetTagBitIndex(addComponentCommand.ComponentType));
622+
entity.Tag.SetBit(bitIdx);
601623
// move group
602624
if (Groups.TryGetValue(oldTag, out var oldGroup))
603625
{

EasyEcs.Core/Entity.cs

+12-4
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,11 @@ public void RemoveComponent<T>() where T : struct, IComponent
6464
/// <exception cref="InvalidOperationException"></exception>
6565
public ComponentRef<T> GetComponent<T>() where T : struct, IComponent
6666
{
67-
if (!Tag.HasBit(Context.TagRegistry.GetTagBitIndex(typeof(T))))
67+
var idx = Context.TagRegistry.GetTagBitIndex(typeof(T));
68+
if (!Tag.HasBit(idx))
6869
throw new InvalidOperationException($"Component {typeof(T)} not found.");
6970

70-
return new ComponentRef<T>(Id, Context);
71+
return new ComponentRef<T>(Id, idx, Context);
7172
}
7273

7374
/// <summary>
@@ -78,8 +79,15 @@ public ComponentRef<T> GetComponent<T>() where T : struct, IComponent
7879
/// <returns></returns>
7980
public bool TryGetComponent<T>(out ComponentRef<T> value) where T : struct, IComponent
8081
{
81-
value = new ComponentRef<T>(Id, Context);
82-
return Tag.HasBit(Context.TagRegistry.GetTagBitIndex(typeof(T)));
82+
var idx = Context.TagRegistry.GetTagBitIndex(typeof(T));
83+
if (!Tag.HasBit(idx))
84+
{
85+
value = default;
86+
return false;
87+
}
88+
89+
value = new ComponentRef<T>(Id, idx, Context);
90+
return true;
8391
}
8492

8593
/// <summary>

0 commit comments

Comments
 (0)