diff --git a/src/EcsMask.cs b/src/EcsMask.cs index 5fc3554..4e6a2db 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; @@ -644,7 +643,7 @@ namespace DCFApixels.DragonECS if (_sortIncChunckBuffer.Length > 1) { - sortIncBuffer.AsSpan().Sort(new IncCountComparer(counts)); + ArraySortUtility.Sort(sortIncBuffer.AsSpan(), new IncCountComparer(counts)); ConvertToChuncks(preSortingBuffer, sortIncBuffer, _sortIncChunckBuffer); } if (_sortIncChunckBuffer.Length > 0) @@ -658,7 +657,7 @@ namespace DCFApixels.DragonECS if (_sortExcChunckBuffer.Length > 1) { - sortExcBuffer.AsSpan().Sort(new ExcCountComparer(counts)); + ArraySortUtility.Sort(sortExcBuffer.AsSpan(), new ExcCountComparer(counts)); ConvertToChuncks(preSortingBuffer, sortExcBuffer, _sortExcChunckBuffer); } // Выражение IncCount < (AllEntitesCount - ExcCount) мало вероятно будет истинным. @@ -668,7 +667,7 @@ namespace DCFApixels.DragonECS if (_sortAnyChunckBuffer.Length > 1) { - sortAnyBuffer.AsSpan().Sort(new ExcCountComparer(counts)); + ArraySortUtility.Sort(sortAnyBuffer.AsSpan(), new ExcCountComparer(counts)); ConvertToChuncks(preSortingBuffer, sortAnyBuffer, _sortAnyChunckBuffer); } // Any не влияет на maxEntites если есть Inc и сложно высчитывается если нет Inc diff --git a/src/Executors/EcsWhereExecutor.cs b/src/Executors/EcsWhereExecutor.cs index e0949ba..8889fd2 100644 --- a/src/Executors/EcsWhereExecutor.cs +++ b/src/Executors/EcsWhereExecutor.cs @@ -146,8 +146,7 @@ namespace DCFApixels.DragonECS.Core.Internal public EcsUnsafeSpan Execute(Comparison comparison) { Execute_Iternal(); - Span result = _filteredAllEntities.AsSpan(_filteredAllEntitiesCount); - result.Sort(comparison); + ArraySortUtility.Sort(_filteredAllEntities.AsSpan(_filteredAllEntitiesCount), comparison); return new EcsUnsafeSpan(World.ID, _filteredAllEntities.Ptr, _filteredAllEntitiesCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -158,8 +157,7 @@ namespace DCFApixels.DragonECS.Core.Internal return Execute(comparison); } ExecuteFor_Iternal(source); - Span result = _filteredEntities.AsSpan(_filteredEntitiesCount); - result.Sort(comparison); + ArraySortUtility.Sort(_filteredEntities.AsSpan(_filteredEntitiesCount), comparison); return new EcsUnsafeSpan(World.ID, _filteredEntities.Ptr, _filteredEntitiesCount); } #endregion diff --git a/src/Internal/Allocators/MemoryAllocator.cs b/src/Internal/Allocators/MemoryAllocator.cs index 5634461..810b1c5 100644 --- a/src/Internal/Allocators/MemoryAllocator.cs +++ b/src/Internal/Allocators/MemoryAllocator.cs @@ -180,6 +180,11 @@ namespace DCFApixels.DragonECS.Core.Internal { 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 { diff --git a/src/Internal/ArraySortUtility.cs b/src/Internal/ArraySortUtility.cs index 4a8afbe..b1cd975 100644 --- a/src/Internal/ArraySortUtility.cs +++ b/src/Internal/ArraySortUtility.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Numerics; using System.Runtime.CompilerServices; #if ENABLE_IL2CPP using Unity.IL2CPP.CompilerServices; @@ -16,17 +15,89 @@ namespace DCFApixels.DragonECS.Core.Internal [Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif - internal static class ArraySortUtility + internal static unsafe class ArraySortUtility { internal static StructComparison ToStruct(this Comparison self) { return new StructComparison(self); } + internal static StructComparer ToStruct(this Comparer self) + { + return new StructComparer(self); + } + public static void Sort(Span span) + { + var c = Comparer.Default.ToStruct(); + ArraySortUtility>.Sort(span, ref c); + } + public static void Sort(Span span, Comparer comparer) + { + var c = comparer.ToStruct(); + ArraySortUtility>.Sort(span, ref c); + } public static void Sort(Span span, Comparison comparison) { var c = comparison.ToStruct(); ArraySortUtility>.Sort(span, ref c); } + public static void Sort(Span span, ref TComparer comparer) + where TComparer : struct, IComparer + { + ArraySortUtility.Sort(span, ref comparer); + } + public static void Sort(Span span, TComparer comparer) + where TComparer : struct, IComparer + { + ArraySortUtility.Sort(span, ref comparer); + } + + + // Таблица для 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 + //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); + } + } } #if ENABLE_IL2CPP [Il2CppSetOption(Option.NullChecks, false)] @@ -44,6 +115,18 @@ namespace DCFApixels.DragonECS.Core.Internal return Comparison(x, y); } } + internal readonly struct StructComparer : IComparer + { + public readonly Comparer Comparer; + public StructComparer(Comparer comparer) + { + Comparer = comparer; + } + public int Compare(T x, T y) + { + return Comparer.Compare(x, y); + } + } // a > b = return > 0 // int Compare(T a, T b); @@ -126,7 +209,7 @@ namespace DCFApixels.DragonECS.Core.Internal //Debug.Assert(comparer != null); if (keys.Length > 1) { - IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1), ref comparer); + IntroSort(keys, 2 * (ArraySortUtility.Log2((uint)keys.Length) + 1), ref comparer); } } diff --git a/src/Internal/ArraySortHalperX.cs.meta b/src/Internal/ArraySortUtility.cs.meta similarity index 83% rename from src/Internal/ArraySortHalperX.cs.meta rename to src/Internal/ArraySortUtility.cs.meta index 0805127..67e3b2f 100644 --- a/src/Internal/ArraySortHalperX.cs.meta +++ b/src/Internal/ArraySortUtility.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a591de1858028504d819333121bfddd6 +guid: fe9273da3e82bfd48983415b1726aed1 MonoImporter: externalObjects: {} serializedVersion: 2