mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2026-04-21 17:35:56 +08:00
update internal
This commit is contained in:
parent
b686e4ab5f
commit
8472280d4b
@ -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<T> : IComparer<T>
|
||||
{
|
||||
// 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<T>
|
||||
{
|
||||
private const int IntrosortSizeThreshold = 16;
|
||||
|
||||
#region IStructComparer
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void SwapIfGreater<TComparer>(T[] items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer<T>
|
||||
{
|
||||
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<TComparer>(T[] items, ref TComparer comparer) where TComparer : IStructComparer<T>
|
||||
{
|
||||
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<TComparer>(T[] items, ref TComparer comparer) where TComparer : IStructComparer<T>
|
||||
{
|
||||
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<T> 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<T> 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<T> 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<T>
|
||||
{
|
||||
public static readonly ComparisonHach Instance = new ComparisonHach();
|
||||
public Comparison<T> comparison;
|
||||
private ComparisonHach() { }
|
||||
public int Compare(T x, T y) { return comparison(x, y); }
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Sort(T[] items, Comparison<T> comparison)
|
||||
{
|
||||
Sort(items, comparison, items.Length);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Sort(T[] items, Comparison<T> 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<T> where T : unmanaged
|
||||
{
|
||||
private const int IntrosortSizeThreshold = 16;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void SwapIfGreater<TComparer>(T* items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer<T>
|
||||
{
|
||||
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<TComparer>(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer<T>
|
||||
{
|
||||
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<TComparer>(T* items, int length, ref TComparer comparer) where TComparer : IComparerX<T>
|
||||
//{
|
||||
// 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<TComparer>(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer<T>
|
||||
{
|
||||
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<TComparer>(T* items, int length, ref TComparer comparer) where TComparer : IComparerX<T>
|
||||
//{
|
||||
// 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);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
246
src/Internal/ArraySortUtility.cs
Normal file
246
src/Internal/ArraySortUtility.cs
Normal file
@ -0,0 +1,246 @@
|
||||
#if DISABLE_DEBUG
|
||||
#undef DEBUG
|
||||
#endif
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
#if ENABLE_IL2CPP
|
||||
using Unity.IL2CPP.CompilerServices;
|
||||
#endif
|
||||
|
||||
namespace DCFApixels.DragonECS.Core.Internal
|
||||
{
|
||||
// a > b = return > 0
|
||||
// int Compare(T a, T b);
|
||||
|
||||
//IComparer<T> comparer
|
||||
//if (comparer == null)
|
||||
//{
|
||||
// comparer = Comparer<T>.Default;
|
||||
//}
|
||||
#if ENABLE_IL2CPP
|
||||
[Il2CppSetOption(Option.NullChecks, false)]
|
||||
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||
#endif
|
||||
internal static class ArraySortUtility<T, TComparer>
|
||||
where TComparer : struct, IComparer<T>
|
||||
{
|
||||
private const int IntrosortSizeThreshold = 16;
|
||||
|
||||
#region Public
|
||||
public static void Sort(Span<T> 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)
|
||||
{
|
||||
return InternalBinarySearch(array, index, length, value, ref comparer);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Internal
|
||||
internal static int InternalBinarySearch(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;
|
||||
}
|
||||
|
||||
private static void SwapIfGreater(Span<T> 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<T> a, int i, int j)
|
||||
{
|
||||
Debug.Assert(i != j);
|
||||
T t = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = t;
|
||||
}
|
||||
|
||||
internal static void IntrospectiveSort(Span<T> keys, ref TComparer comparer)
|
||||
{
|
||||
//Debug.Assert(comparer != null);
|
||||
if (keys.Length > 1)
|
||||
{
|
||||
IntroSort(keys, 2 * (BitOperations.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<T> 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<T> 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<T> keys, ref TComparer comparer)
|
||||
{
|
||||
//Debug.Assert(comparer != null);
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
|
||||
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<T> 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<T> 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
|
||||
}
|
||||
}
|
||||
@ -284,21 +284,26 @@ namespace DCFApixels.DragonECS.Core.Internal
|
||||
|
||||
internal static class SpanUtility
|
||||
{
|
||||
internal static StructComparison<T> ToStruct<T>(this Comparison<T> self)
|
||||
{
|
||||
return new StructComparison<T>(self);
|
||||
}
|
||||
public static void Sort<T>(Span<T> span, Comparison<T> comparison)
|
||||
{
|
||||
span.Sort(new StructComparison<T>(comparison));
|
||||
var c = comparison.ToStruct();
|
||||
ArraySortUtility<T, StructComparison<T>>.Sort(span, ref c);
|
||||
}
|
||||
private readonly struct StructComparison<T> : IComparer<T>
|
||||
}
|
||||
internal readonly struct StructComparison<T> : IComparer<T>
|
||||
{
|
||||
public readonly Comparison<T> Comparison;
|
||||
public StructComparison(Comparison<T> comparison)
|
||||
{
|
||||
public readonly Comparison<T> Comparison;
|
||||
public StructComparison(Comparison<T> comparison)
|
||||
{
|
||||
Comparison = comparison;
|
||||
}
|
||||
public int Compare(T x, T y)
|
||||
{
|
||||
return Comparison(x, y);
|
||||
}
|
||||
Comparison = comparison;
|
||||
}
|
||||
public int Compare(T x, T y)
|
||||
{
|
||||
return Comparison(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user