1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108 |
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using Unity.Burst;
- using Unity.Collections.LowLevel.Unsafe;
- using Unity.Jobs;
- using Unity.Jobs.LowLevel.Unsafe;
- using Unity.Mathematics;
-
- namespace Unity.Collections
- {
- /// <summary>
- /// Extension methods for sorting collections.
- /// </summary>
- [GenerateTestsForBurstCompatibility]
- public static class NativeSortExtension
- {
- /// <summary>
- /// A comparer that uses IComparable.CompareTo(). For primitive types, this is an ascending sort.
- /// </summary>
- /// <typeparam name="T">Source type of elements</typeparam>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public struct DefaultComparer<T> : IComparer<T> where T : IComparable<T>
- {
- /// <summary>
- /// Compares two values.
- /// </summary>
- /// <param name="x">First value to compare.</param>
- /// <param name="y">Second value to compare.</param>
- /// <returns>A signed integer that denotes the relative values of `x` and `y`:
- /// 0 if they're equal, negative if `x < y`, and positive if `x > y`.</returns>
- public int Compare(T x, T y) => x.CompareTo(y);
- }
-
- /// <summary>
- /// Sorts an array in ascending order.
- /// </summary>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="array">The array to sort.</param>
- /// <param name="length">The number of elements to sort in the array.
- /// Indexes greater than or equal to `length` won't be included in the sort.</param>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public unsafe static void Sort<T>(T* array, int length)
- where T : unmanaged, IComparable<T>
- {
- IntroSort<T, DefaultComparer<T>>(array, length, new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Sorts an array using a custom comparison.
- /// </summary>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="array">The array to sort.</param>
- /// <param name="length">The number of elements to sort in the array.
- /// Indexes greater than or equal to `length` won't be included in the sort.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- public unsafe static void Sort<T, U>(T* array, int length, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- IntroSort<T, U>(array, length, comp);
- }
-
- /// <summary>
- /// Returns a job which will sort an array in ascending order.
- /// </summary>
- /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="array">The array to sort.</param>
- /// <param name="length">The number of elements to sort in the array.
- /// Indexes greater than or equal to `length` won't be included in the sort.</param>
- /// <returns>A job for sorting the array.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
- public unsafe static SortJob<T, DefaultComparer<T>> SortJob<T>(T* array, int length)
- where T : unmanaged, IComparable<T>
- {
- return new SortJob<T, DefaultComparer<T>> {Data = array, Length = length, Comp = new DefaultComparer<T>()};
- }
-
- /// <summary>
- /// Returns a job which will sort an array using a custom comparison.
- /// </summary>
- /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="array">The array to sort.</param>
- /// <param name="length">The number of elements to sort in the array.
- /// Indexes greater than or equal to `length` won't be included in the sort.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- /// <returns>A job for sorting the array.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
- public unsafe static SortJob<T, U> SortJob<T, U>(T* array, int length, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- CheckComparer(array, length, comp);
- return new SortJob<T, U>() {Data = array, Length = length, Comp = comp};
- }
-
- /// <summary>
- /// Finds a value in a sorted array by binary search.
- /// </summary>
- /// <remarks>If the array is not sorted, the value might not be found, even if it's present in the array.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="ptr">The array to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <param name="length">The number of elements to search. Indexes greater than or equal to `length` won't be searched.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public unsafe static int BinarySearch<T>(T* ptr, int length, T value)
- where T : unmanaged, IComparable<T>
- {
- return BinarySearch(ptr, length, value, new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Finds a value in a sorted array by binary search using a custom comparison.
- /// </summary>
- /// <remarks>If the array is not sorted, the value might not be found, even if it's present in the array.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="ptr">The array to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <param name="length">The number of elements to search. Indexes greater than or equal to `length` won't be searched.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- public unsafe static int BinarySearch<T, U>(T* ptr, int length, T value, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- CheckComparer(ptr, length, comp);
- var offset = 0;
-
- for (var l = length; l != 0; l >>= 1)
- {
- var idx = offset + (l >> 1);
- var curr = ptr[idx];
- var r = comp.Compare(value, curr);
- if (r == 0)
- {
- return idx;
- }
-
- if (r > 0)
- {
- offset = idx + 1;
- --l;
- }
- }
-
- return ~offset;
- }
-
- /// <summary>
- /// Sorts this array in ascending order.
- /// </summary>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="array">The array to sort.</param>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public unsafe static void Sort<T>(this NativeArray<T> array)
- where T : unmanaged, IComparable<T>
- {
- IntroSortStruct<T, DefaultComparer<T>>(array.GetUnsafePtr(), array.Length, new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Sorts this array using a custom comparison.
- /// </summary>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="array">The array to sort.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- public unsafe static void Sort<T, U>(this NativeArray<T> array, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- var ptr = (T*)array.GetUnsafePtr();
- var len = array.Length;
- CheckComparer(ptr, len, comp);
- IntroSortStruct<T, U>(ptr, len, comp);
- }
-
- /// <summary>
- /// Returns a job which will sort this array in ascending order.
- /// </summary>
- /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="array">The array to sort.</param>
- /// <returns>A job for sorting this array.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
- public unsafe static SortJob<T, DefaultComparer<T>> SortJob<T>(this NativeArray<T> array)
- where T : unmanaged, IComparable<T>
- {
- return SortJob((T*)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(array), array.Length, new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Returns a job which will sort this array using a custom comparison.
- /// </summary>
- /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="array">The array to sort.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- /// <returns>A job for sorting the array.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
- public unsafe static SortJob<T, U> SortJob<T, U>(this NativeArray<T> array, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- var ptr = (T*)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(array);
- var len = array.Length;
- CheckComparer(ptr, len, comp);
-
- return new SortJob<T, U>
- {
- Data = ptr,
- Length = len,
- Comp = comp
- };
- }
-
- /// <summary>
- /// Finds a value in this sorted array by binary search.
- /// </summary>
- /// <remarks>If the array is not sorted, the value might not be found, even if it's present in this array.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="array">The array to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public static int BinarySearch<T>(this NativeArray<T> array, T value)
- where T : unmanaged, IComparable<T>
- {
- return array.BinarySearch(value, new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Finds a value in this sorted array by binary search using a custom comparison.
- /// </summary>
- /// <remarks>If the array is not sorted, the value might not be found, even if it's present in this array.
- /// </remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The comparer type.</typeparam>
- /// <param name="array">The array to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- public unsafe static int BinarySearch<T, U>(this NativeArray<T> array, T value, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- return BinarySearch((T*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(array), array.Length, value, comp);
- }
-
- /// <summary>
- /// Finds a value in this sorted array by binary search.
- /// </summary>
- /// <remarks>If the array is not sorted, the value might not be found, even if it's present in this array.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="array">The array to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public static int BinarySearch<T>(this NativeArray<T>.ReadOnly array, T value)
- where T : unmanaged, IComparable<T>
- {
- return array.BinarySearch(value, new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Finds a value in this sorted array by binary search using a custom comparison.
- /// </summary>
- /// <remarks>If the array is not sorted, the value might not be found, even if it's present in this array.
- /// </remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The comparer type.</typeparam>
- /// <param name="array">The array to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- public unsafe static int BinarySearch<T, U>(this NativeArray<T>.ReadOnly array, T value, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- return BinarySearch((T*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(array), array.Length, value, comp);
- }
-
- /// <summary>
- /// Sorts this list in ascending order.
- /// </summary>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="list">The list to sort.</param>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public unsafe static void Sort<T>(this NativeList<T> list)
- where T : unmanaged, IComparable<T>
- {
- list.Sort(new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Sorts this list using a custom comparison.
- /// </summary>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="list">The list to sort.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- public unsafe static void Sort<T, U>(this NativeList<T> list, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- IntroSort<T, U>(list.GetUnsafePtr(), list.Length, comp);
- }
-
- /// <summary>
- /// Returns a job which will sort this list in ascending order.
- /// </summary>
- /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="list">The list to sort.</param>
- /// <returns>A job for sorting this list.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
- public unsafe static SortJob<T, DefaultComparer<T>> SortJob<T>(this NativeList<T> list)
- where T : unmanaged, IComparable<T>
- {
- return SortJob(list.GetUnsafePtr(), list.Length,new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Returns a job which will sort this list using a custom comparison.
- /// </summary>
- /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="list">The list to sort.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- /// <returns>A job for sorting this list.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
- public unsafe static SortJob<T, U> SortJob<T, U>(this NativeList<T> list, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- return SortJob(list.GetUnsafePtr(), list.Length, comp);
- }
-
- /// <summary>
- /// Finds a value in this sorted list by binary search.
- /// </summary>
- /// <remarks>If this list is not sorted, the value might not be found, even if it's present in this list.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="list">The list to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public static int BinarySearch<T>(this NativeList<T> list, T value)
- where T : unmanaged, IComparable<T>
- {
- return list.AsReadOnly().BinarySearch(value, new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Finds a value in this sorted list by binary search using a custom comparison.
- /// </summary>
- /// <remarks>If this list is not sorted, the value may not be found, even if it's present in this list.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="list">The list to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- public unsafe static int BinarySearch<T, U>(this NativeList<T> list, T value, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- return list.AsReadOnly().BinarySearch(value, comp);
- }
-
- /// <summary>
- /// Sorts this list in ascending order.
- /// </summary>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="list">The list to sort.</param>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public unsafe static void Sort<T>(this UnsafeList<T> list) where T : unmanaged, IComparable<T>
- {
- list.Sort(new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Sorts the list using a custom comparison.
- /// </summary>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="list">The list to sort.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- public unsafe static void Sort<T, U>(this UnsafeList<T> list, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- IntroSort<T, U>(list.Ptr, list.Length, comp);
- }
-
- /// <summary>
- /// Returns a job which will sort this list in ascending order.
- /// </summary>
- /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="list">The list to sort.</param>
- /// <returns>A job for sorting this list.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
- public unsafe static SortJob<T, DefaultComparer<T>> SortJob<T>(this UnsafeList<T> list)
- where T : unmanaged, IComparable<T>
- {
- return SortJob(list.Ptr, list.Length, new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Returns a job which will sort this list using a custom comparison.
- /// </summary>
- /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="list">The list to sort.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- /// <returns>A job for sorting this list.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
- public unsafe static SortJob<T, U> SortJob<T, U>(this UnsafeList<T> list, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- return SortJob(list.Ptr, list.Length, comp);
- }
-
- /// <summary>
- /// Finds a value in this sorted list by binary search.
- /// </summary>
- /// <remarks>If this list is not sorted, the value might not be found, even if it's present in this list.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="list">The list to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public static int BinarySearch<T>(this UnsafeList<T> list, T value)
- where T : unmanaged, IComparable<T>
- {
- return list.BinarySearch(value, new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Finds a value in this sorted list by binary search using a custom comparison.
- /// </summary>
- /// <remarks>If this list is not sorted, the value might not be found, even if it's present in this list.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="list">The list to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- public unsafe static int BinarySearch<T, U>(this UnsafeList<T> list, T value, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- return BinarySearch(list.Ptr, list.Length, value, comp);
- }
-
- /// <summary>
- /// Sorts this slice in ascending order.
- /// </summary>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="slice">The slice to sort.</param>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public unsafe static void Sort<T>(this NativeSlice<T> slice)
- where T : unmanaged, IComparable<T>
- {
- slice.Sort(new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Sorts this slice using a custom comparison.
- /// </summary>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="slice">The slice to sort.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- public unsafe static void Sort<T, U>(this NativeSlice<T> slice, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- var ptr = (T*)slice.GetUnsafePtr();
- var len = slice.Length;
- CheckComparer(ptr, len, comp);
-
- CheckStrideMatchesSize<T>(slice.Stride);
- IntroSortStruct<T, U>(ptr, len, comp);
- }
-
- /// <summary>
- /// Returns a job which will sort this slice in ascending order.
- /// </summary>
- /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="slice">The slice to sort.</param>
- /// <returns>A job for sorting this slice.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
- public unsafe static SortJob<T, DefaultComparer<T>> SortJob<T>(this NativeSlice<T> slice)
- where T : unmanaged, IComparable<T>
- {
- CheckStrideMatchesSize<T>(slice.Stride);
- return SortJob((T*)slice.GetUnsafePtr(), slice.Length, new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Returns a job which will sort this slice using a custom comparison.
- /// </summary>
- /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="slice">The slice to sort.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- /// <returns>A job for sorting this slice.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
- public unsafe static SortJob<T, U> SortJob<T, U>(this NativeSlice<T> slice, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- CheckStrideMatchesSize<T>(slice.Stride);
- return SortJob((T*)slice.GetUnsafePtr(), slice.Length, comp);
- }
-
- /// <summary>
- /// Finds a value in this sorted slice by binary search.
- /// </summary>
- /// <remarks>If this slice is not sorted, the value might not be found, even if it's present in this slice.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <param name="slice">The slice to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public static int BinarySearch<T>(this NativeSlice<T> slice, T value)
- where T : unmanaged, IComparable<T>
- {
- return slice.BinarySearch(value, new DefaultComparer<T>());
- }
-
- /// <summary>
- /// Finds a value in this sorted slice by binary search using a custom comparison.
- /// </summary>
- /// <remarks>If this slice is not sorted, the value might not be found, even if it's present in this slice.</remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- /// <param name="slice">The slice to search.</param>
- /// <param name="value">The value to locate.</param>
- /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
- /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- public unsafe static int BinarySearch<T, U>(this NativeSlice<T> slice, T value, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- return BinarySearch((T*)slice.GetUnsafeReadOnlyPtr(), slice.Length, value, comp);
- }
-
- /// -- Internals
-
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- unsafe internal static void IntroSort<T, U>(void* array, int length, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- CheckComparer((T*)array, length, comp);
- IntroSort_R<T, U>(array, 0, length - 1, 2 * CollectionHelper.Log2Floor(length), comp);
- }
-
- const int k_IntrosortSizeThreshold = 16;
-
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
- unsafe internal static void IntroSort_R<T, U>(void* array, int lo, int hi, int depth, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- while (hi > lo)
- {
- int partitionSize = hi - lo + 1;
- if (partitionSize <= k_IntrosortSizeThreshold)
- {
- if (partitionSize == 1)
- {
- return;
- }
- if (partitionSize == 2)
- {
- SwapIfGreaterWithItems<T, U>(array, lo, hi, comp);
- return;
- }
- if (partitionSize == 3)
- {
- SwapIfGreaterWithItems<T, U>(array, lo, hi - 1, comp);
- SwapIfGreaterWithItems<T, U>(array, lo, hi, comp);
- SwapIfGreaterWithItems<T, U>(array, hi - 1, hi, comp);
- return;
- }
-
- InsertionSort<T, U>(array, lo, hi, comp);
- return;
- }
-
- if (depth == 0)
- {
- HeapSort<T, U>(array, lo, hi, comp);
- return;
- }
- depth--;
-
- int p = Partition<T, U>(array, lo, hi, comp);
- IntroSort_R<T, U>(array, p + 1, hi, depth, comp);
- hi = p - 1;
- }
- }
-
- unsafe static void InsertionSort<T, U>(void* array, int lo, int hi, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- int i, j;
- T t;
- for (i = lo; i < hi; i++)
- {
- j = i;
-
- t = UnsafeUtility.ReadArrayElement<T>(array, i + 1);
- while (j >= lo && comp.Compare(t, UnsafeUtility.ReadArrayElement<T>(array, j)) < 0)
- {
- UnsafeUtility.WriteArrayElement(array, j + 1, UnsafeUtility.ReadArrayElement<T>(array, j));
- j--;
- }
-
- UnsafeUtility.WriteArrayElement(array, j + 1, t);
- }
- }
-
- unsafe static int Partition<T, U>(void* array, int lo, int hi, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- int mid = lo + ((hi - lo) / 2);
- SwapIfGreaterWithItems<T, U>(array, lo, mid, comp);
- SwapIfGreaterWithItems<T, U>(array, lo, hi, comp);
- SwapIfGreaterWithItems<T, U>(array, mid, hi, comp);
-
- T pivot = UnsafeUtility.ReadArrayElement<T>(array, mid);
- Swap<T>(array, mid, hi - 1);
- int left = lo, right = hi - 1;
-
- while (left < right)
- {
- while (left < hi && comp.Compare(pivot, UnsafeUtility.ReadArrayElement<T>(array, ++left)) > 0)
- {
- }
-
- while (right > left && comp.Compare(pivot, UnsafeUtility.ReadArrayElement<T>(array, --right)) < 0)
- {
- }
-
- if (left >= right)
- break;
-
- Swap<T>(array, left, right);
- }
-
- Swap<T>(array, left, (hi - 1));
- return left;
- }
-
- unsafe static void HeapSort<T, U>(void* array, int lo, int hi, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- int n = hi - lo + 1;
-
- for (int i = n / 2; i >= 1; i--)
- {
- Heapify<T, U>(array, i, n, lo, comp);
- }
-
- for (int i = n; i > 1; i--)
- {
- Swap<T>(array, lo, lo + i - 1);
- Heapify<T, U>(array, 1, i - 1, lo, comp);
- }
- }
-
- unsafe static void Heapify<T, U>(void* array, int i, int n, int lo, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- T val = UnsafeUtility.ReadArrayElement<T>(array, lo + i - 1);
- int child;
- while (i <= n / 2)
- {
- child = 2 * i;
-
- if (child < n && (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, lo + child - 1), UnsafeUtility.ReadArrayElement<T>(array, (lo + child))) < 0))
- {
- child++;
- }
-
- if (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, (lo + child - 1)), val) < 0)
- {
- break;
- }
-
- UnsafeUtility.WriteArrayElement(array, lo + i - 1, UnsafeUtility.ReadArrayElement<T>(array, lo + child - 1));
- i = child;
- }
-
- UnsafeUtility.WriteArrayElement(array, lo + i - 1, val);
- }
-
- unsafe static void Swap<T>(void* array, int lhs, int rhs) where T : unmanaged
- {
- T val = UnsafeUtility.ReadArrayElement<T>(array, lhs);
- UnsafeUtility.WriteArrayElement(array, lhs, UnsafeUtility.ReadArrayElement<T>(array, rhs));
- UnsafeUtility.WriteArrayElement(array, rhs, val);
- }
-
- unsafe static void SwapIfGreaterWithItems<T, U>(void* array, int lhs, int rhs, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- if (lhs != rhs)
- {
- if (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, lhs), UnsafeUtility.ReadArrayElement<T>(array, rhs)) > 0)
- {
- Swap<T>(array, lhs, rhs);
- }
- }
- }
-
- unsafe static void IntroSortStruct<T, U>(void* array, int length, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- IntroSortStruct_R<T, U>(array, 0, length - 1, 2 * CollectionHelper.Log2Floor(length), comp);
- }
-
- unsafe static void IntroSortStruct_R<T, U>(void* array, in int lo, in int _hi, int depth, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- var hi = _hi;
-
- while (hi > lo)
- {
- int partitionSize = hi - lo + 1;
- if (partitionSize <= k_IntrosortSizeThreshold)
- {
- if (partitionSize == 1)
- {
- return;
- }
- if (partitionSize == 2)
- {
- SwapIfGreaterWithItemsStruct<T, U>(array, lo, hi, comp);
- return;
- }
- if (partitionSize == 3)
- {
- SwapIfGreaterWithItemsStruct<T, U>(array, lo, hi - 1, comp);
- SwapIfGreaterWithItemsStruct<T, U>(array, lo, hi, comp);
- SwapIfGreaterWithItemsStruct<T, U>(array, hi - 1, hi, comp);
- return;
- }
-
- InsertionSortStruct<T, U>(array, lo, hi, comp);
- return;
- }
-
- if (depth == 0)
- {
- HeapSortStruct<T, U>(array, lo, hi, comp);
- return;
- }
- depth--;
-
- int p = PartitionStruct<T, U>(array, lo, hi, comp);
- IntroSortStruct_R<T, U>(array, p + 1, hi, depth, comp);
- hi = p - 1;
- }
- }
-
- unsafe static void InsertionSortStruct<T, U>(void* array, in int lo, in int hi, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- int i, j;
- T t;
- for (i = lo; i < hi; i++)
- {
- j = i;
- t = UnsafeUtility.ReadArrayElement<T>(array, i + 1);
- while (j >= lo && comp.Compare(t, UnsafeUtility.ReadArrayElement<T>(array, j)) < 0)
- {
- UnsafeUtility.WriteArrayElement(array, j + 1, UnsafeUtility.ReadArrayElement<T>(array, j));
- j--;
- }
- UnsafeUtility.WriteArrayElement(array, j + 1, t);
- }
- }
-
- unsafe static int PartitionStruct<T, U>(void* array, in int lo, in int hi, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- int mid = lo + ((hi - lo) / 2);
- SwapIfGreaterWithItemsStruct<T, U>(array, lo, mid, comp);
- SwapIfGreaterWithItemsStruct<T, U>(array, lo, hi, comp);
- SwapIfGreaterWithItemsStruct<T, U>(array, mid, hi, comp);
-
- T pivot = UnsafeUtility.ReadArrayElement<T>(array, mid);
- SwapStruct<T>(array, mid, hi - 1);
- int left = lo, right = hi - 1;
-
- while (left < right)
- {
- while (left < hi && comp.Compare(pivot, UnsafeUtility.ReadArrayElement<T>(array, ++left)) > 0)
- {
- }
-
- while (right > left && comp.Compare(pivot, UnsafeUtility.ReadArrayElement<T>(array, --right)) < 0)
- {
- }
-
- if (left >= right)
- break;
-
- SwapStruct<T>(array, left, right);
- }
-
- SwapStruct<T>(array, left, (hi - 1));
- return left;
- }
-
- unsafe static void HeapSortStruct<T, U>(void* array, in int lo, in int hi, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- int n = hi - lo + 1;
-
- for (int i = n / 2; i >= 1; i--)
- {
- HeapifyStruct<T, U>(array, i, n, lo, comp);
- }
-
- for (int i = n; i > 1; i--)
- {
- SwapStruct<T>(array, lo, lo + i - 1);
- HeapifyStruct<T, U>(array, 1, i - 1, lo, comp);
- }
- }
-
- unsafe static void HeapifyStruct<T, U>(void* array, int i, int n, in int lo, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- T val = UnsafeUtility.ReadArrayElement<T>(array, lo + i - 1);
- int child;
- while (i <= n / 2)
- {
- child = 2 * i;
-
- if (child < n && (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, lo + child - 1), UnsafeUtility.ReadArrayElement<T>(array, (lo + child))) < 0))
- {
- child++;
- }
-
- if (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, (lo + child - 1)), val) < 0)
- {
- break;
- }
-
- UnsafeUtility.WriteArrayElement(array, lo + i - 1, UnsafeUtility.ReadArrayElement<T>(array, lo + child - 1));
- i = child;
- }
-
- UnsafeUtility.WriteArrayElement(array, lo + i - 1, val);
- }
-
- unsafe static void SwapStruct<T>(void* array, int lhs, int rhs)
- where T : unmanaged
- {
- T val = UnsafeUtility.ReadArrayElement<T>(array, lhs);
- UnsafeUtility.WriteArrayElement(array, lhs, UnsafeUtility.ReadArrayElement<T>(array, rhs));
- UnsafeUtility.WriteArrayElement(array, rhs, val);
- }
-
- unsafe static void SwapIfGreaterWithItemsStruct<T, U>(void* array, int lhs, int rhs, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- if (lhs != rhs)
- {
- if (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, lhs), UnsafeUtility.ReadArrayElement<T>(array, rhs)) > 0)
- {
- SwapStruct<T>(array, lhs, rhs);
- }
- }
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
- static void CheckStrideMatchesSize<T>(int stride) where T : unmanaged
- {
- if (stride != UnsafeUtility.SizeOf<T>())
- {
- throw new InvalidOperationException("Sort requires that stride matches the size of the source type");
- }
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
- unsafe static void CheckComparer<T, U>(T* array, int length, U comp)
- where T : unmanaged
- where U : IComparer<T>
- {
- if (length > 0)
- {
- T a = array[0];
-
- if (0 != comp.Compare(a, a))
- {
- throw new InvalidOperationException("Comparison function is incorrect. Compare(a, a) must return 0/equal.");
- }
-
- for (int i = 1, len = math.min(length, 8); i < len; ++i)
- {
- T b = array[i];
-
- if (0 == comp.Compare(a, b) &&
- 0 == comp.Compare(b, a))
- {
- continue;
- }
-
- if (0 == comp.Compare(a, b))
- {
- throw new InvalidOperationException("Comparison function is incorrect. Compare(a, b) of two different values should not return 0/equal.");
- }
-
- if (0 == comp.Compare(b, a))
- {
- throw new InvalidOperationException("Comparison function is incorrect. Compare(b, a) of two different values should not return 0/equal.");
- }
-
- if (comp.Compare(a, b) == comp.Compare(b, a))
- {
- throw new InvalidOperationException("Comparison function is incorrect. Compare(a, b) when a and b are different values should not return the same value as Compare(b, a).");
- }
-
- break;
- }
- }
- }
- }
-
- /// <summary>
- /// Returned by the `SortJob` methods of <see cref="Unity.Collections.NativeSortExtension"/>. Call `Schedule` to schedule the sorting.
- /// </summary>
- /// <remarks>
- /// When `RegisterGenericJobType` is used on SortJob, to complete registration you must register `SortJob<T,U>.SegmentSort` and `SortJob<T,U>.SegmentSortMerge`.
- /// </remarks>
- /// <typeparam name="T">The type of the elements to sort.</typeparam>
- /// <typeparam name="U">The type of the comparer.</typeparam>
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(NativeSortExtension.DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
- public unsafe struct SortJob<T, U>
- where T : unmanaged
- where U : IComparer<T>
- {
- /// <summary>
- /// The data to sort.
- /// </summary>
- public T* Data;
-
- /// <summary>
- /// Comparison function.
- /// </summary>
- public U Comp;
-
- /// <summary>
- /// The length to sort.
- /// </summary>
- public int Length;
-
- /// <summary>
- /// <undoc />
- /// </summary>
- [BurstCompile]
- public struct SegmentSort : IJobParallelFor
- {
- [NativeDisableUnsafePtrRestriction]
- internal T* Data;
- internal U Comp;
-
- internal int Length;
- internal int SegmentWidth;
-
- /// <summary>
- /// <undoc />
- /// </summary>
- /// <param name="index"><undoc /></param>
- public void Execute(int index)
- {
- var startIndex = index * SegmentWidth;
- var segmentLength = ((Length - startIndex) < SegmentWidth) ? (Length - startIndex) : SegmentWidth;
- NativeSortExtension.Sort(Data + startIndex, segmentLength, Comp);
- }
- }
-
- /// <summary>
- /// <undoc />
- /// </summary>
- [BurstCompile]
- public struct SegmentSortMerge : IJob
- {
- [NativeDisableUnsafePtrRestriction]
- internal T* Data;
- internal U Comp;
-
- internal int Length;
- internal int SegmentWidth;
-
- /// <summary>
- /// <undoc />
- /// </summary>
- public void Execute()
- {
- var segmentCount = (Length + (SegmentWidth - 1)) / SegmentWidth;
- var segmentIndex = stackalloc int[segmentCount];
-
- var resultCopy = (T*)Memory.Unmanaged.Allocate(UnsafeUtility.SizeOf<T>() * Length, 16, Allocator.Temp);
-
- for (int sortIndex = 0; sortIndex < Length; sortIndex++)
- {
- // find next best
- int bestSegmentIndex = -1;
- T bestValue = default(T);
-
- for (int i = 0; i < segmentCount; i++)
- {
- var startIndex = i * SegmentWidth;
- var offset = segmentIndex[i];
- var segmentLength = ((Length - startIndex) < SegmentWidth) ? (Length - startIndex) : SegmentWidth;
- if (offset == segmentLength)
- continue;
-
- var nextValue = Data[startIndex + offset];
- if (bestSegmentIndex != -1)
- {
- if (Comp.Compare(nextValue, bestValue) > 0)
- continue;
- }
-
- bestValue = nextValue;
- bestSegmentIndex = i;
- }
-
- segmentIndex[bestSegmentIndex]++;
- resultCopy[sortIndex] = bestValue;
- }
-
- UnsafeUtility.MemCpy(Data, resultCopy, UnsafeUtility.SizeOf<T>() * Length);
- }
- }
-
- /// <summary>
- /// Schedules this job.
- /// </summary>
- /// <param name="inputDeps">Handle of a job to depend upon.</param>
- /// <returns>The handle of this newly scheduled job.</returns>
- public JobHandle Schedule(JobHandle inputDeps = default)
- {
- if (Length == 0)
- return inputDeps;
- var segmentCount = (Length + 1023) / 1024;
-
- #if UNITY_2022_2_14F1_OR_NEWER
- int maxThreadCount = JobsUtility.ThreadIndexCount;
- #else
- int maxThreadCount = JobsUtility.MaxJobThreadCount;
- #endif
- var workerCount = math.max(1, maxThreadCount);
- var workerSegmentCount = segmentCount / workerCount;
- var segmentSortJob = new SegmentSort { Data = Data, Comp = Comp, Length = Length, SegmentWidth = 1024 };
- var segmentSortJobHandle = segmentSortJob.Schedule(segmentCount, workerSegmentCount, inputDeps);
- var segmentSortMergeJob = new SegmentSortMerge { Data = Data, Comp = Comp, Length = Length, SegmentWidth = 1024 };
- var segmentSortMergeJobHandle = segmentSortMergeJob.Schedule(segmentSortJobHandle);
- return segmentSortMergeJobHandle;
- }
- }
- }
|