diff --git a/README-RU.md b/README-RU.md index b443b71..930d102 100644 --- a/README-RU.md +++ b/README-RU.md @@ -89,12 +89,12 @@ DragonECS - это [ECS](https://en.wikipedia.org/wiki/Entity_component_system) Обязательные требования: + Минимальная версия C# 7.3; -Опционально: -+ Поддержка NativeAOT +Поддерживает: ++ NativeAOT; + Игровые движки с C#: Unity, Godot, MonoGame и т.д. Протестировано: -+ **Unity:** Минимальная версия 2020.3.0; ++ **Unity:** Минимальная версия 2021.2.0; ## Установка для Unity > Рекомендуется так же установить расширение [Интеграция с движком Unity](https://github.com/DCFApixels/DragonECS-Unity) @@ -125,6 +125,7 @@ https://github.com/DCFApixels/DragonECS.git * [Графы](https://github.com/DCFApixels/DragonECS-Graphs) * Утилиты: * [Упрощенный синтаксис](https://gist.github.com/DCFApixels/d7bfbfb8cb70d141deff00be24f28ff0) + * [EcsRefPool](https://gist.github.com/DCFApixels/73e392ccabdd98b3d4a517017d8a3f22) * [Таймеры](https://gist.github.com/DCFApixels/71a416275660c465ece76242290400df) * [Однокадровые компоненты](https://gist.github.com/DCFApixels/46d512dbcf96c115b94c3af502461f60) * [Шаблоны кода IDE](https://gist.github.com/ctzcs/0ba948b0e53aa41fe1c87796a401660b) и [для Unity](https://gist.github.com/ctzcs/d4c7730cf6cd984fe6f9e0e3f108a0f1) @@ -612,9 +613,9 @@ class Aspect : EcsAspect public EcsPool velocities; protected override void Init(Builder b) { - poses = b.IncludePool(); - velocities = b.IncludePool(); - b.ExcludePool(); + poses = b.Inc(); + velocities = b.Inc(); + b.Exc(); } } ``` @@ -638,8 +639,8 @@ class Aspect : EcsAspect otherAspect1 = b.Combine(1); // Хотя для OtherAspect1 метод Combine был вызван раньше, сначала будет скомбинирован с OtherAspect2, так как по умолчанию order = 0. otherAspect2 = b.Combine(); - // Если в OtherAspect1 или в OtherAspect2 было условие b.Exclude() тут оно будет заменено на b.Include(). - poses = b.Include(); + // Если в OtherAspect1 или в OtherAspect2 было условие b.Exc() тут оно будет заменено на b.Inc(). + poses = b.Inc(); } } ``` @@ -963,7 +964,6 @@ using (_marker.Auto()) + `DRAGONECS_DISABLE_CATH_EXCEPTIONS` - Выключает поведение по умолчанию по обработке исключений. По умолчанию фреймворк будет ловить исключения с выводом информации из исключений через EcsDebug и продолжать работу. + `REFLECTION_DISABLED` - Полностью ограничивает работу фреймворка с Reflection. + `DISABLE_DEBUG` - Для среды где не поддерживается ручное отключение DEBUG, например Unity. -+ `ENABLE_DUMMY_SPAN` - На случай если в среде не поддерживаются Span типы, включает его замену.
@@ -1123,13 +1123,6 @@ public struct WorldComponent : IEcsWorldComponent # FAQ -## 'ReadOnlySpan<>' could not be found -В версии Unity 2020.1.х в консоли может выпадать ошибка: -``` -The type or namespace name 'ReadOnlySpan<>' could not be found (are you missing a using directive or an assembly reference?) -``` -Чтобы починить добавьте директиву `ENABLE_DUMMY_SPAN` в `Project Settings/Player/Other Settings/Scripting Define Symbols`. - ## Как Выключать/Включать системы? Напрямую - никак.
Обычно потребность выключить/включить систему появляется когда поменялось общее состояние игры, это может так же значить что нужно переключить сразу группу систем, все это в совокупности можно рассматривать как изменения процессов. Есть 2 решения:
diff --git a/src/Collections/EcsGroup.cs b/src/Collections/EcsGroup.cs index ee7fd30..857694f 100644 --- a/src/Collections/EcsGroup.cs +++ b/src/Collections/EcsGroup.cs @@ -196,7 +196,7 @@ namespace DCFApixels.DragonECS { if (_groupSparsePagePoolCount <= 0) { - return MemoryAllocator.AllocAndInit(EcsGroup.PAGE_SIZE).As(); + return MemoryAllocator.AllocAndInit(EcsGroup.PAGE_SIZE).Ptr; } var takedPage = _groupSparsePagePool[--_groupSparsePagePoolCount]; _groupSparsePagePool[_groupSparsePagePoolCount] = MemoryAllocator.Handler.Empty; @@ -228,7 +228,7 @@ namespace DCFApixels.DragonECS for (int i = 0; i < _groupSparsePagePoolCount; i++) { ref var page = ref _groupSparsePagePool[i]; - if (page.IsEmpty == false) + if (page.IsCreated) { MemoryAllocator.FreeAndClear(ref page); } @@ -291,7 +291,7 @@ namespace DCFApixels.DragonECS private int _count = 0; internal bool _isReleased = true; - internal static readonly int* _nullPage = MemoryAllocator.AllocAndInit(PageSlot.SIZE).As(); + internal static readonly int* _nullPage = MemoryAllocator.AllocAndInit(PageSlot.SIZE).Ptr; internal static readonly long _nullPagePtrFake = (long)_nullPage; #region Properties @@ -344,17 +344,6 @@ namespace DCFApixels.DragonECS #endif return _dense[++index]; } - // [MethodImpl(MethodImplOptions.AggressiveInlining)] - // set - // { - // // TODO добавить лок енумератора на изменение - //#if DEBUG || DRAGONECS_STABILITY_MODE - // if (index < 0 || index >= Count) { Throw.ArgumentOutOfRange(); } - //#endif - // var oldValue = _dense[index]; - // _dense[index] = value; - // _sparse[oldValue] = 0; - // } } #endregion @@ -394,7 +383,7 @@ namespace DCFApixels.DragonECS page.IndexesXOR = 0; page.Count = 0; } - _sparsePagesHandler.Dispose(); + _sparsePagesHandler.DisposeAndReset(); } } public void Dispose() @@ -555,7 +544,6 @@ namespace DCFApixels.DragonECS ref PageSlot page = ref _sparsePages[i]; if (page.Indexes != _nullPage) { - //TODO тут надо оптимизировать отчисткой не всего а по dense списку for (int j = 0; j < PageSlot.SIZE; j++) { page.Indexes[j] = 0; diff --git a/src/Collections/EcsSpan.cs b/src/Collections/EcsSpan.cs index d68ee27..02a9351 100644 --- a/src/Collections/EcsSpan.cs +++ b/src/Collections/EcsSpan.cs @@ -1,6 +1,7 @@ #if DISABLE_DEBUG #undef DEBUG #endif +using DCFApixels.DragonECS.Core; using DCFApixels.DragonECS.Core.Internal; using DCFApixels.DragonECS.Core.Unchecked; using System; @@ -50,7 +51,7 @@ namespace DCFApixels.DragonECS public bool IsSourceEntities { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return this == EcsWorld.GetWorld(_worldID).GetCurrentEntities_Internal(); } + get { return _values == EcsWorld.GetWorld(_worldID).GetCurrentEntities_Internal()._values; } } #if ENABLE_IL2CPP [Il2CppSetOption(Option.ArrayBoundsChecks, true)] @@ -117,8 +118,8 @@ namespace DCFApixels.DragonECS #endregion #region operators - public static bool operator ==(EcsSpan left, EcsSpan right) { return left._values == right._values; } - public static bool operator !=(EcsSpan left, EcsSpan right) { return left._values != right._values; } + public static bool operator ==(EcsSpan left, EcsSpan right) { return left._values == right._values && left._worldID == right._worldID; } + public static bool operator !=(EcsSpan left, EcsSpan right) { return left._values != right._values || left._worldID != right._worldID; } #endregion #region Enumerator @@ -127,6 +128,7 @@ namespace DCFApixels.DragonECS #endregion #region Other + public ReadOnlySpan AsSystemSpan() { return _values; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int First() { return _values[0]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -170,6 +172,7 @@ namespace DCFApixels.DragonECS _worldID = span._worldID; } public DebuggerProxy(EcsLongsSpan span) : this(span.ToSpan()) { } + public DebuggerProxy(EcsUnsafeSpan span) : this(span.ToSpan()) { } } #endregion } @@ -316,4 +319,166 @@ namespace DCFApixels.DragonECS #pragma warning restore CS0809 // Устаревший член переопределяет неустаревший член #endregion } +} + +namespace DCFApixels.DragonECS.Core +{ +#if ENABLE_IL2CPP + using Unity.IL2CPP.CompilerServices; + [Il2CppSetOption(Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +#endif + [DebuggerTypeProxy(typeof(EcsSpan.DebuggerProxy))] + public unsafe readonly struct EcsUnsafeSpan + { + private readonly int* _values; + private readonly int _length; + private readonly short _worldID; + + #region Properties + public bool IsNull + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _worldID == 0; } + } + public short WorldID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _worldID; } + } + public EcsWorld World + { + get { return EcsWorld.GetWorld(_worldID); } + } + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _length; } + } + public EcsLongsSpan Longs + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return ToSpan().Longs; } + } + public bool IsSourceEntities + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return ToSpan().IsSourceEntities; } + } + + public int this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { +#if DEBUG + if ((uint)index >= (uint)_length || (uint)index < 0) + { + ThrowHelper.ThrowIndexOutOfRangeException(); + } +#elif DRAGONECS_STABILITY_MODE + return EcsConsts.NULL_ENTITY_ID; +#endif + return _values[index]; + } + } + #endregion + + #region Constructors + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal EcsUnsafeSpan(short worldID, int* array, int length) + { + _worldID = worldID; + _values = array; + _length = length; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal EcsUnsafeSpan(short worldID, int* array, int start, int length) + { + _worldID = worldID; + _values = array + start; + _length = length; + } + #endregion + + #region Slice/ToArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsUnsafeSpan Slice(int start) + { + if ((uint)start > (uint)_length) + { + ThrowHelper.ThrowArgumentOutOfRangeException(); + } + return new EcsUnsafeSpan(_worldID, _values, start, _length - start); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsUnsafeSpan Slice(int start, int length) + { + if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start)) + { + ThrowHelper.ThrowArgumentOutOfRangeException(); + } + return new EcsUnsafeSpan(_worldID, _values, start, length); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsSpan ToSpan() { return new EcsSpan(_worldID, new ReadOnlySpan(_values, _length)); } + public int[] ToArray() { return new ReadOnlySpan(_values, _length).ToArray(); } + public int ToArray(ref int[] dynamicBuffer) + { + if (dynamicBuffer.Length < _length) + { + Array.Resize(ref dynamicBuffer, ArrayUtility.CeilPow2(_length)); + } + int i = 0; + foreach (var e in this) + { + dynamicBuffer[i++] = e; + } + return i; + } + public void ToCollection(ICollection collection) + { + foreach (var e in this) + { + collection.Add(e); + } + } + #endregion + + #region operators + public static bool operator ==(EcsUnsafeSpan left, EcsUnsafeSpan right) { return left._values == right._values && left._length == right._length && left._worldID == right._worldID; } + public static bool operator !=(EcsUnsafeSpan left, EcsUnsafeSpan right) { return left._values != right._values || left._length != right._length || left._worldID != right._worldID; } + public static implicit operator EcsSpan(EcsUnsafeSpan a) { return a.ToSpan(); } + #endregion + + #region Enumerator + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan.Enumerator GetEnumerator() { return new ReadOnlySpan(_values, _length).GetEnumerator(); } + #endregion + + #region Other + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int First() { return _values[0]; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Last() { return _values[_length - 1]; } + public override string ToString() + { + return CollectionUtility.EntitiesToString(ToArray(), "span"); + } + public override bool Equals(object obj) + { + return obj is EcsUnsafeSpan other && other == this; + } + public override int GetHashCode() + { + return *_values ^ _length ^ (_worldID << 16); + } + private static class ThrowHelper + { + public static void ThrowIndexOutOfRangeException() => throw new IndexOutOfRangeException(); + public static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException(); + public static void ThrowInvalidOperationException() => throw new InvalidOperationException(); + } + #endregion + } } \ No newline at end of file diff --git a/src/Consts.cs b/src/Consts.cs index fb97ee7..cf620b2 100644 --- a/src/Consts.cs +++ b/src/Consts.cs @@ -88,42 +88,6 @@ namespace DCFApixels.DragonECS true; #else false; -#endif - public const bool ENABLE_DUMMY_SPAN = -#if ENABLE_DUMMY_SPAN - true; -#else - false; -#endif - - - [Obsolete("DRAGONECS_ENABLE_DEBUG_SERVICE")] - public const bool ENABLE_DRAGONECS_DEBUGGER = -#if ENABLE_DRAGONECS_DEBUGGER - true; -#else - false; -#endif - [Obsolete("DRAGONECS_DISABLE_POOLS_EVENTS")] - public const bool DISABLE_POOLS_EVENTS = -#if DISABLE_POOLS_EVENTS - true; -#else - false; -#endif - [Obsolete("DRAGONECS_DISABLE_CATH_EXCEPTIONS")] - public const bool DISABLE_CATH_EXCEPTIONS = -#if DISABLE_CATH_EXCEPTIONS - true; -#else - false; -#endif - [Obsolete("DRAGONECS_STABILITY_MODE")] - public const bool ENABLE_DRAGONECS_ASSERT_CHEKS = -#if ENABLE_DRAGONECS_ASSERT_CHEKS - true; -#else - false; #endif } } diff --git a/src/DataInterfaces.cs b/src/DataInterfaces.cs index 3a46db5..945e072 100644 --- a/src/DataInterfaces.cs +++ b/src/DataInterfaces.cs @@ -11,63 +11,84 @@ namespace DCFApixels.DragonECS.Core void Init(ref T component, EcsWorld world); void OnDestroy(ref T component, EcsWorld world); } - public static class EcsWorldComponentHandler + public static class EcsWorldComponent { - public static readonly IEcsWorldComponent instance; - public static readonly bool isHasHandler; - static EcsWorldComponentHandler() + public static readonly IEcsWorldComponent CustomHandler; + public static readonly bool IsCustom; + static EcsWorldComponent() { - T def = default; - if (def is IEcsWorldComponent intrf) + T raw = default; + if (raw is IEcsWorldComponent handler) { - isHasHandler = true; - instance = intrf; + IsCustom = true; + CustomHandler = handler; } else { - isHasHandler = false; - instance = new DummyHandler(); + IsCustom = false; + CustomHandler = new DummyHandler(); } } - private class DummyHandler : IEcsWorldComponent + private sealed class DummyHandler : IEcsWorldComponent { [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Init(ref T component, EcsWorld world) { } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void OnDestroy(ref T component, EcsWorld world) { } } } #endregion - #region IEcsComponentReset + #region IEcsComponentLifecycle public interface IEcsComponentLifecycle { - void Enable(ref T component); - void Disable(ref T component); + void OnAdd(ref T component, short worldID, int entityID); + void OnDel(ref T component, short worldID, int entityID); } - public static class EcsComponentLifecycleHandler + public static class EcsComponentLifecycle where T : struct { - public static readonly IEcsComponentLifecycle instance; - public static readonly bool isHasHandler; - static EcsComponentLifecycleHandler() + public static readonly IEcsComponentLifecycle CustomHandler; + public static readonly bool IsCustom; + static EcsComponentLifecycle() { - T def = default; - if (def is IEcsComponentLifecycle intrf) + T raw = default; + if (raw is IEcsComponentLifecycle handler) { - isHasHandler = true; - instance = intrf; + IsCustom = true; + CustomHandler = handler; } else { - isHasHandler = false; - instance = new DummyHandler(); + IsCustom = false; + CustomHandler = new DummyHandler(); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void OnAdd(bool isCustom, IEcsComponentLifecycle custom, ref T component, short worldID, int entityID) + { + if (isCustom) + { + custom.OnAdd(ref component, worldID, entityID); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void OnDel(bool isCustom, IEcsComponentLifecycle custom, ref T component, short worldID, int entityID) + { + if (isCustom) + { + custom.OnDel(ref component, worldID, entityID); + } + else + { + component = default; } } private sealed class DummyHandler : IEcsComponentLifecycle { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Enable(ref T component) { component = default; } + public void OnAdd(ref T component, short worldID, int entityID) { component = default; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Disable(ref T component) { component = default; } + public void OnDel(ref T component, short worldID, int entityID) { component = default; } } } #endregion @@ -77,22 +98,34 @@ namespace DCFApixels.DragonECS.Core { void Copy(ref T from, ref T to); } - public static class EcsComponentCopyHandler + public static class EcsComponentCopy where T : struct { - public static readonly IEcsComponentCopy instance; - public static readonly bool isHasHandler; - static EcsComponentCopyHandler() + public static readonly IEcsComponentCopy CustomHandler; + public static readonly bool IsCustom; + static EcsComponentCopy() { - T def = default; - if (def is IEcsComponentCopy intrf) + T raw = default; + if (raw is IEcsComponentCopy handler) { - isHasHandler = true; - instance = intrf; + IsCustom = true; + CustomHandler = handler; } else { - isHasHandler = false; - instance = new DummyHandler(); + IsCustom = false; + CustomHandler = new DummyHandler(); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Copy(bool isCustom, IEcsComponentCopy custom, ref T from, ref T to) + { + if (isCustom) + { + custom.Copy(ref from, ref to); + } + else + { + to = from; } } private sealed class DummyHandler : IEcsComponentCopy @@ -102,4 +135,4 @@ namespace DCFApixels.DragonECS.Core } } #endregion -} +} \ No newline at end of file diff --git a/src/DebugUtils/EcsDebugUtility.cs b/src/DebugUtils/EcsDebugUtility.cs index 6a0f794..4ff1577 100644 --- a/src/DebugUtils/EcsDebugUtility.cs +++ b/src/DebugUtils/EcsDebugUtility.cs @@ -285,7 +285,7 @@ namespace DCFApixels.DragonECS public static TypeMeta GetTypeMeta(object obj) { if (obj == null) { return TypeMeta.NullTypeMeta; } - return TypeMeta.Get(GetTypeMetaSource(obj).GetType()); + return TypeMeta.Get(Type.GetTypeHandle(GetTypeMetaSource(obj))); } public static TypeMeta GetTypeMeta() { @@ -295,6 +295,10 @@ namespace DCFApixels.DragonECS { return TypeMeta.Get(type); } + public static TypeMeta GetTypeMeta(RuntimeTypeHandle typeHandle) + { + return TypeMeta.Get(typeHandle); + } #endregion #region TypeMetaProvider @@ -318,7 +322,11 @@ namespace DCFApixels.DragonECS #endif return EcsDebugUtility.GetTypeMeta(self); } - public static TypeMeta ToMeta(this Type self) + public static TypeMeta GetMeta(this Type self) + { + return EcsDebugUtility.GetTypeMeta(self); + } + public static TypeMeta GetMeta(this RuntimeTypeHandle self) { return EcsDebugUtility.GetTypeMeta(self); } diff --git a/src/DebugUtils/TypeMeta.cs b/src/DebugUtils/TypeMeta.cs index 0422993..15fae1e 100644 --- a/src/DebugUtils/TypeMeta.cs +++ b/src/DebugUtils/TypeMeta.cs @@ -46,7 +46,7 @@ namespace DCFApixels.DragonECS public static readonly TypeMeta NullTypeMeta; private static readonly object _lock = new object(); - private static readonly Dictionary _metaCache = new Dictionary(); + private static readonly Dictionary _metaCache = new Dictionary(); private static int _increment = 1; private readonly int _uniqueID; @@ -93,16 +93,17 @@ namespace DCFApixels.DragonECS _initFlags = InitFlag.All, }; - _metaCache.Add(typeof(void), NullTypeMeta); + _metaCache.Add(typeof(void).TypeHandle, NullTypeMeta); } - public static TypeMeta Get(Type type) + public static TypeMeta Get(Type type) { return Get(type.TypeHandle); } + public static TypeMeta Get(RuntimeTypeHandle typeHandle) { - lock (_lock) //TODO посмотреть можно ли тут убрать лок + lock (_lock) { - if (_metaCache.TryGetValue(type, out TypeMeta result) == false) + if (_metaCache.TryGetValue(typeHandle, out TypeMeta result) == false) { - result = new TypeMeta(type); - _metaCache.Add(type, result); + result = new TypeMeta(Type.GetTypeFromHandle(typeHandle)); + _metaCache.Add(typeHandle, result); } return result; } @@ -375,7 +376,7 @@ namespace DCFApixels.DragonECS lock (_lock) { _metaCache.Clear(); - _metaCache.Add(typeof(void), NullTypeMeta); + _metaCache.Add(typeof(void).TypeHandle, NullTypeMeta); } } ITypeMeta ITypeMeta.BaseMeta @@ -395,7 +396,7 @@ namespace DCFApixels.DragonECS { if (IsHasCustomMeta(type)) { - meta = type.ToMeta(); + meta = type.GetMeta(); return true; } meta = null; @@ -469,15 +470,6 @@ namespace DCFApixels.DragonECS } #endregion - #region Obsolete - [Obsolete("Use TryGetCustomMeta(type)")] - [EditorBrowsable(EditorBrowsableState.Never)] - public static bool IsHasMeta(Type type) - { - return IsHasCustomMeta(type); - } - #endregion - #region MetaGenerator private static class MetaGenerator { diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index 0a2afc9..0943c61 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -418,52 +418,6 @@ namespace DCFApixels.DragonECS EcsMask IComponentMask.ToMask(EcsWorld world) { return _mask; } #endregion - #region Obsolete - [Obsolete("Use EcsMask.GetIterator()")] - public Iterator GetIterator() - { - return new Iterator(Mask.GetIterator(), _source.Entities); - } - [Obsolete("Use EcsMask.GetIterator().Iterate(span)")] - public Iterator GetIteratorFor(EcsSpan span) - { - return new Iterator(Mask.GetIterator(), span); - } - [Obsolete("Use EcsMaskIterator")] - public ref struct Iterator - { - public readonly short worldID; - public readonly EcsMaskIterator.Enumerable iterator; - - public Iterator(EcsMaskIterator iterator, EcsSpan span) - { - worldID = iterator.World.ID; - this.iterator = iterator.Iterate(span); - } - - #region CopyTo - public void CopyTo(EcsGroup group) - { - iterator.CopyTo(group); - } - public int CopyTo(ref int[] array) - { - return iterator.CopyTo(ref array); - } - public EcsSpan CopyToSpan(ref int[] array) - { - int count = CopyTo(ref array); - return new EcsSpan(worldID, array, count); - } - #endregion - - public EcsMaskIterator.Enumerable.Enumerator GetEnumerator() - { - return iterator.GetEnumerator(); - } - } - #endregion - #region Events public delegate void OnInitApectHandler(object aspect, Builder builder); public static event OnInitApectHandler OnInit = delegate { }; diff --git a/src/EcsMask.cs b/src/EcsMask.cs index 2aa5376..58ca6e5 100644 --- a/src/EcsMask.cs +++ b/src/EcsMask.cs @@ -5,7 +5,6 @@ using DCFApixels.DragonECS.Core; using DCFApixels.DragonECS.Core.Internal; using System; using System.Collections.Generic; -using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; @@ -34,6 +33,7 @@ namespace DCFApixels.DragonECS { public readonly int ID; public readonly short WorldID; + public readonly EcsWorld World; internal readonly EcsStaticMask _staticMask; internal readonly EcsMaskChunck[] _incChunckMasks; @@ -51,11 +51,6 @@ namespace DCFApixels.DragonECS private EcsMaskIterator _iterator; #region Properties - public EcsWorld World - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return EcsWorld.GetWorld(WorldID); } - } /// Sorted set excluding constraints. public ReadOnlySpan Incs { @@ -74,6 +69,25 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _anys; } } + + /// Sorted set including constraints presented as global type codes. + public ReadOnlySpan IncTypeCodes + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return ToStatic().IncTypeCodes; } + } + /// Sorted set excluding constraints presented as global type codes. + public ReadOnlySpan ExcTypeCodes + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return ToStatic().ExcTypeCodes; } + } + /// Sorted set any constraints presented as global type codes. + public ReadOnlySpan AnyTypeCodes + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return ToStatic().AnyTypeCodes; } + } public EcsMaskFlags Flags { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -116,6 +130,7 @@ namespace DCFApixels.DragonECS _staticMask = staticMask; ID = id; WorldID = worldID; + World = EcsWorld.GetWorld(worldID); _flags = staticMask.Flags; EcsWorld world = EcsWorld.GetWorld(worldID); @@ -345,8 +360,6 @@ namespace DCFApixels.DragonECS internal EcsMask ConvertFromStatic(EcsStaticMask staticMask) { - - if (_staticMasks.TryGetValue(staticMask.ID, out EcsMask result) == false) { result = new EcsMask(staticMask, _staticMasks.Count, _world.ID); @@ -367,20 +380,42 @@ namespace DCFApixels.DragonECS _world = world; _builder = EcsStaticMask.New(); } - + public Builder Inc() { return this; } + public Builder Exc() { return this; } + public Builder Any() { return this; } public Builder Inc() { _builder.Inc(); return this; } public Builder Exc() { _builder.Exc(); return this; } public Builder Any() { _builder.Any(); return this; } public Builder Inc(Type type) { _builder.Inc(type); return this; } public Builder Exc(Type type) { _builder.Exc(type); return this; } public Builder Any(Type type) { _builder.Any(type); return this; } + public Builder Inc(params Type[] types) { _builder.Inc(types); return this; } + public Builder Exc(params Type[] types) { _builder.Exc(types); return this; } + public Builder Any(params Type[] types) { _builder.Any(types); return this; } + public Builder Inc(ReadOnlySpan types) { _builder.Inc(types); return this; } + public Builder Exc(ReadOnlySpan types) { _builder.Exc(types); return this; } + public Builder Any(ReadOnlySpan types) { _builder.Any(types); return this; } + public Builder Inc(IEnumerable types) { _builder.Inc(types); return this; } + public Builder Exc(IEnumerable types) { _builder.Exc(types); return this; } + public Builder Any(IEnumerable types) { _builder.Any(types); return this; } public Builder Inc(EcsTypeCode typeCode) { _builder.Inc(typeCode); return this; } public Builder Exc(EcsTypeCode typeCode) { _builder.Exc(typeCode); return this; } public Builder Any(EcsTypeCode typeCode) { _builder.Any(typeCode); return this; } + public Builder Inc(params EcsTypeCode[] typeCodes) { _builder.Inc(typeCodes); return this; } + public Builder Exc(params EcsTypeCode[] typeCodes) { _builder.Exc(typeCodes); return this; } + public Builder Any(params EcsTypeCode[] typeCodes) { _builder.Any(typeCodes); return this; } + public Builder Inc(ReadOnlySpan typeCodes) { _builder.Inc(typeCodes); return this; } + public Builder Exc(ReadOnlySpan typeCodes) { _builder.Exc(typeCodes); return this; } + public Builder Any(ReadOnlySpan typeCodes) { _builder.Any(typeCodes); return this; } + public Builder Inc(IEnumerable typeCodes) { _builder.Inc(typeCodes); return this; } + public Builder Exc(IEnumerable typeCodes) { _builder.Exc(typeCodes); return this; } + public Builder Any(IEnumerable typeCodes) { _builder.Any(typeCodes); return this; } + public Builder Combine(EcsMask mask) { _builder.Combine(mask._staticMask); return this; } public Builder Except(EcsMask mask) { _builder.Except(mask._staticMask); return this; } public EcsMask Build() { return _world.Get().ConvertFromStatic(_builder.Build()); } + public static implicit operator EcsMask(Builder a) { return a.Build(); } } #endregion @@ -402,15 +437,18 @@ namespace DCFApixels.DragonECS public readonly int ID; public readonly EcsWorld world; private readonly short _worldID; - public readonly EcsMaskChunck[] includedChunkMasks; - public readonly EcsMaskChunck[] excludedChunkMasks; - public readonly EcsMaskChunck[] anyChunkMasks; - public readonly int[] included; - public readonly int[] excluded; - public readonly int[] any; - public readonly Type[] includedTypes; - public readonly Type[] excludedTypes; - public readonly Type[] anyTypes; + public readonly EcsMaskChunck[] incsChunkMasks; + public readonly EcsMaskChunck[] excsChunkMasks; + public readonly EcsMaskChunck[] anysChunkMasks; + public readonly int[] incs; + public readonly int[] excs; + public readonly int[] anys; + public readonly Type[] incsTypes; + public readonly Type[] excsTypes; + public readonly Type[] anysTypes; + public readonly IEcsPool[] incsPools; + public readonly IEcsPool[] excsPools; + public readonly IEcsPool[] anysPools; public bool IsEmpty { get { return _source.IsEmpty; } } public bool IsBroken { get { return _source.IsBroken; } } @@ -422,51 +460,27 @@ namespace DCFApixels.DragonECS ID = mask.ID; world = EcsWorld.GetWorld(mask.WorldID); _worldID = mask.WorldID; - includedChunkMasks = mask._incChunckMasks; - excludedChunkMasks = mask._excChunckMasks; - anyChunkMasks = mask._anyChunckMasks; - included = mask._incs; - excluded = mask._excs; - any = mask._anys; + incsChunkMasks = mask._incChunckMasks; + excsChunkMasks = mask._excChunckMasks; + anysChunkMasks = mask._anyChunckMasks; + incs = mask._incs; + excs = mask._excs; + anys = mask._anys; Type converter(int o) { return world.GetComponentType(o); } - includedTypes = included.Select(converter).ToArray(); - excludedTypes = excluded.Select(converter).ToArray(); - anyTypes = any.Select(converter).ToArray(); + IEcsPool converterPool(int o) { return world.FindPoolInstance(o); } + incsTypes = incs.Select(converter).ToArray(); + excsTypes = excs.Select(converter).ToArray(); + anysTypes = anys.Select(converter).ToArray(); + incsPools = incs.Select(converterPool).ToArray(); + excsPools = excs.Select(converterPool).ToArray(); + anysPools = anys.Select(converterPool).ToArray(); } public override string ToString() { - return CreateLogString(_worldID, included, excluded, any); + return CreateLogString(_worldID, incs, excs, anys); } } #endregion - - #region Obsolete - /// Sorted set including constraints. - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Use Incs")] - public ReadOnlySpan Inc - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _incs; } - } - /// Sorted set excluding constraints. - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Use Excs")] - public ReadOnlySpan Exc - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _excs; } - } - public partial struct Builder - { - [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Include() { return Inc(); } - [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Exclude() { return Exc(); } - [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Include(Type type) { return Inc(type); } - [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Exclude(Type type) { return Exc(type); } - [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Inc(int componentTypeID) { Inc(_world.GetComponentType(componentTypeID)); return this; } - [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Exc(int componentTypeID) { Exc(_world.GetComponentType(componentTypeID)); return this; } - } - #endregion } [Flags] @@ -607,8 +621,8 @@ namespace DCFApixels.DragonECS } private void Cleanup(bool disposing) { - _bufferHandler.Dispose(); - _chunckBufferHandler.Dispose(); + _bufferHandler.DisposeAndReset(); + _chunckBufferHandler.DisposeAndReset(); } #endregion @@ -636,8 +650,7 @@ namespace DCFApixels.DragonECS if (_sortIncChunckBuffer.Length > 1) { - var comparer = new IncCountComparer(counts); - UnsafeArraySortHalperX.InsertionSort(sortIncBuffer.ptr, sortIncBuffer.Length, ref comparer); + SortHalper.Sort(sortIncBuffer.AsSpan(), new IncCountComparer(counts)); ConvertToChuncks(preSortingBuffer, sortIncBuffer, _sortIncChunckBuffer); } if (_sortIncChunckBuffer.Length > 0) @@ -651,8 +664,7 @@ namespace DCFApixels.DragonECS if (_sortExcChunckBuffer.Length > 1) { - ExcCountComparer comparer = new ExcCountComparer(counts); - UnsafeArraySortHalperX.InsertionSort(sortExcBuffer.ptr, sortExcBuffer.Length, ref comparer); + SortHalper.Sort(sortExcBuffer.AsSpan(), new ExcCountComparer(counts)); ConvertToChuncks(preSortingBuffer, sortExcBuffer, _sortExcChunckBuffer); } // Выражение IncCount < (AllEntitesCount - ExcCount) мало вероятно будет истинным. @@ -662,8 +674,7 @@ namespace DCFApixels.DragonECS if (_sortAnyChunckBuffer.Length > 1) { - ExcCountComparer comparer = new ExcCountComparer(counts); - UnsafeArraySortHalperX.InsertionSort(sortAnyBuffer.ptr, sortAnyBuffer.Length, ref comparer); + SortHalper.Sort(sortAnyBuffer.AsSpan(), new ExcCountComparer(counts)); ConvertToChuncks(preSortingBuffer, sortAnyBuffer, _sortAnyChunckBuffer); } // Any не влияет на maxEntites если есть Inc и сложно высчитывается если нет Inc @@ -691,9 +702,13 @@ namespace DCFApixels.DragonECS #endregion #region IterateTo - //TODO Перемеиноваться в CacheTo + public EcsMaskFlags MaskFlags + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _maskFlags; } + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void IterateTo(EcsSpan source, EcsGroup group) + public void CacheTo(EcsSpan source, EcsGroup group) { switch (_maskFlags) { @@ -701,7 +716,7 @@ namespace DCFApixels.DragonECS group.CopyFrom(source); break; case EcsMaskFlags.Inc: - IterateOnlyInc(source).CopyTo(group); + IterateOnlyInc(source).CacheTo(group); break; case EcsMaskFlags.Exc: case EcsMaskFlags.Any: @@ -709,7 +724,7 @@ namespace DCFApixels.DragonECS case EcsMaskFlags.IncAny: case EcsMaskFlags.ExcAny: case EcsMaskFlags.IncExcAny: - Iterate(source).CopyTo(group); + Iterate(source).CacheTo(group); break; case EcsMaskFlags.Broken: group.Clear(); @@ -720,21 +735,21 @@ namespace DCFApixels.DragonECS } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int IterateTo(EcsSpan source, ref int[] array) + public int CacheTo(EcsSpan source, ref int[] array) { switch (_maskFlags) { case EcsMaskFlags.Empty: return source.ToArray(ref array); case EcsMaskFlags.Inc: - return IterateOnlyInc(source).CopyTo(ref array); + return IterateOnlyInc(source).CacheTo(ref array); case EcsMaskFlags.Exc: case EcsMaskFlags.Any: case EcsMaskFlags.IncExc: case EcsMaskFlags.IncAny: case EcsMaskFlags.ExcAny: case EcsMaskFlags.IncExcAny: - return Iterate(source).CopyTo(ref array); + return Iterate(source).CacheTo(ref array); case EcsMaskFlags.Broken: return new EcsSpan(World.ID, Array.Empty()).ToArray(ref array); default: @@ -764,7 +779,7 @@ namespace DCFApixels.DragonECS #region CopyTo [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyTo(EcsGroup group) + public void CacheTo(EcsGroup group) { group.Clear(); var enumerator = GetEnumerator(); @@ -774,7 +789,7 @@ namespace DCFApixels.DragonECS } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int CopyTo(ref int[] array) + public int CacheTo(ref int[] array) { int count = 0; var enumerator = GetEnumerator(); @@ -920,7 +935,7 @@ namespace DCFApixels.DragonECS #region CopyTo [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyTo(EcsGroup group) + public void CacheTo(EcsGroup group) { group.Clear(); var enumerator = GetEnumerator(); @@ -930,7 +945,7 @@ namespace DCFApixels.DragonECS } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int CopyTo(ref int[] array) + public int CacheTo(ref int[] array) { int count = 0; var enumerator = GetEnumerator(); @@ -1077,7 +1092,7 @@ namespace DCFApixels.DragonECS.Core.Internal [Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif - internal readonly struct IncCountComparer : IStructComparer + internal readonly struct IncCountComparer : IComparer { public readonly EcsWorld.PoolSlot[] counts; [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1096,7 +1111,7 @@ namespace DCFApixels.DragonECS.Core.Internal [Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif - internal readonly struct ExcCountComparer : IStructComparer + internal readonly struct ExcCountComparer : IComparer { public readonly EcsWorld.PoolSlot[] counts; [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/EcsPipeline.Builder.cs b/src/EcsPipeline.Builder.cs index e06c7ae..0298976 100644 --- a/src/EcsPipeline.Builder.cs +++ b/src/EcsPipeline.Builder.cs @@ -122,7 +122,6 @@ namespace DCFApixels.DragonECS } private void InsertAfterNode_Internal(int insertAfterIndex, IEcsProcess system, string layer, int sortOrder, bool isUnique) { - //TODO нужно потестить if (isUnique && _uniqueSystemsSet.Add(system.GetType()) == false) { //EcsDebug.PrintWarning($"The pipeline already contains a unique instance of {system.GetType().Name}"); @@ -600,20 +599,6 @@ namespace DCFApixels.DragonECS } } #endregion - - #region Obsolete - [Obsolete("Use " + nameof(Injections))] - public readonly InitInjectionList Injector; - [Obsolete("Use LayersMap")] - public class LayerList : LayersMap - { - //public LayerList(Builder source, string basicLayerName) : base(source, basicLayerName) { } - //public LayerList(Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) : base(source, preBeginlayer, beginlayer, basicLayer, endLayer, postEndLayer) { } - public LayerList(IDependencyGraph graph, Builder pipelineBuilder) : base(graph, pipelineBuilder) - { - } - } - #endregion } } diff --git a/src/EcsRunner.cs b/src/EcsRunner.cs index 32a015e..c86b992 100644 --- a/src/EcsRunner.cs +++ b/src/EcsRunner.cs @@ -148,7 +148,7 @@ namespace DCFApixels.DragonECS #region Constructors public RunHelper(EcsRunner runner) : this(runner, #if DEBUG - typeof(TProcess).ToMeta().Name) + typeof(TProcess).GetMeta().Name) #else string.Empty) #endif @@ -298,7 +298,7 @@ namespace DCFApixels.DragonECS #region Constructors public RunHelperWithFinally(EcsRunner runner) : this(runner, #if DEBUG - typeof(TProcess).ToMeta().Name) + typeof(TProcess).GetMeta().Name) #else string.Empty) #endif diff --git a/src/EcsStaticMask.cs b/src/EcsStaticMask.cs index b34bb38..967376d 100644 --- a/src/EcsStaticMask.cs +++ b/src/EcsStaticMask.cs @@ -65,7 +65,7 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _excs; } } - /// Sorted set excluding constraints presented as global type codes. + /// Sorted set any constraints presented as global type codes. public ReadOnlySpan AnyTypeCodes { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -109,9 +109,15 @@ namespace DCFApixels.DragonECS public static Builder Inc(Type type) { return Builder.New().Inc(type); } public static Builder Exc(Type type) { return Builder.New().Exc(type); } public static Builder Any(Type type) { return Builder.New().Any(type); } + public static Builder Inc(params Type[] types) { return Builder.New().Inc(types); } + public static Builder Exc(params Type[] types) { return Builder.New().Exc(types); } + public static Builder Any(params Type[] types) { return Builder.New().Any(types); } public static Builder Inc(EcsTypeCode typeCode) { return Builder.New().Inc(typeCode); } public static Builder Exc(EcsTypeCode typeCode) { return Builder.New().Exc(typeCode); } public static Builder Any(EcsTypeCode typeCode) { return Builder.New().Any(typeCode); } + public static Builder Inc(params EcsTypeCode[] typeCodes) { return Builder.New().Inc(typeCodes); } + public static Builder Exc(params EcsTypeCode[] typeCodes) { return Builder.New().Exc(typeCodes); } + public static Builder Any(params EcsTypeCode[] typeCodes) { return Builder.New().Any(typeCodes); } private static EcsStaticMask CreateMask(Key key) { if (_ids.TryGetValue(key, out EcsStaticMask result) == false) @@ -305,12 +311,24 @@ namespace DCFApixels.DragonECS #endregion #region Inc/Exc/Combine/Except + public Builder Inc() { return this; } + public Builder Exc() { return this; } + public Builder Any() { return this; } public Builder Inc() { return Inc(EcsTypeCodeManager.Get()); } public Builder Exc() { return Exc(EcsTypeCodeManager.Get()); } public Builder Any() { return Any(EcsTypeCodeManager.Get()); } public Builder Inc(Type type) { return Inc(EcsTypeCodeManager.Get(type)); } public Builder Exc(Type type) { return Exc(EcsTypeCodeManager.Get(type)); } public Builder Any(Type type) { return Any(EcsTypeCodeManager.Get(type)); } + public Builder Inc(params Type[] types) { foreach (var type in types) { Inc(type); } return this; } + public Builder Exc(params Type[] types) { foreach (var type in types) { Exc(type); } return this; } + public Builder Any(params Type[] types) { foreach (var type in types) { Any(type); } return this; } + public Builder Inc(ReadOnlySpan types) { foreach (var type in types) { Inc(type); } return this; } + public Builder Exc(ReadOnlySpan types) { foreach (var type in types) { Exc(type); } return this; } + public Builder Any(ReadOnlySpan types) { foreach (var type in types) { Any(type); } return this; } + public Builder Inc(IEnumerable types) { foreach (var type in types) { Inc(type); } return this; } + public Builder Exc(IEnumerable types) { foreach (var type in types) { Exc(type); } return this; } + public Builder Any(IEnumerable types) { foreach (var type in types) { Any(type); } return this; } public Builder Inc(EcsTypeCode typeCode) { if (_version != _builder._version) { Throw.CantReuseBuilder(); } @@ -329,6 +347,15 @@ namespace DCFApixels.DragonECS _builder.Any(typeCode); return this; } + public Builder Inc(params EcsTypeCode[] typeCodes) { foreach (var typeCode in typeCodes) { Inc(typeCode); } return this; } + public Builder Exc(params EcsTypeCode[] typeCodes) { foreach (var typeCode in typeCodes) { Exc(typeCode); } return this; } + public Builder Any(params EcsTypeCode[] typeCodes) { foreach (var typeCode in typeCodes) { Any(typeCode); } return this; } + public Builder Inc(ReadOnlySpan typeCodes) { foreach (var typeCode in typeCodes) { Inc(typeCode); } return this; } + public Builder Exc(ReadOnlySpan typeCodes) { foreach (var typeCode in typeCodes) { Exc(typeCode); } return this; } + public Builder Any(ReadOnlySpan typeCodes) { foreach (var typeCode in typeCodes) { Any(typeCode); } return this; } + public Builder Inc(IEnumerable typeCodes) { foreach (var typeCode in typeCodes) { Inc(typeCode); } return this; } + public Builder Exc(IEnumerable typeCodes) { foreach (var typeCode in typeCodes) { Exc(typeCode); } return this; } + public Builder Any(IEnumerable typeCodes) { foreach (var typeCode in typeCodes) { Any(typeCode); } return this; } public Builder Combine(EcsStaticMask mask) { if (_version != _builder._version) { Throw.CantReuseBuilder(); } @@ -354,6 +381,7 @@ namespace DCFApixels.DragonECS return result; } } + public static implicit operator EcsStaticMask(Builder a) { return a.Build(); } public void Cancel() { if (_version != _builder._version) { Throw.CantReuseBuilder(); } diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index b68ca3d..a12330f 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -71,6 +71,7 @@ namespace DCFApixels.DragonECS private int[] _delEntBuffer = Array.Empty(); private int _delEntBufferCount = 0; private int[] _emptyEntities = Array.Empty(); + private int _emptyEntitiesLength = 0; private int _emptyEntitiesCount = 0; private bool _isEnableAutoReleaseDelEntBuffer = true; @@ -441,20 +442,37 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] private void MoveToEmptyEntities(int entityID) { - _emptyEntities[_emptyEntitiesCount++] = entityID; + _emptyEntities[_emptyEntitiesLength++] = entityID; + _emptyEntitiesCount++; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool RemoveFromEmptyEntities(int entityID) + private void RemoveFromEmptyEntities(int entityID) { - for (int i = _emptyEntitiesCount - 1; i >= 0; i--) + const int THRESHOLD = 16; + _emptyEntitiesCount--; + + if (_emptyEntitiesLength < THRESHOLD) { - if (_emptyEntities[i] == entityID) + for (int i = _emptyEntitiesLength - 1; i >= 0; i--) { - _emptyEntities[i] = _emptyEntities[--_emptyEntitiesCount]; - return true; + if (_emptyEntities[i] == entityID) + { + _emptyEntities[i] = _emptyEntities[--_emptyEntitiesLength]; + } } } - return false; + +#if DRAGONECS_DEEP_DEBUG + if (_emptyEntitiesCount < 0) + { + Throw.DeepDebugException(); + } +#endif + if (_emptyEntitiesCount == 0) + { + _emptyEntitiesCount = 0; + _emptyEntitiesLength = 0; + } } #endregion @@ -698,7 +716,7 @@ namespace DCFApixels.DragonECS } else { - poolIdsPtr = UnmanagedArrayUtility.New(count); + poolIdsPtr = MemoryAllocator.Alloc(count).Ptr; } UnsafeArray ua = UnsafeArray.Manual(poolIdsPtr, count); @@ -711,7 +729,7 @@ namespace DCFApixels.DragonECS if (count >= BUFFER_THRESHOLD) { - UnmanagedArrayUtility.Free(poolIdsPtr); + MemoryAllocator.Free(poolIdsPtr); } @@ -748,7 +766,7 @@ namespace DCFApixels.DragonECS } else { - poolIdsPtr = UnmanagedArrayUtility.New(count); + poolIdsPtr = MemoryAllocator.Alloc(count).Ptr; } GetComponentTypeIDsFor_Internal(fromEntityID, poolIdsPtr, count); @@ -759,7 +777,7 @@ namespace DCFApixels.DragonECS if (count >= BUFFER_THRESHOLD) { - UnmanagedArrayUtility.Free(poolIdsPtr); + MemoryAllocator.Free(poolIdsPtr); } //foreach (var pool in _pools) @@ -890,16 +908,21 @@ namespace DCFApixels.DragonECS { ReleaseDelEntityBuffer(-1); } - public unsafe void ReleaseDelEntityBuffer(int count) + public void ReleaseDelEntityBuffer(int count) { - if (_emptyEntitiesCount <= 0 && _delEntBufferCount <= 0) { return; } + if (_emptyEntitiesLength <= 0 && _delEntBufferCount <= 0) { return; } unchecked { _version++; } - for (int i = 0; i < _emptyEntitiesCount; i++) + for (int i = 0; i < _emptyEntitiesLength; i++) { - TryDelEntity(_emptyEntities[i]); + var entityID = _emptyEntities[i]; + if (IsUsed(entityID) && _entities[entityID].componentsCount == 0) + { + DelEntity(entityID); + } } _emptyEntitiesCount = 0; + _emptyEntitiesLength = 0; if (count < 0) { @@ -1082,7 +1105,7 @@ namespace DCFApixels.DragonECS } else { - poolIdsPtr = UnmanagedArrayUtility.New(count); + poolIdsPtr = MemoryAllocator.Alloc(count).Ptr; } GetComponentTypeIDsFor_Internal(entityID, poolIdsPtr, count); @@ -1105,7 +1128,7 @@ namespace DCFApixels.DragonECS if (count >= BUFFER_THRESHOLD) { - UnmanagedArrayUtility.Free(poolIdsPtr); + MemoryAllocator.Free(poolIdsPtr); } } public ReadOnlySpan GetComponentsFor(int entityID) diff --git a/src/EcsWorld.pools.cs b/src/EcsWorld.pools.cs index 97c6468..8d84e68 100644 --- a/src/EcsWorld.pools.cs +++ b/src/EcsWorld.pools.cs @@ -127,7 +127,6 @@ namespace DCFApixels.DragonECS { return _cmpTypeCode_2_CmpTypeIDs.Contains((int)EcsTypeCodeManager.Get(componentType)); } - //TODO пересмотреть нейминг или функцию public bool IsComponentTypeDeclared(int componentTypeID) { if (componentTypeID >= 0 && componentTypeID < _pools.Length) diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index 91699e1..5e18422 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -5,7 +5,6 @@ using DCFApixels.DragonECS.Core; using DCFApixels.DragonECS.Core.Internal; using System; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; @@ -26,12 +25,15 @@ namespace DCFApixels.DragonECS private static EcsWorld[] _worlds = Array.Empty(); private static readonly IdDispenser _worldIdDispenser = new IdDispenser(4, 0, n => Array.Resize(ref _worlds, n)); - private static StructList _allWorldComponentPools = new StructList(64); private static readonly object _worldLock = new object(); private StructList _worldComponentPools; private int _builtinWorldComponentsCount = 0; + public static int AllWorldsCount + { + get { return _worldIdDispenser.Count; } + } static EcsWorld() { _worlds[NULL_WORLD_ID] = new NullWorld(); @@ -145,7 +147,7 @@ namespace DCFApixels.DragonECS private static short _count; private static short[] _recycledItems = new short[4]; private static short _recycledItemsCount; - private static readonly IEcsWorldComponent _interface = EcsWorldComponentHandler.instance; + private static readonly IEcsWorldComponent _interface = EcsWorldComponent.CustomHandler; private static readonly Abstract _controller = new Abstract(); [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -321,27 +323,5 @@ namespace DCFApixels.DragonECS } } #endregion - - #region Obsolete - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Use EcsWorld.ID")] - public short id - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return ID; } - } - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("The GetPoolInstance(int componentTypeID) method will be removed in future updates, use FindPoolInstance(Type componentType)")] - public IEcsPool GetPoolInstance(int componentTypeID) - { - return FindPoolInstance(componentTypeID); - } - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("The GetPoolInstance(Type componentType) method will be removed in future updates, use FindPoolInstance(Type componentType)")] - public IEcsPool GetPoolInstance(Type componentType) - { - return FindPoolInstance(componentType); - } - #endregion } } \ No newline at end of file diff --git a/src/Executors/EcsWhereExecutor.cs b/src/Executors/EcsWhereExecutor.cs index 9b94458..3b71fcd 100644 --- a/src/Executors/EcsWhereExecutor.cs +++ b/src/Executors/EcsWhereExecutor.cs @@ -3,6 +3,7 @@ #endif using System; using System.Runtime.CompilerServices; +using static DCFApixels.DragonECS.Core.Internal.MemoryAllocator; #if ENABLE_IL2CPP using Unity.IL2CPP.CompilerServices; #endif @@ -13,13 +14,13 @@ namespace DCFApixels.DragonECS.Core.Internal [Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif - internal sealed class EcsWhereExecutor : MaskQueryExecutor + internal sealed unsafe class EcsWhereExecutor : MaskQueryExecutor { private EcsMaskIterator _iterator; - private int[] _filteredAllEntities = new int[32]; + private HMem _filteredAllEntities = Alloc(32); private int _filteredAllEntitiesCount = 0; - private int[] _filteredEntities = null; + private HMem _filteredEntities = default; private int _filteredEntitiesCount = 0; private long _version; @@ -54,6 +55,14 @@ namespace DCFApixels.DragonECS.Core.Internal protected sealed override void OnDestroy() { if (_isDestroyed) { return; } + if (_filteredAllEntities.IsCreated) + { + _filteredAllEntities.DisposeAndReset(); + } + if (_filteredEntities.IsCreated) + { + _filteredEntities.DisposeAndReset(); + } _isDestroyed = true; _versionsChecker.Dispose(); } @@ -67,7 +76,7 @@ namespace DCFApixels.DragonECS.Core.Internal if (_versionsChecker.CheckAndNext() == false) { _version++; - _filteredAllEntitiesCount = _iterator.IterateTo(World.Entities, ref _filteredAllEntities); + _filteredAllEntitiesCount = _iterator.CacheTo(World.Entities, ref _filteredAllEntities); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -77,19 +86,19 @@ namespace DCFApixels.DragonECS.Core.Internal if (span.IsNull) { Throw.ArgumentNull(nameof(span)); } if (span.WorldID != World.ID) { Throw.Quiery_ArgumentDifferentWorldsException(); } #endif - if (_filteredEntities == null) + if (_filteredEntities.IsCreated == false) { - _filteredEntities = new int[32]; + _filteredEntities = Alloc(32); } - _filteredEntitiesCount = _iterator.IterateTo(span, ref _filteredEntities); + _filteredEntitiesCount = _iterator.CacheTo(span, ref _filteredEntities); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public EcsSpan Execute() + public EcsUnsafeSpan Execute() { Execute_Iternal(); #if DEBUG && DRAGONECS_DEEP_DEBUG - var newSpan = new EcsSpan(World.ID, _filteredAllEntities, _filteredAllEntitiesCount); + var result = new EcsUnsafeSpan(World.ID, _filteredAllEntities.Ptr, _filteredAllEntitiesCount); using (EcsGroup group = EcsGroup.New(World)) { foreach (var e in World.Entities) @@ -100,20 +109,20 @@ namespace DCFApixels.DragonECS.Core.Internal } } - if (group.SetEquals(newSpan) == false) + if (group.SetEquals(result.ToSpan()) == false) { int[] array = new int[_filteredAllEntities.Length]; - var count = _iterator.IterateTo(World.Entities, ref array); + var count = _iterator.CacheTo(World.Entities, ref array); - EcsDebug.PrintError(newSpan.ToString() + "\r\n" + group.ToSpan().ToString()); + EcsDebug.PrintError(result.ToString() + "\r\n" + group.ToSpan().ToString()); Throw.DeepDebugException(); } } #endif - return new EcsSpan(World.ID, _filteredAllEntities, _filteredAllEntitiesCount); + return new EcsUnsafeSpan(World.ID, _filteredAllEntities.Ptr, _filteredAllEntitiesCount); ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public EcsSpan ExecuteFor(EcsSpan span) + public EcsUnsafeSpan ExecuteFor(EcsSpan span) { if (span.IsSourceEntities) { @@ -121,8 +130,8 @@ namespace DCFApixels.DragonECS.Core.Internal } ExecuteFor_Iternal(span); #if DEBUG && DRAGONECS_DEEP_DEBUG - var newSpan = new EcsSpan(World.ID, _filteredEntities, _filteredEntitiesCount); - foreach (var e in newSpan) + var result = new EcsUnsafeSpan(World.ID, _filteredEntities.Ptr, _filteredEntitiesCount); + foreach (var e in result) { if (World.IsMatchesMask(Mask, e) == false) { @@ -130,26 +139,26 @@ namespace DCFApixels.DragonECS.Core.Internal } } #endif - return new EcsSpan(World.ID, _filteredEntities, _filteredEntitiesCount); + return new EcsUnsafeSpan(World.ID, _filteredEntities.Ptr, _filteredEntitiesCount); ; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public EcsSpan Execute(Comparison comparison) + public EcsUnsafeSpan Execute(Comparison comparison) { Execute_Iternal(); - ArraySortHalperX.Sort(_filteredAllEntities, comparison, _filteredAllEntitiesCount); - return new EcsSpan(World.ID, _filteredAllEntities, _filteredAllEntitiesCount); + SortHalper.Sort(_filteredAllEntities.AsSpan(_filteredAllEntitiesCount), comparison); + return new EcsUnsafeSpan(World.ID, _filteredAllEntities.Ptr, _filteredAllEntitiesCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public EcsSpan ExecuteFor(EcsSpan span, Comparison comparison) + public EcsUnsafeSpan ExecuteFor(EcsSpan source, Comparison comparison) { - if (span.IsSourceEntities) + if (source.IsSourceEntities) { return Execute(comparison); } - ExecuteFor_Iternal(span); - ArraySortHalperX.Sort(_filteredEntities, comparison, _filteredEntitiesCount); - return new EcsSpan(World.ID, _filteredEntities, _filteredEntitiesCount); + ExecuteFor_Iternal(source); + SortHalper.Sort(_filteredEntities.AsSpan(_filteredEntitiesCount), comparison); + return new EcsUnsafeSpan(World.ID, _filteredEntities.Ptr, _filteredEntitiesCount); } #endregion } diff --git a/src/Executors/EcsWhereToGroupExecutor.cs b/src/Executors/EcsWhereToGroupExecutor.cs index aea581b..6b19643 100644 --- a/src/Executors/EcsWhereToGroupExecutor.cs +++ b/src/Executors/EcsWhereToGroupExecutor.cs @@ -66,7 +66,7 @@ namespace DCFApixels.DragonECS.Core.Internal if (_versionsChecker.CheckAndNext() == false) { _version++; - _iterator.IterateTo(World.Entities, _filteredAllGroup); + _iterator.CacheTo(World.Entities, _filteredAllGroup); #if DEBUG && DRAGONECS_DEEP_DEBUG if (_filteredGroup == null) { @@ -98,7 +98,7 @@ namespace DCFApixels.DragonECS.Core.Internal { _filteredGroup = EcsGroup.New(World); } - _iterator.IterateTo(span, _filteredGroup); + _iterator.CacheTo(span, _filteredGroup); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Executors/Queries.cs b/src/Executors/Queries.cs index 30c9644..f3c8318 100644 --- a/src/Executors/Queries.cs +++ b/src/Executors/Queries.cs @@ -84,6 +84,76 @@ namespace DCFApixels.DragonECS } #endregion + #region WhereUnsafe + public static EcsUnsafeSpan WhereUnsafe(this TCollection entities, out TAspect aspect) + where TAspect : new() + where TCollection : IEntityStorage + { + return entities.ToSpan().WhereUnsafe(out aspect); + } + public static EcsUnsafeSpan WhereUnsafe(this EcsReadonlyGroup group, out TAspect aspect) + where TAspect : new() + { + return group.ToSpan().WhereUnsafe(out aspect); + } + public static EcsUnsafeSpan WhereUnsafe(this EcsSpan span, out TAspect aspect) + where TAspect : new() + { + span.World.GetQueryCache(out EcsWhereExecutor executor, out aspect); + return executor.ExecuteFor(span); + } + + public static EcsUnsafeSpan WhereUnsafe(this TCollection entities, IComponentMask mask) + where TCollection : IEntityStorage + { + return entities.ToSpan().WhereUnsafe(mask); + } + public static EcsUnsafeSpan WhereUnsafe(this EcsReadonlyGroup group, IComponentMask mask) + { + return group.ToSpan().WhereUnsafe(mask); + } + public static EcsUnsafeSpan WhereUnsafe(this EcsSpan span, IComponentMask mask) + { + var executor = span.World.GetExecutorForMask(mask); + return executor.ExecuteFor(span); + } + #endregion + + #region WhereUnsafe with sort + public static EcsUnsafeSpan WhereUnsafe(this TCollection entities, out TAspect aspect, Comparison comparison) + where TAspect : new() + where TCollection : IEntityStorage + { + return entities.ToSpan().WhereUnsafe(out aspect, comparison); + } + public static EcsUnsafeSpan WhereUnsafe(this EcsReadonlyGroup group, out TAspect aspect, Comparison comparison) + where TAspect : new() + { + return group.ToSpan().WhereUnsafe(out aspect, comparison); + } + public static EcsUnsafeSpan WhereUnsafe(this EcsSpan span, out TAspect aspect, Comparison comparison) + where TAspect : new() + { + span.World.GetQueryCache(out EcsWhereExecutor executor, out aspect); + return executor.ExecuteFor(span, comparison); + } + + public static EcsUnsafeSpan WhereUnsafe(this TCollection entities, IComponentMask mask, Comparison comparison) + where TCollection : IEntityStorage + { + return entities.ToSpan().WhereUnsafe(mask, comparison); + } + public static EcsUnsafeSpan WhereUnsafe(this EcsReadonlyGroup group, IComponentMask mask, Comparison comparison) + { + return group.ToSpan().WhereUnsafe(mask, comparison); + } + public static EcsUnsafeSpan WhereUnsafe(this EcsSpan span, IComponentMask mask, Comparison comparison) + { + var executor = span.World.GetExecutorForMask(mask); + return executor.ExecuteFor(span); + } + #endregion + #region WhereToGroup public static EcsReadonlyGroup WhereToGroup(this TCollection entities, out TAspect aspect) where TAspect : new() diff --git a/src/Injections/Injector.cs b/src/Injections/Injector.cs index c68c965..1950766 100644 --- a/src/Injections/Injector.cs +++ b/src/Injections/Injector.cs @@ -126,7 +126,7 @@ namespace DCFApixels.DragonECS { return (T)Extract_Internal(typeof(T)); } - private object Extract_Internal(Type type)//TODO проверить + private object Extract_Internal(Type type) { if (_nodes.TryGetValue(type, out InjectionNodeBase node)) { @@ -192,7 +192,7 @@ namespace DCFApixels.DragonECS FindMonoWorld(obj); _injections.Add(new Injection(obj)); } - public void Extract(ref T obj) // TODO проверить + public void Extract(ref T obj) { Type type = typeof(T); for (int i = _injections.Count - 1; i >= 0; i--) @@ -272,7 +272,7 @@ namespace DCFApixels.DragonECS } public void InjectTo(Injector injector, EcsPipeline pipeline) { - var monoWorldProcess = pipeline.GetProcess(); // TODO Проверить IMonoWorldInject + var monoWorldProcess = pipeline.GetProcess(); foreach (var monoWorldSystem in monoWorldProcess) { monoWorldSystem.World = _monoWorld; diff --git a/src/Internal/Allocators/AllocatorUtility.cs b/src/Internal/Allocators/AllocatorUtility.cs index 27f608b..cfc092f 100644 --- a/src/Internal/Allocators/AllocatorUtility.cs +++ b/src/Internal/Allocators/AllocatorUtility.cs @@ -1,25 +1,89 @@ using System; - +using System.Runtime.CompilerServices; +using static DCFApixels.DragonECS.Core.Internal.MemoryAllocator; namespace DCFApixels.DragonECS.Core.Internal { - internal static class AllocatorUtility + internal static unsafe class AllocatorUtility { - public static unsafe void ClearAllocatedMemory(IntPtr ptr, int startByte, int lengthInBytes) + public static void ClearAllocatedMemory(IntPtr ptr, int startByte, int lengthInBytes) { ClearAllocatedMemory((byte*)ptr, startByte, lengthInBytes); } - public static unsafe void ClearAllocatedMemory(byte* ptr, int startByte, int lengthInBytes) + public static void ClearAllocatedMemory(byte* ptr, int startByte, int lengthInBytes) { -#if ENABLE_DUMMY_SPAN - lengthInBytes += startByte; - for (int i = startByte; i < lengthInBytes; i++) - { - ptr[i] = 0; - } -#else Span memorySpan = new Span(ptr + startByte, lengthInBytes); memorySpan.Clear(); -#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CacheTo(this EcsMaskIterator it, EcsSpan source, ref HMem array) + { + switch (it.MaskFlags) + { + case EcsMaskFlags.Empty: + { + if(array.Length < source.Count) + { + array = Realloc(array, source.Count); + } + source.AsSystemSpan().CopyTo(array.AsSpan()); + return source.Count; + } + case EcsMaskFlags.Inc: + { + return it.IterateOnlyInc(source).CacheTo(ref array); + } + case EcsMaskFlags.Exc: + case EcsMaskFlags.Any: + case EcsMaskFlags.IncExc: + case EcsMaskFlags.IncAny: + case EcsMaskFlags.ExcAny: + case EcsMaskFlags.IncExcAny: + { + return it.Iterate(source).CacheTo(ref array); + } + case EcsMaskFlags.Broken: + { + return 0; + } + default: + { + Throw.UndefinedException(); + return 0; + } + } + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CacheTo(this EcsMaskIterator.OnlyIncEnumerable e, ref HMem array) + { + int count = 0; + var enumerator = e.GetEnumerator(); + while (enumerator.MoveNext()) + { + if (array.Length <= count) + { + array = Realloc(array, array.Length << 1); + } + array.Ptr[count++] = enumerator.Current; + } + return count; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CacheTo(this EcsMaskIterator.Enumerable e, ref HMem array) + { + int count = 0; + var enumerator = e.GetEnumerator(); + while (enumerator.MoveNext()) + { + if (array.Length <= count) + { + array = Realloc(array, array.Length << 1); + } + array.Ptr[count++] = enumerator.Current; + } + return count; } } } diff --git a/src/Internal/Allocators/MemoryAllocator.cs b/src/Internal/Allocators/MemoryAllocator.cs index c0f2afc..4f71627 100644 --- a/src/Internal/Allocators/MemoryAllocator.cs +++ b/src/Internal/Allocators/MemoryAllocator.cs @@ -3,6 +3,7 @@ #endif using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace DCFApixels.DragonECS.Core.Internal @@ -27,30 +28,30 @@ namespace DCFApixels.DragonECS.Core.Internal } #region AllocAndInit - public static Handler AllocAndInit(int count) where T : unmanaged + public static HMem AllocAndInit(int count) where T : unmanaged { - return AllocAndInit_Internal(Marshal.SizeOf() * count, typeof(T)); + return new HMem(AllocAndInit_Internal(Marshal.SizeOf() * count, typeof(T)), count); } - public static Handler AllocAndInit(int byteLength) + public static HMem AllocAndInit(int byteLength) { - return AllocAndInit_Internal(byteLength, null); + return new HMem(AllocAndInit_Internal(byteLength, null), byteLength); } public static Handler AllocAndInit_Internal(int byteLength, Type type) { Handler handler = Alloc_Internal(byteLength, type); - AllocatorUtility.ClearAllocatedMemory(handler.Ptr, 0, byteLength); + AllocatorUtility.ClearAllocatedMemory(handler.RawPtr, 0, byteLength); return handler; } #endregion #region Alloc - public static Handler Alloc(int count) where T : unmanaged + public static HMem Alloc(int count) where T : unmanaged { - return Alloc_Internal(Marshal.SizeOf() * count, typeof(T)); + return new HMem(Alloc_Internal(Marshal.SizeOf() * count, typeof(T)), count); } - public static Handler Alloc(int byteLength) + public static HMem Alloc(int byteLength) { - return Alloc_Internal(byteLength, null); + return new HMem(Alloc_Internal(byteLength, null), byteLength); ; } public static Handler Alloc_Internal(int byteLength, Type type) { @@ -85,69 +86,78 @@ namespace DCFApixels.DragonECS.Core.Internal #endregion #region ReallocAndInit - public static Handler ReallocAndInit(void* target, int oldCount, int newCount) where T : unmanaged + public static HMem ReallocAndInit(void* target, int oldCount, int newCount) where T : unmanaged { return ReallocAndInit(Handler.FromDataPtr(target), oldCount, newCount); } - public static Handler ReallocAndInit(void* target, int oldByteLength, int newByteLength) + public static HMem ReallocAndInit(void* target, int oldByteLength, int newByteLength) { return ReallocAndInit(Handler.FromDataPtr(target), oldByteLength, newByteLength); } - public static Handler ReallocAndInit(Handler target, int oldCount, int newCount) where T : unmanaged + public static HMem ReallocAndInit(HMem target, int newCount) where T : unmanaged { var size = Marshal.SizeOf(); - return ReallocAndInit_Internal(target, size * oldCount, size * newCount, typeof(T)); + return new HMem(ReallocAndInit_Internal(target, size * target.Length, size * newCount, typeof(T)), newCount); } - public static Handler ReallocAndInit(Handler target, int oldByteLength, int newByteLength) + public static HMem ReallocAndInit(Handler target, int oldCount, int newCount) where T : unmanaged { - return ReallocAndInit_Internal(target, oldByteLength, newByteLength, null); + var size = Marshal.SizeOf(); + return new HMem(ReallocAndInit_Internal(target, size * oldCount, size * newCount, typeof(T)), newCount); + } + public static HMem ReallocAndInit(Handler target, int oldByteLength, int newByteLength) + { + return new HMem(ReallocAndInit_Internal(target, oldByteLength, newByteLength, null), newByteLength); } private static Handler ReallocAndInit_Internal(Handler target, int oldByteLength, int newByteLength, Type newType) { Handler handler = Realloc_Internal(target, newByteLength, newType); - AllocatorUtility.ClearAllocatedMemory(handler.Ptr, oldByteLength, newByteLength - oldByteLength); + AllocatorUtility.ClearAllocatedMemory(handler.RawPtr, oldByteLength, newByteLength - oldByteLength); return handler; } #endregion #region Realloc - public static Handler ReallocOrAlloc(void* target, int newCount) where T : unmanaged - { - if (target == null) { return Alloc(newCount); } - return Realloc(Handler.FromDataPtr(target), Marshal.SizeOf() * newCount); - } - public static Handler ReallocOrAlloc(void* target, int newByteLength) - { - if (target == null) { return Alloc(newByteLength); } - return Realloc(Handler.FromDataPtr(target), newByteLength); - } - public static Handler ReallocOrAlloc(Handler target, int newCount) where T : unmanaged - { - if (target.IsEmpty) { return Alloc(newCount); } - return Realloc_Internal(target, Marshal.SizeOf() * newCount, typeof(T)); - } - public static Handler Realloc(void* target, int newCount) where T : unmanaged + public static HMem Realloc(void* target, int newCount) where T : unmanaged { return Realloc(Handler.FromDataPtr(target), Marshal.SizeOf() * newCount); } - public static Handler Realloc(void* target, int newByteLength) + public static HMem Realloc(void* target, int newByteLength) { - return Realloc(Handler.FromDataPtr(target), newByteLength); + return new HMem(Realloc(Handler.FromDataPtr(target), newByteLength), newByteLength); } - public static Handler Realloc(Handler target, int newCount) where T : unmanaged + public static HMem Realloc(Handler target, int newCount) where T : unmanaged { - return Realloc_Internal(target, Marshal.SizeOf() * newCount, typeof(T)); + return new HMem(Realloc_Internal(target, Marshal.SizeOf() * newCount, typeof(T)), newCount); } - public static Handler Realloc(Handler target, int newByteLength) + public static HMem Realloc(Handler target, int newByteLength) { - return Realloc_Internal(target, newByteLength, null); + return new HMem(Realloc_Internal(target, newByteLength, null), newByteLength); } private static Handler Realloc_Internal(Handler target, int newByteLength, Type newType) { newByteLength = newByteLength == 0 ? 1 : newByteLength; - Meta* newHandledPtr = (Meta*)Marshal.ReAllocHGlobal((IntPtr)target.GetHandledPtr(), (IntPtr)newByteLength + sizeof(Meta)); + if (target.IsCreated == false) + { + return Alloc_Internal(newByteLength, newType); + } +#if DEBUG + int id = 0; + lock (_idDispenser) + { + if (_debugInfos.Length <= _idDispenser.Count) + { + Array.Resize(ref _debugInfos, ArrayUtility.NextPow2(_idDispenser.Count)); + } + id = _idDispenser.UseFree(); + } +#endif + Meta* newHandledPtr = (Meta*)Marshal.ReAllocHGlobal( + (IntPtr)target.GetHandledPtr(), + (IntPtr)newByteLength + sizeof(Meta)); Handler handler = Handler.FromHandledPtr(newHandledPtr); #if DEBUG + newHandledPtr->ID = id; + newHandledPtr->ByteLength = newByteLength; #if DRAGONECS_DEEP_DEBUG _debugInfos[newHandledPtr->ID].stackTrace = new System.Diagnostics.StackTrace(); #endif @@ -158,11 +168,44 @@ namespace DCFApixels.DragonECS.Core.Internal } #endregion + #region Clone + public static HMem From(HMem source) + where T : unmanaged + { + var result = Alloc(source.Length); + source.AsSpan().CopyTo(result.AsSpan()); + return result; + } + public static HMem From(T* ptr, int length) + where T : unmanaged + { + return From(new ReadOnlySpan(ptr, length)); + } + public static HMem From(T[] source) + where T : unmanaged + { + return From(new ReadOnlySpan(source)); + } + public static HMem From(ReadOnlySpan source) + where T : unmanaged + { + var result = Alloc(source.Length); + source.CopyTo(result.AsSpan()); + return result; + } + #endregion + #region Free public static void Free(Handler target) { Free_Internal(target.GetHandledPtr()); } + public static void FreeAndClear(ref HMem target) + where T : unmanaged + { + Free_Internal(target.Handler.GetHandledPtr()); + target = default; + } public static void FreeAndClear(ref Handler target) { Free_Internal(target.GetHandledPtr()); @@ -175,6 +218,10 @@ namespace DCFApixels.DragonECS.Core.Internal private static void Free_Internal(Meta* handledPtr) { #if DEBUG + if (handledPtr == null) + { + throw new ArgumentNullException(); + } lock (_idDispenser) { _idDispenser.Release(handledPtr->ID); @@ -226,11 +273,96 @@ namespace DCFApixels.DragonECS.Core.Internal } #endregion + public readonly struct HMem : IDisposable, IEquatable> + where T : unmanaged + { + public readonly T* Ptr; + public readonly int Length; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal HMem(Handler handler, int length) + { + Ptr = handler.As(); + Length = length; + } + + public bool IsCreated + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return Ptr != null; } + } + public IntPtr RawPtr + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return new IntPtr(Ptr); } + } + public Handler Handler + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return Handler.FromDataPtr(Ptr); } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HMem As() where U : unmanaged + { + if (IsCreated) + { + return default; + } + + long totalBytes = (long)Length * sizeof(T); + long newLengthLong = totalBytes / sizeof(U); +#if DEBUG + if (totalBytes % sizeof(U) != 0) + { + throw new InvalidOperationException($"Cannot cast Memory<{typeof(T).Name}> to Memory<{typeof(U).Name}> because the size of the underlying memory ({totalBytes} bytes) is not a multiple of the size of {typeof(U).Name} ({sizeof(U)} bytes)."); + } + if (newLengthLong > int.MaxValue) + { + throw new InvalidOperationException($"Resulting length ({newLengthLong}) exceeds int.MaxValue."); + } +#endif + + return new HMem(Handler, (int)newLengthLong); + } + public void Dispose() + { + Handler.Dispose(); + } + +#if DEBUG + public override string ToString() { return Handler.DebuggerDisplay(); } +#endif + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() { return RawPtr.GetHashCode(); } + public override bool Equals(object obj) { return obj is Handler h && h == this; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(HMem other) { return other.Ptr == Ptr; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(HMem a, HMem b) { return a.Ptr == b.Ptr; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(HMem a, HMem b) { return a.Ptr != b.Ptr; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() { return new Span(Ptr, Length); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int length) + { +#if DEBUG + if (length > Length) { Throw.UndefinedException(); } +#endif + return new Span(Ptr, length); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Handler(HMem memory) { return memory.Handler; } + } + #if DEBUG [System.Diagnostics.DebuggerDisplay("{DebuggerDisplay()}")] [System.Diagnostics.DebuggerTypeProxy(typeof(DebuggerProxy))] #endif - public readonly struct Handler : IDisposable + public readonly struct Handler : IDisposable, IEquatable { public static readonly Handler Empty = new Handler(); internal readonly Meta* Data; // Data[-1] is meta; @@ -255,16 +387,39 @@ namespace DCFApixels.DragonECS.Core.Internal #endif } - public bool IsEmpty { get { return Data == null; } } - public IntPtr Ptr { get { return (IntPtr)Data; } } - public T* As() where T : unmanaged { return (T*)Ptr; } + public bool IsCreated + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return Data != null; } + } + public IntPtr RawPtr + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return (IntPtr)Data; } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T* As() where T : unmanaged { return (T*)RawPtr; } - void IDisposable.Dispose() { Free((void*)Ptr); } + public void Dispose() { Free((void*)RawPtr); } + +#if DEBUG + public override string ToString() { return DebuggerDisplay(); } +#endif + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() { return RawPtr.GetHashCode(); } + public override bool Equals(object obj) { return obj is Handler h && h == this; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Handler other) { return other.Data == Data; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Handler a, Handler b) { return a.Data == b.Data; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Handler a, Handler b) { return a.Data != b.Data; } #region Debugger #if DEBUG #pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. - internal unsafe string DebuggerDisplay() + internal string DebuggerDisplay() { if (Data == null) { @@ -298,6 +453,7 @@ namespace DCFApixels.DragonECS.Core.Internal } return array; } + [StructLayout(LayoutKind.Explicit)] private unsafe struct Union { @@ -319,13 +475,13 @@ namespace DCFApixels.DragonECS.Core.Internal public HandlerDebugInfo[] OtherHandlersInfo; - public unsafe DebuggerProxy(Handler handler) + public DebuggerProxy(Handler handler) { - IsAlive = handler.Ptr.ToPointer() != null; + IsAlive = handler.RawPtr.ToPointer() != null; if (IsAlive == false) { return; } Meta = handler.GetHandledPtr()[0]; - _data = (byte*)handler.Ptr; + _data = (byte*)handler.RawPtr; DebugInfo = _debugInfos[Meta.ID]; if (DebugInfo.type == null) @@ -397,9 +553,15 @@ namespace DCFApixels.DragonECS.Core.Internal internal static class MemoryAllocatorHandlerExtensions { - public static void Dispose(this ref MemoryAllocator.Handler self) + public static void DisposeAndReset(this ref MemoryAllocator.Handler self) { MemoryAllocator.FreeAndClear(ref self); } + public static void DisposeAndReset(this ref MemoryAllocator.HMem self) + where T : unmanaged + { + self.Dispose(); + self = default; + } } } \ No newline at end of file diff --git a/src/Internal/Allocators/TempBuffer.cs b/src/Internal/Allocators/TempBuffer.cs index f777174..f86ea56 100644 --- a/src/Internal/Allocators/TempBuffer.cs +++ b/src/Internal/Allocators/TempBuffer.cs @@ -54,7 +54,7 @@ namespace DCFApixels.DragonECS.Core.Internal { MemoryAllocator.Free(_ptr); } - _ptr = MemoryAllocator.Alloc(byteSize).As(); + _ptr = MemoryAllocator.Alloc(byteSize).Ptr; _byteSize = byteSize; } return (T*)_ptr; diff --git a/src/Internal/ArraySortHalperX.cs b/src/Internal/ArraySortHalperX.cs deleted file mode 100644 index 293007d..0000000 --- a/src/Internal/ArraySortHalperX.cs +++ /dev/null @@ -1,272 +0,0 @@ -#if DISABLE_DEBUG -#undef DEBUG -#endif -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -#if ENABLE_IL2CPP -using Unity.IL2CPP.CompilerServices; -#endif - -namespace DCFApixels.DragonECS.Core.Internal -{ - internal interface IStructComparer : IComparer - { - // a > b = return > 0 - // int Compare(T a, T b); - } - -#if ENABLE_IL2CPP - [Il2CppSetOption(Option.NullChecks, false)] - [Il2CppSetOption(Option.ArrayBoundsChecks, false)] -#endif - internal static class ArraySortHalperX - { - private const int IntrosortSizeThreshold = 16; - - #region IStructComparer - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SwapIfGreater(T[] items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer - { - if (comparer.Compare(items[i], items[j]) > 0) - { - T key = items[i]; - items[i] = items[j]; - items[j] = key; - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InsertionSort(T[] items, ref TComparer comparer) where TComparer : IStructComparer - { - for (int i = 0; i < items.Length - 1; i++) - { - T t = items[i + 1]; - - int j = i; - while (j >= 0 && comparer.Compare(t, items[j]) < 0) - { - items[j + 1] = items[j]; - j--; - } - - items[j + 1] = t; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Sort(T[] items, ref TComparer comparer) where TComparer : IStructComparer - { - int length = items.Length; - if (length == 1) - { - return; - } - - if (length <= IntrosortSizeThreshold) - { - - if (length == 2) - { - SwapIfGreater(items, ref comparer, 0, 1); - return; - } - - if (length == 3) - { - SwapIfGreater(items, ref comparer, 0, 1); - SwapIfGreater(items, ref comparer, 0, 2); - SwapIfGreater(items, ref comparer, 1, 2); - return; - } - - InsertionSort(items, ref comparer); - return; - } - - IStructComparer packed = comparer; - Array.Sort(items, 0, items.Length, packed); - comparer = (TComparer)packed; - } - #endregion - - #region Comparison - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SwapIfGreater(T[] items, Comparison comparison, int i, int j) - { - if (comparison(items[i], items[j]) > 0) - { - T key = items[i]; - items[i] = items[j]; - items[j] = key; - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InsertionSort(T[] items, int length, Comparison comparison) - { - for (int i = 0; i < length - 1; i++) - { - T t = items[i + 1]; - - int j = i; - while (j >= 0 && comparison(t, items[j]) < 0) - { - items[j + 1] = items[j]; - j--; - } - - items[j + 1] = t; - } - } - -#if ENABLE_IL2CPP - [Il2CppSetOption(Option.NullChecks, false)] - [Il2CppSetOption(Option.ArrayBoundsChecks, false)] -#endif - private class ComparisonHach : IComparer - { - public static readonly ComparisonHach Instance = new ComparisonHach(); - public Comparison comparison; - private ComparisonHach() { } - public int Compare(T x, T y) { return comparison(x, y); } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Sort(T[] items, Comparison comparison) - { - Sort(items, comparison, items.Length); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Sort(T[] items, Comparison comparison, int length) - { - if (length <= IntrosortSizeThreshold) - { - if (length == 1) - { - return; - } - if (length == 2) - { - SwapIfGreater(items, comparison, 0, 1); - return; - } - if (length == 3) - { - SwapIfGreater(items, comparison, 0, 1); - SwapIfGreater(items, comparison, 0, 2); - SwapIfGreater(items, comparison, 1, 2); - return; - } - InsertionSort(items, length, comparison); - return; - } - ComparisonHach.Instance.comparison = comparison; - Array.Sort(items, 0, length, ComparisonHach.Instance); - } - #endregion - } - -#if ENABLE_IL2CPP - [Il2CppSetOption(Option.NullChecks, false)] - [Il2CppSetOption(Option.ArrayBoundsChecks, false)] -#endif - internal static unsafe class UnsafeArraySortHalperX where T : unmanaged - { - private const int IntrosortSizeThreshold = 16; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SwapIfGreater(T* items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer - { - if (comparer.Compare(items[i], items[j]) > 0) - { - T key = items[i]; - items[i] = items[j]; - items[j] = key; - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InsertionSort_Unchecked(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer - { - for (int i = 0; i < length - 1; i++) - { - T t = items[i + 1]; - - int j = i; - while (j >= 0 && comparer.Compare(t, items[j]) < 0) - { - items[j + 1] = items[j]; - j--; - } - - items[j + 1] = t; - } - } - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static void OptimizedBubbleSort_Unchecked(T* items, int length, ref TComparer comparer) where TComparer : IComparerX - //{ - // for (int i = 0, n = length - 1; i < n; i++) - // { - // bool noSwaped = true; - // for (int j = 0; j < n - i;) - // { - // ref T j0 = ref items[j++]; - // if(comparer.Compare(j0, items[j]) < 0) - // { - // T tmp = items[j]; - // items[j] = j0; - // j0 = tmp; - // noSwaped = false; - // } - // } - // if (noSwaped) - // break; - // } - //} - public static void InsertionSort(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer - { - if (length == 1) - { - return; - } - - if (length == 2) - { - SwapIfGreater(items, ref comparer, 0, 1); - return; - } - - if (length == 3) - { - SwapIfGreater(items, ref comparer, 0, 1); - SwapIfGreater(items, ref comparer, 0, 2); - SwapIfGreater(items, ref comparer, 1, 2); - return; - } - - InsertionSort_Unchecked(items, length, ref comparer); - } - //public static void OptimizedBubbleSort(T* items, int length, ref TComparer comparer) where TComparer : IComparerX - //{ - // if (length == 1) - // { - // return; - // } - // - // if (length == 2) - // { - // SwapIfGreater(items, ref comparer, 0, 1); - // return; - // } - // - // if (length == 3) - // { - // SwapIfGreater(items, ref comparer, 0, 1); - // SwapIfGreater(items, ref comparer, 0, 2); - // SwapIfGreater(items, ref comparer, 1, 2); - // return; - // } - // - // OptimizedBubbleSort_Unchecked(items, length, ref comparer); - //} - } -} - - diff --git a/src/Internal/ArrayUtility.cs b/src/Internal/ArrayUtility.cs index 1dbbb2d..536feb8 100644 --- a/src/Internal/ArrayUtility.cs +++ b/src/Internal/ArrayUtility.cs @@ -6,7 +6,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; namespace DCFApixels.DragonECS.Core.Internal { @@ -270,114 +269,6 @@ namespace DCFApixels.DragonECS.Core.Internal } } - internal static unsafe class UnmanagedArrayUtility - { - private static class MetaCache - { - public readonly static int Size; - static MetaCache() - { - T def = default; - Size = Marshal.SizeOf(def); - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T* New(int capacity) where T : unmanaged - { - //Console.WriteLine($"{typeof(T).Name} - {Marshal.SizeOf()} - {capacity} - {Marshal.SizeOf() * capacity}"); - //return (T*)Marshal.AllocHGlobal(Marshal.SizeOf() * capacity).ToPointer(); - return MemoryAllocator.Alloc(capacity).As(); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void New(out T* ptr, int capacity) where T : unmanaged - { - //ptr = (T*)Marshal.AllocHGlobal(Marshal.SizeOf() * capacity).ToPointer(); - ptr = MemoryAllocator.Alloc(capacity).As(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T* NewAndInit(int capacity) where T : unmanaged - { - //int newSize = MetaCache.Size * capacity; - //byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer(); - // - //for (int i = 0; i < newSize; i++) - //{ - // *(newPointer + i) = 0; - //} - // - //return (T*)newPointer; - return MemoryAllocator.AllocAndInit(capacity).As(); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void NewAndInit(out T* ptr, int capacity) where T : unmanaged - { - //int newSize = MetaCache.Size * capacity; - //byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer(); - // - //for (int i = 0; i < newSize; i++) - //{ - // *(newPointer + i) = 0; - //} - // - //ptr = (T*)newPointer; - ptr = MemoryAllocator.AllocAndInit(capacity).As(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Free(void* pointer) - { - //Marshal.FreeHGlobal(new IntPtr(pointer)); - MemoryAllocator.Free(dataPtr: pointer); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Free(ref T* pointer, ref int length) where T : unmanaged - { - //Marshal.FreeHGlobal(new IntPtr(pointer)); - MemoryAllocator.Free(dataPtr: pointer); - pointer = null; - length = 0; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T* Clone(T* sourcePtr, int length) where T : unmanaged - { - T* clone = New(length); - for (int i = 0; i < length; i++) - { - clone[i] = sourcePtr[i]; - } - return clone; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T* Resize(void* oldPointer, int newCount) where T : unmanaged - { - //return (T*)(Marshal.ReAllocHGlobal( - // new IntPtr(oldPointer), - // new IntPtr(MetaCache.Size * newCount))).ToPointer(); - return MemoryAllocator.Realloc(MemoryAllocator.Handler.FromDataPtr(oldPointer), newCount).As(); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T* ResizeAndInit(void* oldPointer, int oldSize, int newSize) where T : unmanaged - { - //int sizeT = MetaCache.Size; - //T* result = (T*)Marshal.ReAllocHGlobal( - // new IntPtr(oldPointer), - // new IntPtr(sizeT * newSize)).ToPointer(); - //Init((byte*)result, sizeT * oldSize, sizeT * newSize); - //return result; - return MemoryAllocator.ReallocAndInit(MemoryAllocator.Handler.FromDataPtr(oldPointer), oldSize, newSize).As(); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Init(byte* pointer, int startByteIndex, int endByteIndex) - { - for (int i = startByteIndex; i < endByteIndex; i++) - { - *(pointer + i) = 0; - } - } - } public static class CollectionUtility { diff --git a/src/Internal/SortHalper.cs b/src/Internal/SortHalper.cs new file mode 100644 index 0000000..31e4c49 --- /dev/null +++ b/src/Internal/SortHalper.cs @@ -0,0 +1,631 @@ +#if DISABLE_DEBUG +#undef DEBUG +#endif +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +#if ENABLE_IL2CPP +using Unity.IL2CPP.CompilerServices; +#endif + +namespace DCFApixels.DragonECS.Core.Internal +{ +#if ENABLE_IL2CPP + [Il2CppSetOption(Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +#endif + internal static unsafe class SortHalper + { + #region Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Sort(Span span) + { + var c = new ComparerWrapper(Comparer.Default); + SortHalper>.Sort(span, ref c); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Sort(Span span, bool _ = false) + where T : IComparable + { + var c = new ComparableWrapper(); + SortHalper>.Sort(span, ref c); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Sort(Span span, Comparer comparer) + { + var c = new ComparerWrapper(comparer); + SortHalper>.Sort(span, ref c); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Sort(Span span, Comparison comparison) + { + var c = new ComparisonWrapper(comparison); + SortHalper>.Sort(span, ref c); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Sort(Span span, ref TComparer comparer) + where TComparer : struct, IComparer + { + SortHalper.Sort(span, ref comparer); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Sort(Span span, TComparer comparer) + where TComparer : struct, IComparer + { + SortHalper.Sort(span, ref comparer); + } + #endregion + + #region Utils + // Таблица для De Bruijn-умножения (позиция старшего бита для чисел 0..31) + private const int Log2DeBruijn32_Length = 32; + private static readonly uint* Log2DeBruijn32 = MemoryAllocator.From(new uint[Log2DeBruijn32_Length] + { + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 + }).Ptr; + + /// 32-битный логарифм по основанию 2 (округление вниз). Для value = 0 возвращает 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Log2(uint value) + { + // Для нуля сразу возвращаем 0 (по договорённости, чтобы избежать исключения) + if (value == 0) return 0; + + // Заполняем все биты справа от старшего единицей: превращаем число в 2^n - 1 + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + + // Умножение на константу De Bruijn и сдвиг для получения индекса в таблице + return (int)Log2DeBruijn32[(value * 0x07C4ACDDu) >> 27]; + } + + /// 64-битный логарифм по основанию 2 (округление вниз). Для value = 0 возвращает 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Log2(ulong value) + { + if (value == 0) { return 0; } + + uint high = (uint)(value >> 32); + if (high == 0) + { + return Log2((uint)value); + } + else + { + return 32 + Log2(high); + } + } + #endregion + } + // a > b = return > 0 + // int Compare(T a, T b); + + //IComparer comparer + //if (comparer == null) + //{ + // comparer = Comparer.Default; + //} +#if ENABLE_IL2CPP + [Il2CppSetOption(Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +#endif + internal static class SortHalper + where TComparer : struct, IComparer + { + private const int IntrosortSizeThreshold = 16; + + #region Public + public static void Sort(Span keys, ref TComparer comparer) + { + // Add a try block here to detect IComparers (or their + // underlying IComparables, etc) that are bogus. + IntrospectiveSort(keys, ref comparer); + } + public static int BinarySearch(T[] array, int index, int length, T value, ref TComparer comparer) + { + Debug.Assert(array != null, "Check the arguments in the caller!"); + Debug.Assert(index >= 0 && length >= 0 && (array.Length - index >= length), "Check the arguments in the caller!"); + + int lo = index; + int hi = index + length - 1; + while (lo <= hi) + { + int i = lo + ((hi - lo) >> 1); + int order = comparer.Compare(array[i], value); + + if (order == 0) return i; + if (order < 0) + { + lo = i + 1; + } + else + { + hi = i - 1; + } + } + + return ~lo; + } + #endregion + + #region Internal + internal static void IntrospectiveSort(Span keys, ref TComparer comparer) + { + //Debug.Assert(comparer != null); + if (keys.Length > 1) + { + IntroSort(keys, 2 * (SortHalper.Log2((uint)keys.Length) + 1), ref comparer); + } + } + + // IntroSort is recursive; block it from being inlined into itself as + // this is currenly not profitable. + [MethodImpl(MethodImplOptions.NoInlining)] + private static void IntroSort(Span keys, int depthLimit, ref TComparer comparer) + { + Debug.Assert(!keys.IsEmpty); + Debug.Assert(depthLimit >= 0); + //Debug.Assert(comparer != null); + + int partitionSize = keys.Length; + while (partitionSize > 1) + { + if (partitionSize <= IntrosortSizeThreshold) + { + + if (partitionSize == 2) + { + SwapIfGreater(keys, ref comparer, 0, 1); + return; + } + + if (partitionSize == 3) + { + SwapIfGreater(keys, ref comparer, 0, 1); + SwapIfGreater(keys, ref comparer, 0, 2); + SwapIfGreater(keys, ref comparer, 1, 2); + return; + } + + InsertionSort(keys.Slice(0, partitionSize), ref comparer); + return; + } + + if (depthLimit == 0) + { + HeapSort(keys.Slice(0, partitionSize), ref comparer); + return; + } + depthLimit--; + + int p = PickPivotAndPartition(keys.Slice(0, partitionSize), ref comparer); + + // Note we've already partitioned around the pivot and do not have to move the pivot again. + IntroSort(keys.Slice(p + 1, partitionSize - (p + 1)), depthLimit, ref comparer); + partitionSize = p; + } + } + + private static int PickPivotAndPartition(Span keys, ref TComparer comparer) + { + Debug.Assert(keys.Length >= IntrosortSizeThreshold); + //Debug.Assert(comparer != null); + + int hi = keys.Length - 1; + + // Compute median-of-three. But also partition them, since we've done the comparison. + int middle = hi >> 1; + + // Sort lo, mid and hi appropriately, then pick mid as the pivot. + SwapIfGreater(keys, ref comparer, 0, middle); // swap the low with the mid point + SwapIfGreater(keys, ref comparer, 0, hi); // swap the low with the high + SwapIfGreater(keys, ref comparer, middle, hi); // swap the middle with the high + + T pivot = keys[middle]; + Swap(keys, middle, hi - 1); + int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. + + while (left < right) + { + while (comparer.Compare(keys[++left], pivot) < 0) ; + while (comparer.Compare(pivot, keys[--right]) < 0) ; + + if (left >= right) + break; + + Swap(keys, left, right); + } + + // Put pivot in the right location. + if (left != hi - 1) + { + Swap(keys, left, hi - 1); + } + return left; + } + + private static void HeapSort(Span keys, ref TComparer comparer) + { + Debug.Assert(!keys.IsEmpty); + //Debug.Assert(comparer != null); + + int n = keys.Length; + for (int i = n >> 1; i >= 1; i--) + { + DownHeap(keys, i, n, ref comparer); + } + + for (int i = n; i > 1; i--) + { + Swap(keys, 0, i - 1); + DownHeap(keys, 1, i - 1, ref comparer); + } + } + + private static void DownHeap(Span keys, int i, int n, ref TComparer comparer) + { + //Debug.Assert(comparer != null); + + T d = keys[i - 1]; + while (i <= n >> 1) + { + int child = 2 * i; + if (child < n && comparer.Compare(keys[child - 1], keys[child]) < 0) + { + child++; + } + + if (!(comparer.Compare(d, keys[child - 1]) < 0)) + break; + + keys[i - 1] = keys[child - 1]; + i = child; + } + + keys[i - 1] = d; + } + + private static void InsertionSort(Span keys, ref TComparer comparer) + { + for (int i = 0; i < keys.Length - 1; i++) + { + T t = keys[i + 1]; + + int j = i; + while (j >= 0 && comparer.Compare(t, keys[j]) < 0) + { + keys[j + 1] = keys[j]; + j--; + } + + keys[j + 1] = t; + } + } + #endregion + + #region Swaps + private static void SwapIfGreater(Span keys, ref TComparer comparer, int i, int j) + { + Debug.Assert(i != j); + if (comparer.Compare(keys[i], keys[j]) > 0) + { + T key = keys[i]; + keys[i] = keys[j]; + keys[j] = key; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Swap(Span a, int i, int j) + { + Debug.Assert(i != j); + T t = a[i]; + a[i] = a[j]; + a[j] = t; + } + #endregion + } + + #region Wrappers +#if ENABLE_IL2CPP + [Il2CppSetOption(Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +#endif + internal readonly struct ComparableWrapper : IComparer + where T : IComparable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Compare(T x, T y) { return x.CompareTo(y); } + } +#if ENABLE_IL2CPP + [Il2CppSetOption(Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +#endif + internal readonly struct ComparisonWrapper : IComparer + { + public readonly Comparison Comparison; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ComparisonWrapper(Comparison comparison) + { + Comparison = comparison; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Compare(T x, T y) + { + return Comparison(x, y); + } + } +#if ENABLE_IL2CPP + [Il2CppSetOption(Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +#endif + internal readonly struct ComparerWrapper : IComparer + { + public readonly Comparer Comparer; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ComparerWrapper(Comparer comparer) + { + Comparer = comparer; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Compare(T x, T y) + { + return Comparer.Compare(x, y); + } + } + #endregion +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +//namespace DCFApixels.DragonECS.Core.Internal +//{ +// internal interface IStructComparer : IComparer +// { +// // a > b = return > 0 +// // int Compare(T a, T b); +// } +// +//#if ENABLE_IL2CPP +// [Il2CppSetOption(Option.NullChecks, false)] +// [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +//#endif +// internal static class ArraySortHalperX +// { +// private const int IntrosortSizeThreshold = 16; +// +// #region IStructComparer +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public static void SwapIfGreater(T[] items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer +// { +// if (comparer.Compare(items[i], items[j]) > 0) +// { +// T key = items[i]; +// items[i] = items[j]; +// items[j] = key; +// } +// } +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public static void InsertionSort(T[] items, ref TComparer comparer) where TComparer : IStructComparer +// { +// for (int i = 0; i < items.Length - 1; i++) +// { +// T t = items[i + 1]; +// +// int j = i; +// while (j >= 0 && comparer.Compare(t, items[j]) < 0) +// { +// items[j + 1] = items[j]; +// j--; +// } +// +// items[j + 1] = t; +// } +// } +// +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public static void Sort(T[] items, ref TComparer comparer) where TComparer : IStructComparer +// { +// int length = items.Length; +// if (length == 1) +// { +// return; +// } +// +// if (length <= IntrosortSizeThreshold) +// { +// +// if (length == 2) +// { +// SwapIfGreater(items, ref comparer, 0, 1); +// return; +// } +// +// if (length == 3) +// { +// SwapIfGreater(items, ref comparer, 0, 1); +// SwapIfGreater(items, ref comparer, 0, 2); +// SwapIfGreater(items, ref comparer, 1, 2); +// return; +// } +// +// InsertionSort(items, ref comparer); +// return; +// } +// +// IStructComparer packed = comparer; +// Array.Sort(items, 0, items.Length, packed); +// comparer = (TComparer)packed; +// } +// #endregion +// +// #region Comparison +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public static void SwapIfGreater(T[] items, Comparison comparison, int i, int j) +// { +// if (comparison(items[i], items[j]) > 0) +// { +// T key = items[i]; +// items[i] = items[j]; +// items[j] = key; +// } +// } +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public static void InsertionSort(T[] items, int length, Comparison comparison) +// { +// for (int i = 0; i < length - 1; i++) +// { +// T t = items[i + 1]; +// +// int j = i; +// while (j >= 0 && comparison(t, items[j]) < 0) +// { +// items[j + 1] = items[j]; +// j--; +// } +// +// items[j + 1] = t; +// } +// } +// +//#if ENABLE_IL2CPP +// [Il2CppSetOption(Option.NullChecks, false)] +// [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +//#endif +// private class ComparisonHach : IComparer +// { +// public static readonly ComparisonHach Instance = new ComparisonHach(); +// public Comparison comparison; +// private ComparisonHach() { } +// public int Compare(T x, T y) { return comparison(x, y); } +// } +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public static void Sort(T[] items, Comparison comparison) +// { +// Sort(items, comparison, items.Length); +// } +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public static void Sort(T[] items, Comparison comparison, int length) +// { +// if (length <= IntrosortSizeThreshold) +// { +// if (length == 1) +// { +// return; +// } +// if (length == 2) +// { +// SwapIfGreater(items, comparison, 0, 1); +// return; +// } +// if (length == 3) +// { +// SwapIfGreater(items, comparison, 0, 1); +// SwapIfGreater(items, comparison, 0, 2); +// SwapIfGreater(items, comparison, 1, 2); +// return; +// } +// InsertionSort(items, length, comparison); +// return; +// } +// ComparisonHach.Instance.comparison = comparison; +// Array.Sort(items, 0, length, ComparisonHach.Instance); +// } +// #endregion +// } +// +//#if ENABLE_IL2CPP +// [Il2CppSetOption(Option.NullChecks, false)] +// [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +//#endif +// internal static unsafe class UnsafeArraySortHalperX where T : unmanaged +// { +// private const int IntrosortSizeThreshold = 16; +// +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public static void SwapIfGreater(T* items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer +// { +// if (comparer.Compare(items[i], items[j]) > 0) +// { +// T key = items[i]; +// items[i] = items[j]; +// items[j] = key; +// } +// } +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public static void InsertionSort_Unchecked(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer +// { +// for (int i = 0; i < length - 1; i++) +// { +// T t = items[i + 1]; +// +// int j = i; +// while (j >= 0 && comparer.Compare(t, items[j]) < 0) +// { +// items[j + 1] = items[j]; +// j--; +// } +// +// items[j + 1] = t; +// } +// } +// public static void InsertionSort(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer +// { +// if (length == 1) +// { +// return; +// } +// +// if (length == 2) +// { +// SwapIfGreater(items, ref comparer, 0, 1); +// return; +// } +// +// if (length == 3) +// { +// SwapIfGreater(items, ref comparer, 0, 1); +// SwapIfGreater(items, ref comparer, 0, 2); +// SwapIfGreater(items, ref comparer, 1, 2); +// return; +// } +// +// InsertionSort_Unchecked(items, length, ref comparer); +// } +// } +//} \ No newline at end of file diff --git a/src/Internal/ArraySortHalperX.cs.meta b/src/Internal/SortHalper.cs.meta similarity index 83% rename from src/Internal/ArraySortHalperX.cs.meta rename to src/Internal/SortHalper.cs.meta index 0805127..06a6947 100644 --- a/src/Internal/ArraySortHalperX.cs.meta +++ b/src/Internal/SortHalper.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a591de1858028504d819333121bfddd6 +guid: 7e60048b7c58cdf4ba044b7c832bd6a4 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/src/Internal/UnsafeArray.cs b/src/Internal/UnsafeArray.cs index 4ec388b..ce13c17 100644 --- a/src/Internal/UnsafeArray.cs +++ b/src/Internal/UnsafeArray.cs @@ -38,13 +38,13 @@ namespace DCFApixels.DragonECS.Core.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public UnsafeArray(int length) { - UnmanagedArrayUtility.New(out ptr, length); + ptr = MemoryAllocator.Alloc(length).Ptr; Length = length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public UnsafeArray(int length, bool isInit) { - UnmanagedArrayUtility.NewAndInit(out ptr, length); + ptr = MemoryAllocator.AllocAndInit(length).Ptr; Length = length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -90,18 +90,20 @@ namespace DCFApixels.DragonECS.Core.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public UnsafeArray Clone() { - return new UnsafeArray(UnmanagedArrayUtility.Clone(ptr, Length), Length); + return new UnsafeArray(MemoryAllocator.From(ptr, Length).Ptr, Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Dispose() { - UnmanagedArrayUtility.Free(ref ptr, ref Length); + MemoryAllocator.Free(ptr); + ptr = default; + Length = default; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ReadonlyDispose() { - UnmanagedArrayUtility.Free(ptr); + MemoryAllocator.Free(ptr); } public override string ToString() { @@ -114,6 +116,9 @@ namespace DCFApixels.DragonECS.Core.Internal return CollectionUtility.AutoToString(elements, "ua"); } + public Span AsSpan() { return new Span(ptr, Length); } + public T[] ToArray() { return AsSpan().ToArray(); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs index 943d6c7..4bd629e 100644 --- a/src/Pools/EcsPool.cs +++ b/src/Pools/EcsPool.cs @@ -35,7 +35,8 @@ namespace DCFApixels.DragonECS public sealed class EcsPool : IEcsPoolImplementation, IEcsStructPool, IEnumerable //IEnumerable - IntelliSense hack where T : struct, IEcsComponent { - private EcsWorld _source; + private short _worldID; + private EcsWorld _world; private int _componentTypeID; private EcsMaskChunck _maskBit; @@ -45,14 +46,14 @@ namespace DCFApixels.DragonECS private int[] _recycledItems; private int _recycledItemsCount = 0; - private readonly IEcsComponentLifecycle _componentLifecycleHandler = EcsComponentLifecycleHandler.instance; - private readonly bool _isHasComponentLifecycleHandler = EcsComponentLifecycleHandler.isHasHandler; - private readonly IEcsComponentCopy _componentCopyHandler = EcsComponentCopyHandler.instance; - private readonly bool _isHasComponentCopyHandler = EcsComponentCopyHandler.isHasHandler; + private readonly IEcsComponentLifecycle _customLifecycle = EcsComponentLifecycle.CustomHandler; + private readonly bool _isCustomLifecycle = EcsComponentLifecycle.IsCustom; + private readonly IEcsComponentCopy _customCopy = EcsComponentCopy.CustomHandler; + private readonly bool _isCustomCopy = EcsComponentCopy.IsCustom; #if !DRAGONECS_DISABLE_POOLS_EVENTS private StructList _listeners = new StructList(2); - private int _listenersCachedCount = 0; + private bool _hasAnyListener = false; #endif private bool _isLocked; @@ -77,7 +78,7 @@ namespace DCFApixels.DragonECS } public EcsWorld World { - get { return _source; } + get { return _world; } } public bool IsReadOnly { @@ -104,7 +105,8 @@ namespace DCFApixels.DragonECS } void IEcsPoolImplementation.OnInit(EcsWorld world, EcsWorld.PoolsMediator mediator, int componentTypeID) { - _source = world; + _world = world; + _worldID = world.ID; _mediator = mediator; _componentTypeID = componentTypeID; _maskBit = EcsMaskChunck.FromID(componentTypeID); @@ -128,13 +130,13 @@ namespace DCFApixels.DragonECS { ref int itemIndex = ref _mapping[entityID]; #if DEBUG - if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_source, entityID); } - if (_source.IsUsed(entityID) == false) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_source, entityID); } + if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); } + if (_world.IsUsed(entityID) == false) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); } if (itemIndex > 0) { EcsPoolThrowHelper.ThrowAlreadyHasComponent(entityID); } if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); } #elif DRAGONECS_STABILITY_MODE if (itemIndex > 0) { return ref Get(entityID); } - if (_isLocked | _source.IsUsed(entityID) == false) { return ref _items[0]; } + if (_isLocked | _world.IsUsed(entityID) == false) { return ref _items[0]; } #endif if (_recycledItemsCount > 0) { @@ -151,9 +153,9 @@ namespace DCFApixels.DragonECS } _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); ref T result = ref _items[itemIndex]; - EnableComponent(ref result); + EcsComponentLifecycle.OnAdd( _isCustomLifecycle, _customLifecycle, ref result, _worldID, entityID); #if !DRAGONECS_DISABLE_POOLS_EVENTS - _listeners.InvokeOnAddAndGet(entityID, _listenersCachedCount); + if (_hasAnyListener) { _listeners.InvokeOnAddAndGet(entityID); } #endif return ref result; } @@ -164,7 +166,7 @@ namespace DCFApixels.DragonECS if (!Has(entityID)) { EcsPoolThrowHelper.ThrowNotHaveComponent(entityID); } #endif #if !DRAGONECS_DISABLE_POOLS_EVENTS - _listeners.InvokeOnGet(entityID, _listenersCachedCount); + if (_hasAnyListener) { _listeners.InvokeOnGet(entityID); } #endif return ref _items[_mapping[entityID]]; } @@ -179,7 +181,7 @@ namespace DCFApixels.DragonECS public ref T TryAddOrGet(int entityID) { #if DEBUG - if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_source, entityID); } + if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); } #endif ref int itemIndex = ref _mapping[entityID]; if (itemIndex <= 0) @@ -203,13 +205,13 @@ namespace DCFApixels.DragonECS } } _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); - EnableComponent(ref _items[itemIndex]); + EcsComponentLifecycle.OnAdd(_isCustomLifecycle, _customLifecycle, ref _items[itemIndex], _worldID, entityID); #if !DRAGONECS_DISABLE_POOLS_EVENTS - _listeners.InvokeOnAdd(entityID, _listenersCachedCount); + if (_hasAnyListener) { _listeners.InvokeOnAdd(entityID); } #endif } //Add block end #if !DRAGONECS_DISABLE_POOLS_EVENTS - _listeners.InvokeOnGet(entityID, _listenersCachedCount); + if (_hasAnyListener) { _listeners.InvokeOnGet(entityID); } #endif return ref _items[itemIndex]; } @@ -222,14 +224,14 @@ namespace DCFApixels.DragonECS { ref int itemIndex = ref _mapping[entityID]; #if DEBUG - if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_source, entityID); } + if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); } if (itemIndex <= 0) { EcsPoolThrowHelper.ThrowNotHaveComponent(entityID); } if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); } #elif DRAGONECS_STABILITY_MODE if (itemIndex <= 0) { return; } if (_isLocked) { return; } #endif - DisableComponent(ref _items[itemIndex]); + EcsComponentLifecycle.OnDel( _isCustomLifecycle, _customLifecycle, ref _items[itemIndex], _worldID, entityID); if (_recycledItemsCount >= _recycledItems.Length) { Array.Resize(ref _recycledItems, ArrayUtility.NextPow2Safe(_recycledItemsCount)); @@ -239,7 +241,7 @@ namespace DCFApixels.DragonECS _itemsCount--; _mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit); #if !DRAGONECS_DISABLE_POOLS_EVENTS - _listeners.InvokeOnDel(entityID, _listenersCachedCount); + if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); } #endif } public void TryDel(int entityID) @@ -256,7 +258,7 @@ namespace DCFApixels.DragonECS #elif DRAGONECS_STABILITY_MODE if (!Has(fromEntityID)) { return; } #endif - CopyComponent(ref Get(fromEntityID), ref TryAddOrGet(toEntityID)); + EcsComponentCopy.Copy(_isCustomCopy, _customCopy, ref Get(fromEntityID), ref TryAddOrGet(toEntityID)); } public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID) { @@ -265,7 +267,7 @@ namespace DCFApixels.DragonECS #elif DRAGONECS_STABILITY_MODE if (!Has(fromEntityID)) { return; } #endif - CopyComponent(ref Get(fromEntityID), ref toWorld.GetPool().TryAddOrGet(toEntityID)); + EcsComponentCopy.Copy(_isCustomCopy, _customCopy, ref Get(fromEntityID), ref toWorld.GetPool().TryAddOrGet(toEntityID)); } public void ClearAll() @@ -277,15 +279,15 @@ namespace DCFApixels.DragonECS #endif _recycledItemsCount = 0; // , Del if (_itemsCount <= 0) { return; } - var span = _source.Where(out SingleAspect _); + var span = _world.Where(out SingleAspect _); foreach (var entityID in span) { ref int itemIndex = ref _mapping[entityID]; - DisableComponent(ref _items[itemIndex]); + EcsComponentLifecycle.OnDel(_isCustomLifecycle, _customLifecycle, ref _items[itemIndex], _worldID, entityID); itemIndex = 0; _mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit); #if !DRAGONECS_DISABLE_POOLS_EVENTS - _listeners.InvokeOnDel(entityID, _listenersCachedCount); + if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); } #endif } _itemsCount = 0; @@ -332,58 +334,19 @@ namespace DCFApixels.DragonECS { if (listener == null) { EcsPoolThrowHelper.ThrowNullListener(); } _listeners.Add(listener); - _listenersCachedCount++; + _hasAnyListener = _listeners.Count > 0; } public void RemoveListener(IEcsPoolEventListener listener) { if (listener == null) { EcsPoolThrowHelper.ThrowNullListener(); } if (_listeners.RemoveWithOrder(listener)) { - _listenersCachedCount--; + _hasAnyListener = _listeners.Count > 0; } } #endif #endregion - #region Enable/Disable/Copy - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void EnableComponent(ref T component) - { - if (_isHasComponentLifecycleHandler) - { - _componentLifecycleHandler.Enable(ref component); - } - else - { - component = default; - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void DisableComponent(ref T component) - { - if (_isHasComponentLifecycleHandler) - { - _componentLifecycleHandler.Disable(ref component); - } - else - { - component = default; - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void CopyComponent(ref T from, ref T to) - { - if (_isHasComponentCopyHandler) - { - _componentCopyHandler.Copy(ref from, ref to); - } - else - { - to = from; - } - } - #endregion - #region IEnumerator - IntelliSense hack IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } @@ -484,7 +447,6 @@ namespace DCFApixels.DragonECS #endregion } - public static class EcsPoolExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -518,29 +480,5 @@ namespace DCFApixels.DragonECS { return self.AnyPool>(); } - - #region Obsolete - [Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Inc) + "()")] - [EditorBrowsable(EditorBrowsableState.Never)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsPool Include(this EcsAspect.Builder self) where TComponent : struct, IEcsComponent - { - return self.IncludePool>(); - } - [Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Exc) + "()")] - [EditorBrowsable(EditorBrowsableState.Never)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsPool Exclude(this EcsAspect.Builder self) where TComponent : struct, IEcsComponent - { - return self.ExcludePool>(); - } - [Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Opt) + "()")] - [EditorBrowsable(EditorBrowsableState.Never)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsPool Optional(this EcsAspect.Builder self) where TComponent : struct, IEcsComponent - { - return self.OptionalPool>(); - } - #endregion } -} +} \ No newline at end of file diff --git a/src/Pools/EcsPoolBase.cs b/src/Pools/EcsPoolBase.cs index d7423e6..8aa01ef 100644 --- a/src/Pools/EcsPoolBase.cs +++ b/src/Pools/EcsPoolBase.cs @@ -62,7 +62,12 @@ namespace DCFApixels.DragonECS.PoolsCore [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowNullListener() { - throw new ArgumentNullException("listener is null"); + throw new ArgumentNullException("Listener is null"); + } + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ThrowNullComponent() + { + throw new ArgumentNullException("Component is null"); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowPoolLocked() @@ -291,67 +296,11 @@ namespace DCFApixels.DragonECS { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvokeOnAdd(this List self, int entityID) - { - self.InvokeOnAdd(entityID, self.Count); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InvokeOnAdd(this List self, int entityID, int cachedCount) - { - for (int i = 0; i < cachedCount; i++) { self[i].OnAdd(entityID); } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InvokeOnAddAndGet(this List self, int entityID) - { - self.InvokeOnAddAndGet(entityID, self.Count); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InvokeOnAddAndGet(this List self, int entityID, int cachedCount) - { - for (int i = 0; i < cachedCount; i++) - { - self[i].OnAdd(entityID); - self[i].OnGet(entityID); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InvokeOnGet(this List self, int entityID) - { - self.InvokeOnGet(entityID, self.Count); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InvokeOnGet(this List self, int entityID, int cachedCount) - { - for (int i = 1; i < cachedCount; i++) { self[i].OnGet(entityID); } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InvokeOnDel(this List self, int entityID) - { - self.InvokeOnDel(entityID, self.Count); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InvokeOnDel(this List self, int entityID, int cachedCount) - { - for (int i = 0; i < cachedCount; i++) { self[i].OnDel(entityID); } - } - - // - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void InvokeOnAdd(ref this StructList self, int entityID) { for (int i = 0; i < self.Count; i++) { self[i].OnAdd(entityID); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void InvokeOnAdd(ref this StructList self, int entityID, int cachedCount) - { - for (int i = 0; i < cachedCount; i++) { self[i].OnAdd(entityID); } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void InvokeOnAddAndGet(ref this StructList self, int entityID) + public static void InvokeOnAddAndGet(this List self, int entityID) { for (int i = 0; i < self.Count; i++) { @@ -360,34 +309,43 @@ namespace DCFApixels.DragonECS } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void InvokeOnAddAndGet(ref this StructList self, int entityID, int cachedCount) + public static void InvokeOnGet(this List self, int entityID) { - for (int i = 0; i < cachedCount; i++) + for (int i = 1; i < self.Count; i++) { self[i].OnGet(entityID); } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void InvokeOnDel(this List self, int entityID) + { + for (int i = 0; i < self.Count; i++) { self[i].OnDel(entityID); } + } + + // + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void InvokeOnAdd(this StructList self, int entityID) + { + for (int i = 0; i < self.Count; i++) { self[i].OnAdd(entityID); } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void InvokeOnAddAndGet(this StructList self, int entityID) + { + for (int i = 0; i < self.Count; i++) { self[i].OnAdd(entityID); self[i].OnGet(entityID); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void InvokeOnGet(ref this StructList self, int entityID) + internal static void InvokeOnGet(this StructList self, int entityID) { - for (int i = 1; i < self.Count; i++) { self[i].OnGet(entityID); } + for (int i = 0; i < self.Count; i++) { self[i].OnGet(entityID); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void InvokeOnGet(ref this StructList self, int entityID, int cachedCount) - { - for (int i = 1; i < cachedCount; i++) { self[i].OnGet(entityID); } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void InvokeOnDel(ref this StructList self, int entityID) + internal static void InvokeOnDel(this StructList self, int entityID) { for (int i = 0; i < self.Count; i++) { self[i].OnDel(entityID); } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void InvokeOnDel(ref this StructList self, int entityID, int cachedCount) - { - for (int i = 0; i < cachedCount; i++) { self[i].OnDel(entityID); } - } } #endif #endregion diff --git a/src/Pools/EcsTagPool.cs b/src/Pools/EcsTagPool.cs index 536fe9c..9517938 100644 --- a/src/Pools/EcsTagPool.cs +++ b/src/Pools/EcsTagPool.cs @@ -35,7 +35,7 @@ namespace DCFApixels.DragonECS public sealed class EcsTagPool : IEcsPoolImplementation, IEcsStructPool, IEnumerable //IEnumerable - IntelliSense hack where T : struct, IEcsTagComponent { - private EcsWorld _source; + private EcsWorld _world; private int _componentTypeID; private EcsMaskChunck _maskBit; @@ -44,7 +44,7 @@ namespace DCFApixels.DragonECS #if !DRAGONECS_DISABLE_POOLS_EVENTS private StructList _listeners = new StructList(2); - private int _listenersCachedCount = 0; + private bool _hasAnyListener = false; #endif private bool _isLocked; @@ -78,7 +78,7 @@ namespace DCFApixels.DragonECS } public EcsWorld World { - get { return _source; } + get { return _world; } } public bool IsReadOnly { @@ -102,7 +102,7 @@ namespace DCFApixels.DragonECS } void IEcsPoolImplementation.OnInit(EcsWorld world, EcsWorld.PoolsMediator mediator, int componentTypeID) { - _source = world; + _world = world; _mediator = mediator; _componentTypeID = componentTypeID; _maskBit = EcsMaskChunck.FromID(componentTypeID); @@ -116,17 +116,18 @@ namespace DCFApixels.DragonECS public void Add(int entityID) { #if DEBUG - if (_source.IsUsed(entityID) == false) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_source, entityID); } + if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); } + if (_world.IsUsed(entityID) == false) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); } if (Has(entityID)) { EcsPoolThrowHelper.ThrowAlreadyHasComponent(entityID); } if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); } #elif DRAGONECS_STABILITY_MODE - if (Has(entityID) | _source.IsUsed(entityID) == false | _isLocked) { return; } + if (Has(entityID) | _world.IsUsed(entityID) == false | _isLocked) { return; } #endif _count++; _mapping[entityID] = true; _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); #if !DRAGONECS_DISABLE_POOLS_EVENTS - _listeners.InvokeOnAdd(entityID, _listenersCachedCount); + if (_hasAnyListener) { _listeners.InvokeOnAdd(entityID); } #endif } public void TryAdd(int entityID) @@ -144,6 +145,7 @@ namespace DCFApixels.DragonECS public void Del(int entityID) { #if DEBUG + if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); } if (!Has(entityID)) { EcsPoolThrowHelper.ThrowNotHaveComponent(entityID); } if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); } #elif DRAGONECS_STABILITY_MODE @@ -153,7 +155,7 @@ namespace DCFApixels.DragonECS _count--; _mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit); #if !DRAGONECS_DISABLE_POOLS_EVENTS - _listeners.InvokeOnDel(entityID, _listenersCachedCount); + if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); } #endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -216,14 +218,14 @@ namespace DCFApixels.DragonECS if (_isLocked) { return; } #endif if (_count <= 0) { return; } - var span = _source.Where(out SingleTagAspect _); + var span = _world.Where(out SingleTagAspect _); _count = 0; foreach (var entityID in span) { _mapping[entityID] = false; _mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit); #if !DRAGONECS_DISABLE_POOLS_EVENTS - _listeners.InvokeOnDel(entityID, _listenersCachedCount); + if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); } #endif } } @@ -293,14 +295,14 @@ namespace DCFApixels.DragonECS { if (listener == null) { EcsPoolThrowHelper.ThrowNullListener(); } _listeners.Add(listener); - _listenersCachedCount++; + _hasAnyListener = _listeners.Count > 0; } public void RemoveListener(IEcsPoolEventListener listener) { if (listener == null) { EcsPoolThrowHelper.ThrowNullListener(); } if (_listeners.RemoveWithOrder(listener)) { - _listenersCachedCount--; + _hasAnyListener = _listeners.Count > 0; } } #endif @@ -407,7 +409,6 @@ namespace DCFApixels.DragonECS public static implicit operator ReadonlyEcsTagPool(EcsWorld.GetPoolInstanceMarker a) { return a.GetInstance>(); } #endregion } - public static class EcsTagPoolExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -441,68 +442,5 @@ namespace DCFApixels.DragonECS { return self.OptionalPool>(); } - - #region Obsolete - [Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Inc) + "()")] - [EditorBrowsable(EditorBrowsableState.Never)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsTagPool Include(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent - { - return self.IncludePool>(); - } - [Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Exc) + "()")] - [EditorBrowsable(EditorBrowsableState.Never)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsTagPool Exclude(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent - { - return self.ExcludePool>(); - } - [Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Opt) + "()")] - [EditorBrowsable(EditorBrowsableState.Never)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsTagPool Optional(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent - { - return self.OptionalPool>(); - } - - //--------------------------------------------------- - - [Obsolete("Use " + nameof(EcsWorld) + "." + nameof(GetPool) + "()")] - [EditorBrowsable(EditorBrowsableState.Never)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsTagPool GetTagPool(this EcsWorld self) where TTagComponent : struct, IEcsTagComponent - { - return self.GetPoolInstance>(); - } - [Obsolete("Use " + nameof(EcsWorld) + "." + nameof(GetPoolUnchecked) + "()")] - [EditorBrowsable(EditorBrowsableState.Never)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsTagPool GetTagPoolUnchecked(this EcsWorld self) where TTagComponent : struct, IEcsTagComponent - { - return self.GetPoolInstanceUnchecked>(); - } - - [Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Inc) + "()")] - [EditorBrowsable(EditorBrowsableState.Never)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsTagPool IncludeTag(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent - { - return self.IncludePool>(); - } - [Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Exc) + "()")] - [EditorBrowsable(EditorBrowsableState.Never)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsTagPool ExcludeTag(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent - { - return self.ExcludePool>(); - } - [Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Opt) + "()")] - [EditorBrowsable(EditorBrowsableState.Never)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsTagPool OptionalTag(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent - { - return self.OptionalPool>(); - } - #endregion } -} +} \ No newline at end of file diff --git a/src/Utils/AllowedInWorldsAttribute.cs b/src/Utils/AllowedInWorldsAttribute.cs index 19457ed..58ed487 100644 --- a/src/Utils/AllowedInWorldsAttribute.cs +++ b/src/Utils/AllowedInWorldsAttribute.cs @@ -37,7 +37,7 @@ namespace DCFApixels.DragonECS return; } } - throw new InvalidOperationException($"Using component {componentType.ToMeta().TypeName} is not allowed in the {worldType.ToMeta().TypeName} world."); + throw new InvalidOperationException($"Using component {componentType.GetMeta().TypeName} is not allowed in the {worldType.GetMeta().TypeName} world."); } } } diff --git a/src/Utils/Exceptions.cs b/src/Utils/Exceptions.cs index 832c41d..49db43f 100644 --- a/src/Utils/Exceptions.cs +++ b/src/Utils/Exceptions.cs @@ -139,12 +139,12 @@ namespace DCFApixels.DragonECS.Core.Internal [MethodImpl(MethodImplOptions.NoInlining)] internal static void Quiery_ArgumentDifferentWorldsException() { - throw new ArgumentException("The groups belong to different worlds."); + ArgumentDifferentWorldsException(); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void ArgumentDifferentWorldsException() { - throw new ArgumentException("The groups belong to different worlds."); + throw new ArgumentException("World ID mismatch: the expected and actual world identifiers do not match."); } [MethodImpl(MethodImplOptions.NoInlining)] diff --git a/src/Utils/LayersMap.cs b/src/Utils/LayersMap.cs index 4a27d4c..c995632 100644 --- a/src/Utils/LayersMap.cs +++ b/src/Utils/LayersMap.cs @@ -252,74 +252,5 @@ namespace DCFApixels.DragonECS.Core return _graph.Sort(); } #endregion - - #region Obsolete - [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).Before(targetLayer).Back;")] - public EcsPipeline.Builder Insert(string targetLayer, string newLayer) - { - Add(newLayer).Before(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).After(targetLayer).Back;")] - public EcsPipeline.Builder InsertAfter(string targetLayer, string newLayer) - { - Add(newLayer).After(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).Before(targetLayer).Back;")] - public EcsPipeline.Builder Move(string targetLayer, string newLayer) - { - Move(newLayer).Before(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).After(targetLayer).Back;")] - public EcsPipeline.Builder MoveAfter(string targetLayer, string newLayer) - { - Move(newLayer).After(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).Before(targetLayer).Back;")] - public EcsPipeline.Builder Insert(string targetLayer, params string[] newLayers) - { - Add(newLayers).Before(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).After(targetLayer).Back;")] - public EcsPipeline.Builder InsertAfter(string targetLayer, params string[] newLayers) - { - Add(newLayers).After(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).Before(targetLayer).Back;")] - public EcsPipeline.Builder Move(string targetLayer, params string[] movingLayers) - { - Move(movingLayers).Before(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).After(targetLayer).Back;")] - public EcsPipeline.Builder MoveAfter(string targetLayer, params string[] movingLayers) - { - Move(movingLayers).After(targetLayer); - return _pipelineBuilder; - } - - [Obsolete] - public object this[int index] - { - get - { - int i = 0; - foreach (var item in this) - { - if (i == index) - { - return item; - } - i++; - } - return null; - } - } - #endregion } } \ No newline at end of file diff --git a/src/Utils/ReadOnlySpanDummy.cs b/src/Utils/ReadOnlySpanDummy.cs deleted file mode 100644 index 4a4cdae..0000000 --- a/src/Utils/ReadOnlySpanDummy.cs +++ /dev/null @@ -1,202 +0,0 @@ -#if ENABLE_DUMMY_SPAN -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; -using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; - -namespace DCFApixels.DragonECS -{ - internal static class ThrowHelper - { - public static void ThrowIndexOutOfRangeException() => throw new IndexOutOfRangeException(); - public static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException(); - public static void ThrowInvalidOperationException() => throw new InvalidOperationException(); - } - [DebuggerDisplay("{ToString(),raw}")] - public readonly ref struct ReadOnlySpan - { - public static ReadOnlySpan Empty => new ReadOnlySpan(null); - - internal readonly T[] _array; - private readonly int _start; - private readonly int _length; - - #region Properties - public int Length => _length; - public bool IsEmpty => _length == 0; - public ref readonly T this[int index] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - if ((uint)index >= (uint)_length || (uint)index < 0) - ThrowHelper.ThrowIndexOutOfRangeException(); - return ref _array[index + _start]; - } - } - #endregion - - #region Constructors - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan(T[] array) - { - _array = array ?? Array.Empty(); - _start = 0; - _length = array.Length; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan(T[] array, int start, int length) - { - if (array == null) - { - if (start != 0 || length != 0) - ThrowHelper.ThrowArgumentOutOfRangeException(); - _array = Array.Empty(); - _start = 0; - _length = 0; - return; - } - - if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - _array = array; - _start = start; - _length = length; - } - #endregion - - #region Object -#pragma warning disable CS0809 // - [Obsolete("Equals() on ReadOnlySpan will always throw an exception. Use the equality operator instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool Equals(object obj) => throw new NotSupportedException(); - [Obsolete("GetHashCode() on ReadOnlySpan will always throw an exception.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public override int GetHashCode() => throw new NotSupportedException(); -#pragma warning restore CS0809 // - public override string ToString() - { - //if (typeof(T) == typeof(char)) - // return new string(new ReadOnlySpan(ref Unsafe.As(ref _reference), _length)); - return $"System.ReadOnlySpan<{typeof(T).Name}>[{_length}]"; - } - #endregion - - #region operators - public static bool operator !=(ReadOnlySpan left, ReadOnlySpan right) => !(left == right); - - public static implicit operator ReadOnlySpan(T[] array) => new ReadOnlySpan(array); - - public static implicit operator ReadOnlySpan(ArraySegment segment) => new ReadOnlySpan(segment.Array, segment.Offset, segment.Count); - public static bool operator ==(ReadOnlySpan left, ReadOnlySpan right) => left._length == right._length && left._array == right._array; - #endregion - - #region Enumerator - public Enumerator GetEnumerator() => new Enumerator(this); - public ref struct Enumerator - { - private readonly ReadOnlySpan _span; - private int _index; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Enumerator(ReadOnlySpan span) - { - _span = span; - _index = span._start - 1; - } - public ref readonly T Current - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref _span[_index]; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() - { - int index = _index + 1; - if (index < _span.Length) - { - _index = index; - return true; - } - return false; - } - } - #endregion - - #region Other - [EditorBrowsable(EditorBrowsableState.Never)] - public ref readonly T GetPinnableReference() - { - if (_length != 0) ThrowHelper.ThrowInvalidOperationException(); - return ref _array[0]; - } - - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public void CopyTo(Span destination) - //{ - // if ((uint)_length <= (uint)destination.Length) - // { - // Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length); - // } - // else - // { - // ThrowHelper.ThrowArgumentException_DestinationTooShort(); - // } - //} - - //public bool TryCopyTo(Span destination) - //{ - // bool retVal = false; - // if ((uint)_length <= (uint)destination.Length) - // { - // Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length); - // retVal = true; - // } - // return retVal; - //} - public void CopyTo(T[] array) - { - if (_length > array.Length) - { - throw new ArgumentOutOfRangeException(); - } - - for (int i = 0; i < _length; i++) - { - array[i] = _array[i]; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan Slice(int start) - { - if ((uint)start > (uint)_length) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return new ReadOnlySpan(_array, _start + start, _length - start); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan Slice(int start, int length) - { - if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return new ReadOnlySpan(_array, _start + start, length); - } - - public T[] ToArray() - { - if (_length == 0) - return Array.Empty(); - var result = new T[_length]; - Array.Copy(_array, _start, result, 0, _length); - return result; - } - #endregion - } -} -#endif \ No newline at end of file diff --git a/src/Utils/ReadOnlySpanDummy.cs.meta b/src/Utils/ReadOnlySpanDummy.cs.meta deleted file mode 100644 index 40c53b3..0000000 --- a/src/Utils/ReadOnlySpanDummy.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bfb00ad58c175a84388c316daf9b03ae -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/Utils/Uncheked/UncheckedUtility.cs b/src/Utils/Uncheked/UncheckedUtility.cs index 1775abc..76c5105 100644 --- a/src/Utils/Uncheked/UncheckedUtility.cs +++ b/src/Utils/Uncheked/UncheckedUtility.cs @@ -5,73 +5,6 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; -namespace DCFApixels.DragonECS.UncheckedCore -{ - [Obsolete("Use DCFApixels.DragonECS.Core.UncheckedUtility")] - public static class UncheckedCoreUtility - { - #region CreateEntLong - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static entlong CreateEntLong(int entityID, short gen, short worldID) - { - return new entlong(entityID, gen, worldID); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static entlong CreateEntLong(long entityGenWorld) - { - return new entlong(entityGenWorld); - } - #endregion - - #region CreateSpan - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsSpan CreateSpan(short worldID, ReadOnlySpan entitesArray) - { - return new EcsSpan(worldID, entitesArray); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsSpan CreateSpan(short worldID, int[] entitesArray, int startIndex, int length) - { - return new EcsSpan(worldID, entitesArray, startIndex, length); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsSpan CreateSpan(short worldID, int[] entitesArray, int length) - { - return new EcsSpan(worldID, entitesArray, length); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsSpan CreateSpan(short worldID, int[] entitesArray) - { - return new EcsSpan(worldID, entitesArray); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static EcsSpan CreateEmptySpan(short worldID) - { - return new EcsSpan(worldID, Array.Empty()); - } - public static bool CheckSpanValideDebug(EcsSpan span) - { - HashSet set = new HashSet(); - foreach (var e in span) - { - if (set.Add(e) == false) - { - return false; - } - } - return true; - } - #endregion - - #region EcsGroup - public static EcsGroup GetSourceInstance(EcsReadonlyGroup group) - { - return group.GetSource_Internal(); - } - #endregion - } -} - namespace DCFApixels.DragonECS.Core.Unchecked { public static class UncheckedUtility @@ -129,6 +62,14 @@ namespace DCFApixels.DragonECS.Core.Unchecked } #endregion + #region Unsafe Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe EcsUnsafeSpan CreateUnsafeSpan(short worldID, int* ptr, int length) + { + return new EcsUnsafeSpan(worldID, ptr, length); + } + #endregion + #region EcsGroup public static EcsGroup GetSourceInstance(EcsReadonlyGroup group) { diff --git a/src/entlong.cs b/src/entlong.cs index d5ab1ac..76c2516 100644 --- a/src/entlong.cs +++ b/src/entlong.cs @@ -116,6 +116,48 @@ namespace DCFApixels.DragonECS #endregion #region Constructors + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public entlong(EcsWorld world, int id) : this() + { + if (world == null) + { + _id = 0; + _gen = 0; + _world = 0; + } + else + { + _id = id; + _gen = world.GetGen(id); + _world = world.ID; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public entlong(int id, EcsWorld world) : this(world, id) { } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public entlong(EcsWorld world, entlong entity) : this() + { +#if DEBUG + if (world.ID != entity.WorldID) { Throw.ArgumentDifferentWorldsException(); } +#elif DRAGONECS_STABILITY_MODE + if (world.ID != entity.WorldID) { world = null; } +#endif + if (world == null) + { + _id = 0; + _gen = 0; + _world = 0; + } + else + { + _id = entity._id; + _gen = entity._gen; + _world = entity._world; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public entlong(entlong entity, EcsWorld world) : this(world, entity) { } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public entlong(int id, short gen, short world) : this() { @@ -128,12 +170,6 @@ namespace DCFApixels.DragonECS { _full = full; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static unsafe entlong NewUnsafe(long id, long gen, long world) - { - long x = id << 48 | gen << 32 | id; - return *(entlong*)&x; - } #endregion #region Unpacking Try @@ -155,6 +191,13 @@ namespace DCFApixels.DragonECS worldID = _world; return IsAlive; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetGen(out short gen) + { + gen = _gen; + return IsAlive; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryUnpack(out int id) @@ -192,17 +235,24 @@ namespace DCFApixels.DragonECS id = _id; return IsAlive; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryUnpack(EcsWorld world) + { + if (world.ID != _world) { return false; } + return world.IsAlive(_id, _gen); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryUnpack(EcsWorld world, out int id) { - if (world.ID != _world) { Throw.ArgumentDifferentWorldsException(); } + if (world.ID != _world) { id = EcsConsts.NULL_ENTITY_ID; return false; } id = _id; return world.IsAlive(_id, _gen); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryUnpack(EcsWorld world, out int id, out short gen) { - if (world.ID != _world) { Throw.ArgumentDifferentWorldsException(); } + if (world.ID != _world) { gen = 0; id = EcsConsts.NULL_ENTITY_ID; return false; } gen = _gen; id = _id; return world.IsAlive(_id, _gen); @@ -210,14 +260,14 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryUnpack(EcsMask mask, out int id) { - if (mask.WorldID != _world) { Throw.ArgumentDifferentWorldsException(); } + if (mask.WorldID != _world) { id = EcsConsts.NULL_ENTITY_ID; return false; } id = _id; return mask.World.IsAlive(_id, _gen) && mask.World.IsMatchesMask(mask, _id); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryUnpack(EcsMask mask, out int id, out short gen) { - if (mask.WorldID != _world) { Throw.ArgumentDifferentWorldsException(); } + if (mask.WorldID != _world) { gen = 0; id = EcsConsts.NULL_ENTITY_ID; return false; } gen = _gen; id = _id; return mask.World.IsAlive(_id, _gen) && mask.World.IsMatchesMask(mask, _id); @@ -225,14 +275,14 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryUnpack(EcsAspect aspect, out int id) { - if (aspect.World.ID != _world) { Throw.ArgumentDifferentWorldsException(); } + if (aspect.World.ID != _world) { id = EcsConsts.NULL_ENTITY_ID; return false; } id = _id; return aspect.World.IsAlive(_id, _gen) && aspect.IsMatches(_id); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryUnpack(EcsAspect aspect, out int id, out short gen) { - if (aspect.World.ID != _world) { Throw.ArgumentDifferentWorldsException(); } + if (aspect.World.ID != _world) { gen = 0; id = EcsConsts.NULL_ENTITY_ID; return false; } gen = _gen; id = _id; return aspect.World.IsAlive(_id, _gen) && aspect.IsMatches(_id); @@ -323,9 +373,39 @@ namespace DCFApixels.DragonECS id = _id; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Deconstruct(out int id, out short gen, out short worldID) { Unpack(out id, out gen, out worldID); } + public void Deconstruct(out int id, out short gen, out short worldID) + { +#if DEBUG + if (IsAlive == false) { Throw.Ent_ThrowIsNotAlive(this); } +#elif DRAGONECS_STABILITY_MODE + if (IsAlive == false) + { + worldID = EcsConsts.NULL_WORLD_ID; + gen = default; + id = EcsConsts.NULL_ENTITY_ID; + return; + } +#endif + worldID = _world; + gen = _gen; + id = _id; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Deconstruct(out int id, out EcsWorld world) { Unpack(out id, out world); } + public void Deconstruct(out int id, out EcsWorld world) + { +#if DEBUG + if (IsAlive == false) { Throw.Ent_ThrowIsNotAlive(this); } +#elif DRAGONECS_STABILITY_MODE + if (IsAlive == false) + { + world = EcsWorld.GetWorld(EcsConsts.NULL_WORLD_ID); + id = EcsConsts.NULL_ENTITY_ID; + return; + } +#endif + world = EcsWorld.GetWorld(_world); + id = _id; + } #endregion #region Unpacking Unchecked @@ -384,16 +464,10 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator entlong((EcsWorld world, int entityID) a) { return Combine_Internal(a.entityID, a.world); } - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static implicit operator entlong((entlong entity, EcsWorld world) a) { return Combine_Internal(a.entity._id, a.world); } - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static implicit operator entlong((EcsWorld world, entlong entity) a) { return Combine_Internal(a.entity._id, a.world); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static entlong Combine_Internal(int entityID, EcsWorld world) - { - return world == null ? new entlong(entityID, 0, 0) : world.GetEntityLong(entityID); - } + public static implicit operator entlong((entlong entity, EcsWorld world) a) { return Combine_Internal(a.entity, a.world); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator entlong((EcsWorld world, entlong entity) a) { return Combine_Internal(a.entity, a.world); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator long(entlong a) { return a._full; } @@ -405,6 +479,21 @@ namespace DCFApixels.DragonECS #region Other [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static entlong Combine_Internal(int entityID, EcsWorld world) + { + return world == null ? new entlong(entityID, 0, 0) : world.GetEntityLong(entityID); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static entlong Combine_Internal(entlong entity, EcsWorld world) + { +#if DEBUG + if (world.ID != entity.WorldID) { Throw.ArgumentDifferentWorldsException(); } +#elif DRAGONECS_STABILITY_MODE + if (world.ID != entity.WorldID) { return default; } +#endif + return entity; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private EcsWorld GetWorld_Internal() { #if DRAGONECS_STABILITY_MODE @@ -412,6 +501,7 @@ namespace DCFApixels.DragonECS #endif return EcsWorld.GetWorld(_world); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { return unchecked((int)_full) ^ (int)(_full >> 32); } [MethodImpl(MethodImplOptions.AggressiveInlining)]