update EcsGroup

This commit is contained in:
Mikhail 2023-06-01 19:13:04 +08:00
parent 5f047a4507
commit 5c9452e56b

View File

@ -1,9 +1,11 @@
using System; using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
using static DCFApixels.DragonECS.EcsGroup.ThrowHalper; using static DCFApixels.DragonECS.EcsGroup.ThrowHelper;
#endif #endif
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
@ -57,9 +59,21 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) => _source.Has(entityID); public bool Has(int entityID) => _source.Has(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(int entityID) => _source.IndexOf(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup.Enumerator GetEnumerator() => _source.GetEnumerator(); public EcsGroup.Enumerator GetEnumerator() => _source.GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup Clone() => _source.Clone(); public EcsGroup Clone() => _source.Clone();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int[] Bake() => _source.Bake();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Bake(ref int[] entities) => _source.Bake(ref entities);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Bake(List<int> entities) => _source.Bake(entities);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<int> ToSpan() => _source.ToSpan();
public Span<int> ToSpan(int start, int length) => _source.ToSpan(start, length);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int First() => _source.First(); public int First() => _source.First();
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -95,7 +109,7 @@ namespace DCFApixels.DragonECS
} }
[DebuggerTypeProxy(typeof(DebuggerProxy))] [DebuggerTypeProxy(typeof(DebuggerProxy))]
public unsafe class EcsGroup : IDisposable, IEquatable<EcsGroup> public unsafe class EcsGroup : IDisposable, IEquatable<EcsGroup>, IEnumerable<int>
{ {
private EcsWorld _source; private EcsWorld _source;
private int[] _dense; private int[] _dense;
@ -143,7 +157,7 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region Constrcutors/Finalizer #region Constrcutors
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsGroup New(EcsWorld world) public static EcsGroup New(EcsWorld world)
{ {
@ -161,16 +175,12 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region Has #region Has/IndexOf
//TODO переименовать в Has
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) public bool Has(int entityID)
{ {
return _sparse[entityID] > 0; return _sparse[entityID] > 0;
} }
#endregion
#region IndexOf
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(int entityID) public int IndexOf(int entityID)
{ {
@ -234,7 +244,7 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region CopyFrom/Clone #region CopyFrom/Clone/Bake/ToSpan
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyFrom(EcsReadonlyGroup group) => CopyFrom(group.GetGroupInternal()); public void CopyFrom(EcsReadonlyGroup group) => CopyFrom(group.GetGroupInternal());
public void CopyFrom(EcsGroup group) public void CopyFrom(EcsGroup group)
@ -253,6 +263,33 @@ namespace DCFApixels.DragonECS
result.CopyFrom(this); result.CopyFrom(this);
return result; return result;
} }
public int[] Bake()
{
int[] result = new int[_count];
Array.Copy(_dense, result, _count);
return result;
}
public int Bake(ref int[] entities)
{
if(entities.Length < _count)
entities = new int[_count];
Array.Copy(_dense, entities, _count);
return _count;
}
public void Bake(List<int> entities)
{
entities.Clear();
foreach (var e in this)
entities.Add(e);
}
public Span<int> ToSpan() => new Span<int>(_dense, 0, _count);
public Span<int> ToSpan(int start, int length)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (start + length > _count) ThrowArgumentOutOfRangeException();
#endif
return new Span<int>(_dense, start, length);
}
#endregion #endregion
#region Set operations #region Set operations
@ -263,7 +300,7 @@ namespace DCFApixels.DragonECS
public void UnionWith(EcsGroup group) public void UnionWith(EcsGroup group)
{ {
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); if (_source != group.World) ThrowArgumentDifferentWorldsException();
#endif #endif
foreach (var item in group) foreach (var item in group)
if (!Has(item)) if (!Has(item))
@ -277,7 +314,7 @@ namespace DCFApixels.DragonECS
public void ExceptWith(EcsGroup group) public void ExceptWith(EcsGroup group)
{ {
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); if (_source != group.World) ThrowArgumentDifferentWorldsException();
#endif #endif
foreach (var item in this) foreach (var item in this)
if (group.Has(item)) if (group.Has(item))
@ -291,7 +328,7 @@ namespace DCFApixels.DragonECS
public void AndWith(EcsGroup group) public void AndWith(EcsGroup group)
{ {
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (World != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); if (World != group.World) ThrowArgumentDifferentWorldsException();
#endif #endif
foreach (var item in this) foreach (var item in this)
if (!group.Has(item)) if (!group.Has(item))
@ -305,7 +342,7 @@ namespace DCFApixels.DragonECS
public void XorWith(EcsGroup group) public void XorWith(EcsGroup group)
{ {
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); if (_source != group.World) ThrowArgumentDifferentWorldsException();
#endif #endif
foreach (var item in group) foreach (var item in group)
if (Has(item)) if (Has(item))
@ -316,18 +353,31 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Static Set operations #region Static Set operations
/// <summary>as Intersect sets</summary>
/// <returns>new group from pool</returns>
public static EcsGroup Union(EcsGroup a, EcsGroup b)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (a._source != b._source) ThrowArgumentDifferentWorldsException();
#endif
EcsGroup result = a._source.GetGroupFromPool();
foreach (var item in a)
result.AddInternal(item);
foreach (var item in b)
result.Add(item);
return result;
}
/// <summary>as Except sets</summary> /// <summary>as Except sets</summary>
/// <returns>new group from pool</returns> /// <returns>new group from pool</returns>
public static EcsGroup Except(EcsGroup a, EcsGroup b) public static EcsGroup Except(EcsGroup a, EcsGroup b)
{ {
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex"); if (a._source != b._source) ThrowArgumentDifferentWorldsException();
#endif #endif
EcsGroup result = a._source.GetGroupFromPool(); EcsGroup result = a._source.GetGroupFromPool();
foreach (var item in a) foreach (var item in a)
if (!b.Has(item)) if (!b.Has(item))
result.AddInternal(item); result.AddInternal(item);
a._source.ReleaseGroup(a);
return result; return result;
} }
/// <summary>as Intersect sets</summary> /// <summary>as Intersect sets</summary>
@ -335,50 +385,57 @@ namespace DCFApixels.DragonECS
public static EcsGroup And(EcsGroup a, EcsGroup b) public static EcsGroup And(EcsGroup a, EcsGroup b)
{ {
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex"); if (a._source != b._source) ThrowArgumentDifferentWorldsException();
#endif #endif
EcsGroup result = a._source.GetGroupFromPool(); EcsGroup result = a._source.GetGroupFromPool();
foreach (var item in a) foreach (var item in a)
if (b.Has(item)) if (b.Has(item))
result.AddInternal(item); result.AddInternal(item);
a._source.ReleaseGroup(a);
return result; return result;
} }
/// <summary>as Intersect sets</summary>
/// <summary>as Symmetric Except sets</summary>
/// <returns>new group from pool</returns> /// <returns>new group from pool</returns>
public static EcsGroup Union(EcsGroup a, EcsGroup b) public static EcsGroup Xor(EcsGroup a, EcsGroup b)
{ {
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex"); if (a._source != b._source) ThrowArgumentDifferentWorldsException();
#endif #endif
EcsGroup result = a._source.GetGroupFromPool(); EcsGroup result = a._source.GetGroupFromPool();
foreach (var item in a) foreach (var item in a)
result.AddInternal(item); if (!b.Has(item))
foreach (var item in a) result.AddInternal(item);
result.Add(item); foreach (var item in b)
if (!a.Has(item))
result.AddInternal(item);
return result; return result;
} }
#endregion #endregion
#region GetEnumerator #region Enumerator
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator() public Enumerator GetEnumerator()
{ {
return new Enumerator(this); return new Enumerator(this);
} }
#endregion IEnumerator IEnumerable.GetEnumerator()
{
#region Enumerator for (int i = 0; i < _count; i++)
public ref struct Enumerator// : IDisposable yield return _dense[i];
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
for (int i = 0; i < _count; i++)
yield return _dense[i];
}
public ref struct Enumerator
{ {
// private readonly EcsGroup source;
private readonly int[] _dense; private readonly int[] _dense;
private readonly int _count; private readonly int _count;
private int _index; private int _index;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator(EcsGroup group) public Enumerator(EcsGroup group)
{ {
// source = group;
_dense = group._dense; _dense = group._dense;
_count = group._count; _count = group._count;
_index = 0; _index = 0;
@ -390,8 +447,6 @@ namespace DCFApixels.DragonECS
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext() => ++_index <= _count && _count < _dense.Length; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны public bool MoveNext() => ++_index <= _count && _count < _dense.Length; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public void Dispose() => source.Unlock();
} }
#endregion #endregion
@ -401,12 +456,10 @@ namespace DCFApixels.DragonECS
public bool Equals(EcsReadonlyGroup other) => Equals(other.GetGroupInternal()); public bool Equals(EcsReadonlyGroup other) => Equals(other.GetGroupInternal());
public bool Equals(EcsGroup other) public bool Equals(EcsGroup other)
{ {
if (ReferenceEquals(other, null)) if (other is null || other.Count != Count)
return false; return false;
if (other.Count != Count) foreach (var e in other)
return false; if (!Has(e))
foreach (var item in other)
if (!Has(item))
return false; return false;
return true; return true;
} }
@ -431,8 +484,7 @@ namespace DCFApixels.DragonECS
private static bool StaticEquals(EcsGroup a, EcsReadonlyGroup b) => StaticEquals(a, b.GetGroupInternal()); private static bool StaticEquals(EcsGroup a, EcsReadonlyGroup b) => StaticEquals(a, b.GetGroupInternal());
private static bool StaticEquals(EcsGroup a, EcsGroup b) private static bool StaticEquals(EcsGroup a, EcsGroup b)
{ {
if (ReferenceEquals(a, null)) if (a is null) return false;
return false;
return a.Equals(b); return a.Equals(b);
} }
public static bool operator ==(EcsGroup a, EcsGroup b) => StaticEquals(a, b); public static bool operator ==(EcsGroup a, EcsGroup b) => StaticEquals(a, b);
@ -451,15 +503,12 @@ namespace DCFApixels.DragonECS
#region IDisposable/Release #region IDisposable/Release
public void Dispose() => Release(); public void Dispose() => Release();
public void Release() public void Release() => _source.ReleaseGroup(this);
{
_source.ReleaseGroup(this);
}
#endregion #endregion
#region ThrowHalper #region ThrowHalper
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
internal static class ThrowHalper internal static class ThrowHelper
{ {
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowAlreadyContains(int entityID) => throw new EcsFrameworkException($"This group already contains entity {entityID}."); public static void ThrowAlreadyContains(int entityID) => throw new EcsFrameworkException($"This group already contains entity {entityID}.");
@ -467,6 +516,10 @@ namespace DCFApixels.DragonECS
public static void ThrowArgumentOutOfRange() => throw new ArgumentOutOfRangeException($"index is less than 0 or is equal to or greater than Count."); public static void ThrowArgumentOutOfRange() => throw new ArgumentOutOfRangeException($"index is less than 0 or is equal to or greater than Count.");
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowDoesNotContain(int entityID) => throw new EcsFrameworkException($"This group does not contain entity {entityID}."); public static void ThrowDoesNotContain(int entityID) => throw new EcsFrameworkException($"This group does not contain entity {entityID}.");
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException();
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowArgumentDifferentWorldsException() => throw new ArgumentException("The groups belong to different worlds.");
} }
#endif #endif
#endregion #endregion