From 5c9452e56bd70b59b19965d07cf672b9179251b6 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 1 Jun 2023 19:13:04 +0800 Subject: [PATCH] update EcsGroup --- src/EcsGroup.cs | 141 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 97 insertions(+), 44 deletions(-) diff --git a/src/EcsGroup.cs b/src/EcsGroup.cs index 53b4c67..1a05b0c 100644 --- a/src/EcsGroup.cs +++ b/src/EcsGroup.cs @@ -1,9 +1,11 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS -using static DCFApixels.DragonECS.EcsGroup.ThrowHalper; +using static DCFApixels.DragonECS.EcsGroup.ThrowHelper; #endif namespace DCFApixels.DragonECS @@ -57,9 +59,21 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has(int entityID) => _source.Has(entityID); [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int IndexOf(int entityID) => _source.IndexOf(entityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public EcsGroup.Enumerator GetEnumerator() => _source.GetEnumerator(); [MethodImpl(MethodImplOptions.AggressiveInlining)] 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 entities) => _source.Bake(entities); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span ToSpan() => _source.ToSpan(); + public Span ToSpan(int start, int length) => _source.ToSpan(start, length); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int First() => _source.First(); [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -95,7 +109,7 @@ namespace DCFApixels.DragonECS } [DebuggerTypeProxy(typeof(DebuggerProxy))] - public unsafe class EcsGroup : IDisposable, IEquatable + public unsafe class EcsGroup : IDisposable, IEquatable, IEnumerable { private EcsWorld _source; private int[] _dense; @@ -143,7 +157,7 @@ namespace DCFApixels.DragonECS } #endregion - #region Constrcutors/Finalizer + #region Constrcutors [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsGroup New(EcsWorld world) { @@ -161,16 +175,12 @@ namespace DCFApixels.DragonECS } #endregion - #region Has - //TODO переименовать в Has + #region Has/IndexOf [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has(int entityID) { return _sparse[entityID] > 0; } - #endregion - - #region IndexOf [MethodImpl(MethodImplOptions.AggressiveInlining)] public int IndexOf(int entityID) { @@ -234,7 +244,7 @@ namespace DCFApixels.DragonECS } #endregion - #region CopyFrom/Clone + #region CopyFrom/Clone/Bake/ToSpan [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyFrom(EcsReadonlyGroup group) => CopyFrom(group.GetGroupInternal()); public void CopyFrom(EcsGroup group) @@ -253,6 +263,33 @@ namespace DCFApixels.DragonECS result.CopyFrom(this); 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 entities) + { + entities.Clear(); + foreach (var e in this) + entities.Add(e); + } + public Span ToSpan() => new Span(_dense, 0, _count); + public Span ToSpan(int start, int length) + { +#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS + if (start + length > _count) ThrowArgumentOutOfRangeException(); +#endif + return new Span(_dense, start, length); + } #endregion #region Set operations @@ -263,7 +300,7 @@ namespace DCFApixels.DragonECS public void UnionWith(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); + if (_source != group.World) ThrowArgumentDifferentWorldsException(); #endif foreach (var item in group) if (!Has(item)) @@ -277,7 +314,7 @@ namespace DCFApixels.DragonECS public void ExceptWith(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); + if (_source != group.World) ThrowArgumentDifferentWorldsException(); #endif foreach (var item in this) if (group.Has(item)) @@ -291,7 +328,7 @@ namespace DCFApixels.DragonECS public void AndWith(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (World != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); + if (World != group.World) ThrowArgumentDifferentWorldsException(); #endif foreach (var item in this) if (!group.Has(item)) @@ -305,7 +342,7 @@ namespace DCFApixels.DragonECS public void XorWith(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); + if (_source != group.World) ThrowArgumentDifferentWorldsException(); #endif foreach (var item in group) if (Has(item)) @@ -316,18 +353,31 @@ namespace DCFApixels.DragonECS #endregion #region Static Set operations + /// as Intersect sets + /// new group from pool + 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; + } /// as Except sets /// new group from pool public static EcsGroup Except(EcsGroup a, EcsGroup b) { #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 EcsGroup result = a._source.GetGroupFromPool(); foreach (var item in a) if (!b.Has(item)) result.AddInternal(item); - a._source.ReleaseGroup(a); return result; } /// as Intersect sets @@ -335,50 +385,57 @@ namespace DCFApixels.DragonECS public static EcsGroup And(EcsGroup a, EcsGroup b) { #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 EcsGroup result = a._source.GetGroupFromPool(); foreach (var item in a) if (b.Has(item)) result.AddInternal(item); - a._source.ReleaseGroup(a); return result; } - /// as Intersect sets + + /// as Symmetric Except sets /// new group from pool - 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 (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex"); + if (a._source != b._source) ThrowArgumentDifferentWorldsException(); #endif EcsGroup result = a._source.GetGroupFromPool(); foreach (var item in a) - result.AddInternal(item); - foreach (var item in a) - result.Add(item); + if (!b.Has(item)) + result.AddInternal(item); + foreach (var item in b) + if (!a.Has(item)) + result.AddInternal(item); return result; } #endregion - #region GetEnumerator + #region Enumerator [MethodImpl(MethodImplOptions.AggressiveInlining)] public Enumerator GetEnumerator() { return new Enumerator(this); } - #endregion - - #region Enumerator - public ref struct Enumerator// : IDisposable + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < _count; i++) + yield return _dense[i]; + } + IEnumerator IEnumerable.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 _count; private int _index; [MethodImpl(MethodImplOptions.AggressiveInlining)] public Enumerator(EcsGroup group) { - // source = group; _dense = group._dense; _count = group._count; _index = 0; @@ -390,8 +447,6 @@ namespace DCFApixels.DragonECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() => ++_index <= _count && _count < _dense.Length; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public void Dispose() => source.Unlock(); } #endregion @@ -401,12 +456,10 @@ namespace DCFApixels.DragonECS public bool Equals(EcsReadonlyGroup other) => Equals(other.GetGroupInternal()); public bool Equals(EcsGroup other) { - if (ReferenceEquals(other, null)) + if (other is null || other.Count != Count) return false; - if (other.Count != Count) - return false; - foreach (var item in other) - if (!Has(item)) + foreach (var e in other) + if (!Has(e)) return false; 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, EcsGroup b) { - if (ReferenceEquals(a, null)) - return false; + if (a is null) return false; return a.Equals(b); } public static bool operator ==(EcsGroup a, EcsGroup b) => StaticEquals(a, b); @@ -451,15 +503,12 @@ namespace DCFApixels.DragonECS #region IDisposable/Release public void Dispose() => Release(); - public void Release() - { - _source.ReleaseGroup(this); - } + public void Release() => _source.ReleaseGroup(this); #endregion #region ThrowHalper #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - internal static class ThrowHalper + internal static class ThrowHelper { [MethodImpl(MethodImplOptions.NoInlining)] 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."); [MethodImpl(MethodImplOptions.NoInlining)] 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 #endregion