No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

NativeSort.cs 50KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using Unity.Burst;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. using Unity.Jobs;
  7. using Unity.Jobs.LowLevel.Unsafe;
  8. using Unity.Mathematics;
  9. namespace Unity.Collections
  10. {
  11. /// <summary>
  12. /// Extension methods for sorting collections.
  13. /// </summary>
  14. [GenerateTestsForBurstCompatibility]
  15. public static class NativeSortExtension
  16. {
  17. /// <summary>
  18. /// A comparer that uses IComparable.CompareTo(). For primitive types, this is an ascending sort.
  19. /// </summary>
  20. /// <typeparam name="T">Source type of elements</typeparam>
  21. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  22. public struct DefaultComparer<T> : IComparer<T> where T : IComparable<T>
  23. {
  24. /// <summary>
  25. /// Compares two values.
  26. /// </summary>
  27. /// <param name="x">First value to compare.</param>
  28. /// <param name="y">Second value to compare.</param>
  29. /// <returns>A signed integer that denotes the relative values of `x` and `y`:
  30. /// 0 if they're equal, negative if `x &lt; y`, and positive if `x &gt; y`.</returns>
  31. public int Compare(T x, T y) => x.CompareTo(y);
  32. }
  33. /// <summary>
  34. /// Sorts an array in ascending order.
  35. /// </summary>
  36. /// <typeparam name="T">The type of the elements.</typeparam>
  37. /// <param name="array">The array to sort.</param>
  38. /// <param name="length">The number of elements to sort in the array.
  39. /// Indexes greater than or equal to `length` won't be included in the sort.</param>
  40. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  41. public unsafe static void Sort<T>(T* array, int length)
  42. where T : unmanaged, IComparable<T>
  43. {
  44. IntroSort<T, DefaultComparer<T>>(array, length, new DefaultComparer<T>());
  45. }
  46. /// <summary>
  47. /// Sorts an array using a custom comparison.
  48. /// </summary>
  49. /// <typeparam name="T">The type of the elements.</typeparam>
  50. /// <typeparam name="U">The type of the comparer.</typeparam>
  51. /// <param name="array">The array to sort.</param>
  52. /// <param name="length">The number of elements to sort in the array.
  53. /// Indexes greater than or equal to `length` won't be included in the sort.</param>
  54. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  55. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  56. public unsafe static void Sort<T, U>(T* array, int length, U comp)
  57. where T : unmanaged
  58. where U : IComparer<T>
  59. {
  60. IntroSort<T, U>(array, length, comp);
  61. }
  62. /// <summary>
  63. /// Returns a job which will sort an array in ascending order.
  64. /// </summary>
  65. /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
  66. /// <typeparam name="T">The type of the elements.</typeparam>
  67. /// <param name="array">The array to sort.</param>
  68. /// <param name="length">The number of elements to sort in the array.
  69. /// Indexes greater than or equal to `length` won't be included in the sort.</param>
  70. /// <returns>A job for sorting the array.</returns>
  71. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
  72. public unsafe static SortJob<T, DefaultComparer<T>> SortJob<T>(T* array, int length)
  73. where T : unmanaged, IComparable<T>
  74. {
  75. return new SortJob<T, DefaultComparer<T>> {Data = array, Length = length, Comp = new DefaultComparer<T>()};
  76. }
  77. /// <summary>
  78. /// Returns a job which will sort an array using a custom comparison.
  79. /// </summary>
  80. /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
  81. /// <typeparam name="T">The type of the elements.</typeparam>
  82. /// <typeparam name="U">The type of the comparer.</typeparam>
  83. /// <param name="array">The array to sort.</param>
  84. /// <param name="length">The number of elements to sort in the array.
  85. /// Indexes greater than or equal to `length` won't be included in the sort.</param>
  86. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  87. /// <returns>A job for sorting the array.</returns>
  88. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
  89. public unsafe static SortJob<T, U> SortJob<T, U>(T* array, int length, U comp)
  90. where T : unmanaged
  91. where U : IComparer<T>
  92. {
  93. CheckComparer(array, length, comp);
  94. return new SortJob<T, U>() {Data = array, Length = length, Comp = comp};
  95. }
  96. /// <summary>
  97. /// Finds a value in a sorted array by binary search.
  98. /// </summary>
  99. /// <remarks>If the array is not sorted, the value might not be found, even if it's present in the array.</remarks>
  100. /// <typeparam name="T">The type of the elements.</typeparam>
  101. /// <param name="ptr">The array to search.</param>
  102. /// <param name="value">The value to locate.</param>
  103. /// <param name="length">The number of elements to search. Indexes greater than or equal to `length` won't be searched.</param>
  104. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  105. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  106. public unsafe static int BinarySearch<T>(T* ptr, int length, T value)
  107. where T : unmanaged, IComparable<T>
  108. {
  109. return BinarySearch(ptr, length, value, new DefaultComparer<T>());
  110. }
  111. /// <summary>
  112. /// Finds a value in a sorted array by binary search using a custom comparison.
  113. /// </summary>
  114. /// <remarks>If the array is not sorted, the value might not be found, even if it's present in the array.</remarks>
  115. /// <typeparam name="T">The type of the elements.</typeparam>
  116. /// <typeparam name="U">The type of the comparer.</typeparam>
  117. /// <param name="ptr">The array to search.</param>
  118. /// <param name="value">The value to locate.</param>
  119. /// <param name="length">The number of elements to search. Indexes greater than or equal to `length` won't be searched.</param>
  120. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  121. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  122. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  123. public unsafe static int BinarySearch<T, U>(T* ptr, int length, T value, U comp)
  124. where T : unmanaged
  125. where U : IComparer<T>
  126. {
  127. CheckComparer(ptr, length, comp);
  128. var offset = 0;
  129. for (var l = length; l != 0; l >>= 1)
  130. {
  131. var idx = offset + (l >> 1);
  132. var curr = ptr[idx];
  133. var r = comp.Compare(value, curr);
  134. if (r == 0)
  135. {
  136. return idx;
  137. }
  138. if (r > 0)
  139. {
  140. offset = idx + 1;
  141. --l;
  142. }
  143. }
  144. return ~offset;
  145. }
  146. /// <summary>
  147. /// Sorts this array in ascending order.
  148. /// </summary>
  149. /// <typeparam name="T">The type of the elements.</typeparam>
  150. /// <param name="array">The array to sort.</param>
  151. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  152. public unsafe static void Sort<T>(this NativeArray<T> array)
  153. where T : unmanaged, IComparable<T>
  154. {
  155. IntroSortStruct<T, DefaultComparer<T>>(array.GetUnsafePtr(), array.Length, new DefaultComparer<T>());
  156. }
  157. /// <summary>
  158. /// Sorts this array using a custom comparison.
  159. /// </summary>
  160. /// <typeparam name="T">The type of the elements.</typeparam>
  161. /// <typeparam name="U">The type of the comparer.</typeparam>
  162. /// <param name="array">The array to sort.</param>
  163. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  164. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  165. public unsafe static void Sort<T, U>(this NativeArray<T> array, U comp)
  166. where T : unmanaged
  167. where U : IComparer<T>
  168. {
  169. var ptr = (T*)array.GetUnsafePtr();
  170. var len = array.Length;
  171. CheckComparer(ptr, len, comp);
  172. IntroSortStruct<T, U>(ptr, len, comp);
  173. }
  174. /// <summary>
  175. /// Returns a job which will sort this array in ascending order.
  176. /// </summary>
  177. /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
  178. /// <typeparam name="T">The type of the elements.</typeparam>
  179. /// <param name="array">The array to sort.</param>
  180. /// <returns>A job for sorting this array.</returns>
  181. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
  182. public unsafe static SortJob<T, DefaultComparer<T>> SortJob<T>(this NativeArray<T> array)
  183. where T : unmanaged, IComparable<T>
  184. {
  185. return SortJob((T*)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(array), array.Length, new DefaultComparer<T>());
  186. }
  187. /// <summary>
  188. /// Returns a job which will sort this array using a custom comparison.
  189. /// </summary>
  190. /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
  191. /// <typeparam name="T">The type of the elements.</typeparam>
  192. /// <typeparam name="U">The type of the comparer.</typeparam>
  193. /// <param name="array">The array to sort.</param>
  194. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  195. /// <returns>A job for sorting the array.</returns>
  196. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
  197. public unsafe static SortJob<T, U> SortJob<T, U>(this NativeArray<T> array, U comp)
  198. where T : unmanaged
  199. where U : IComparer<T>
  200. {
  201. var ptr = (T*)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(array);
  202. var len = array.Length;
  203. CheckComparer(ptr, len, comp);
  204. return new SortJob<T, U>
  205. {
  206. Data = ptr,
  207. Length = len,
  208. Comp = comp
  209. };
  210. }
  211. /// <summary>
  212. /// Finds a value in this sorted array by binary search.
  213. /// </summary>
  214. /// <remarks>If the array is not sorted, the value might not be found, even if it's present in this array.</remarks>
  215. /// <typeparam name="T">The type of the elements.</typeparam>
  216. /// <param name="array">The array to search.</param>
  217. /// <param name="value">The value to locate.</param>
  218. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  219. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  220. public static int BinarySearch<T>(this NativeArray<T> array, T value)
  221. where T : unmanaged, IComparable<T>
  222. {
  223. return array.BinarySearch(value, new DefaultComparer<T>());
  224. }
  225. /// <summary>
  226. /// Finds a value in this sorted array by binary search using a custom comparison.
  227. /// </summary>
  228. /// <remarks>If the array is not sorted, the value might not be found, even if it's present in this array.
  229. /// </remarks>
  230. /// <typeparam name="T">The type of the elements.</typeparam>
  231. /// <typeparam name="U">The comparer type.</typeparam>
  232. /// <param name="array">The array to search.</param>
  233. /// <param name="value">The value to locate.</param>
  234. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  235. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  236. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  237. public unsafe static int BinarySearch<T, U>(this NativeArray<T> array, T value, U comp)
  238. where T : unmanaged
  239. where U : IComparer<T>
  240. {
  241. return BinarySearch((T*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(array), array.Length, value, comp);
  242. }
  243. /// <summary>
  244. /// Finds a value in this sorted array by binary search.
  245. /// </summary>
  246. /// <remarks>If the array is not sorted, the value might not be found, even if it's present in this array.</remarks>
  247. /// <typeparam name="T">The type of the elements.</typeparam>
  248. /// <param name="array">The array to search.</param>
  249. /// <param name="value">The value to locate.</param>
  250. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  251. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  252. public static int BinarySearch<T>(this NativeArray<T>.ReadOnly array, T value)
  253. where T : unmanaged, IComparable<T>
  254. {
  255. return array.BinarySearch(value, new DefaultComparer<T>());
  256. }
  257. /// <summary>
  258. /// Finds a value in this sorted array by binary search using a custom comparison.
  259. /// </summary>
  260. /// <remarks>If the array is not sorted, the value might not be found, even if it's present in this array.
  261. /// </remarks>
  262. /// <typeparam name="T">The type of the elements.</typeparam>
  263. /// <typeparam name="U">The comparer type.</typeparam>
  264. /// <param name="array">The array to search.</param>
  265. /// <param name="value">The value to locate.</param>
  266. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  267. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  268. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  269. public unsafe static int BinarySearch<T, U>(this NativeArray<T>.ReadOnly array, T value, U comp)
  270. where T : unmanaged
  271. where U : IComparer<T>
  272. {
  273. return BinarySearch((T*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(array), array.Length, value, comp);
  274. }
  275. /// <summary>
  276. /// Sorts this list in ascending order.
  277. /// </summary>
  278. /// <typeparam name="T">The type of the elements.</typeparam>
  279. /// <param name="list">The list to sort.</param>
  280. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  281. public unsafe static void Sort<T>(this NativeList<T> list)
  282. where T : unmanaged, IComparable<T>
  283. {
  284. list.Sort(new DefaultComparer<T>());
  285. }
  286. /// <summary>
  287. /// Sorts this list using a custom comparison.
  288. /// </summary>
  289. /// <typeparam name="T">The type of the elements.</typeparam>
  290. /// <typeparam name="U">The type of the comparer.</typeparam>
  291. /// <param name="list">The list to sort.</param>
  292. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  293. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  294. public unsafe static void Sort<T, U>(this NativeList<T> list, U comp)
  295. where T : unmanaged
  296. where U : IComparer<T>
  297. {
  298. IntroSort<T, U>(list.GetUnsafePtr(), list.Length, comp);
  299. }
  300. /// <summary>
  301. /// Returns a job which will sort this list in ascending order.
  302. /// </summary>
  303. /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
  304. /// <typeparam name="T">The type of the elements.</typeparam>
  305. /// <param name="list">The list to sort.</param>
  306. /// <returns>A job for sorting this list.</returns>
  307. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
  308. public unsafe static SortJob<T, DefaultComparer<T>> SortJob<T>(this NativeList<T> list)
  309. where T : unmanaged, IComparable<T>
  310. {
  311. return SortJob(list.GetUnsafePtr(), list.Length,new DefaultComparer<T>());
  312. }
  313. /// <summary>
  314. /// Returns a job which will sort this list using a custom comparison.
  315. /// </summary>
  316. /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
  317. /// <typeparam name="T">The type of the elements.</typeparam>
  318. /// <typeparam name="U">The type of the comparer.</typeparam>
  319. /// <param name="list">The list to sort.</param>
  320. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  321. /// <returns>A job for sorting this list.</returns>
  322. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
  323. public unsafe static SortJob<T, U> SortJob<T, U>(this NativeList<T> list, U comp)
  324. where T : unmanaged
  325. where U : IComparer<T>
  326. {
  327. return SortJob(list.GetUnsafePtr(), list.Length, comp);
  328. }
  329. /// <summary>
  330. /// Finds a value in this sorted list by binary search.
  331. /// </summary>
  332. /// <remarks>If this list is not sorted, the value might not be found, even if it's present in this list.</remarks>
  333. /// <typeparam name="T">The type of the elements.</typeparam>
  334. /// <param name="list">The list to search.</param>
  335. /// <param name="value">The value to locate.</param>
  336. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  337. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  338. public static int BinarySearch<T>(this NativeList<T> list, T value)
  339. where T : unmanaged, IComparable<T>
  340. {
  341. return list.AsReadOnly().BinarySearch(value, new DefaultComparer<T>());
  342. }
  343. /// <summary>
  344. /// Finds a value in this sorted list by binary search using a custom comparison.
  345. /// </summary>
  346. /// <remarks>If this list is not sorted, the value may not be found, even if it's present in this list.</remarks>
  347. /// <typeparam name="T">The type of the elements.</typeparam>
  348. /// <typeparam name="U">The type of the comparer.</typeparam>
  349. /// <param name="list">The list to search.</param>
  350. /// <param name="value">The value to locate.</param>
  351. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  352. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  353. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  354. public unsafe static int BinarySearch<T, U>(this NativeList<T> list, T value, U comp)
  355. where T : unmanaged
  356. where U : IComparer<T>
  357. {
  358. return list.AsReadOnly().BinarySearch(value, comp);
  359. }
  360. /// <summary>
  361. /// Sorts this list in ascending order.
  362. /// </summary>
  363. /// <typeparam name="T">The type of the elements.</typeparam>
  364. /// <param name="list">The list to sort.</param>
  365. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  366. public unsafe static void Sort<T>(this UnsafeList<T> list) where T : unmanaged, IComparable<T>
  367. {
  368. list.Sort(new DefaultComparer<T>());
  369. }
  370. /// <summary>
  371. /// Sorts the list using a custom comparison.
  372. /// </summary>
  373. /// <typeparam name="T">The type of the elements.</typeparam>
  374. /// <typeparam name="U">The type of the comparer.</typeparam>
  375. /// <param name="list">The list to sort.</param>
  376. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  377. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  378. public unsafe static void Sort<T, U>(this UnsafeList<T> list, U comp)
  379. where T : unmanaged
  380. where U : IComparer<T>
  381. {
  382. IntroSort<T, U>(list.Ptr, list.Length, comp);
  383. }
  384. /// <summary>
  385. /// Returns a job which will sort this list in ascending order.
  386. /// </summary>
  387. /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
  388. /// <typeparam name="T">The type of the elements.</typeparam>
  389. /// <param name="list">The list to sort.</param>
  390. /// <returns>A job for sorting this list.</returns>
  391. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
  392. public unsafe static SortJob<T, DefaultComparer<T>> SortJob<T>(this UnsafeList<T> list)
  393. where T : unmanaged, IComparable<T>
  394. {
  395. return SortJob(list.Ptr, list.Length, new DefaultComparer<T>());
  396. }
  397. /// <summary>
  398. /// Returns a job which will sort this list using a custom comparison.
  399. /// </summary>
  400. /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
  401. /// <typeparam name="T">The type of the elements.</typeparam>
  402. /// <typeparam name="U">The type of the comparer.</typeparam>
  403. /// <param name="list">The list to sort.</param>
  404. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  405. /// <returns>A job for sorting this list.</returns>
  406. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
  407. public unsafe static SortJob<T, U> SortJob<T, U>(this UnsafeList<T> list, U comp)
  408. where T : unmanaged
  409. where U : IComparer<T>
  410. {
  411. return SortJob(list.Ptr, list.Length, comp);
  412. }
  413. /// <summary>
  414. /// Finds a value in this sorted list by binary search.
  415. /// </summary>
  416. /// <remarks>If this list is not sorted, the value might not be found, even if it's present in this list.</remarks>
  417. /// <typeparam name="T">The type of the elements.</typeparam>
  418. /// <param name="list">The list to search.</param>
  419. /// <param name="value">The value to locate.</param>
  420. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  421. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  422. public static int BinarySearch<T>(this UnsafeList<T> list, T value)
  423. where T : unmanaged, IComparable<T>
  424. {
  425. return list.BinarySearch(value, new DefaultComparer<T>());
  426. }
  427. /// <summary>
  428. /// Finds a value in this sorted list by binary search using a custom comparison.
  429. /// </summary>
  430. /// <remarks>If this list is not sorted, the value might not be found, even if it's present in this list.</remarks>
  431. /// <typeparam name="T">The type of the elements.</typeparam>
  432. /// <typeparam name="U">The type of the comparer.</typeparam>
  433. /// <param name="list">The list to search.</param>
  434. /// <param name="value">The value to locate.</param>
  435. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  436. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  437. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  438. public unsafe static int BinarySearch<T, U>(this UnsafeList<T> list, T value, U comp)
  439. where T : unmanaged
  440. where U : IComparer<T>
  441. {
  442. return BinarySearch(list.Ptr, list.Length, value, comp);
  443. }
  444. /// <summary>
  445. /// Sorts this slice in ascending order.
  446. /// </summary>
  447. /// <typeparam name="T">The type of the elements.</typeparam>
  448. /// <param name="slice">The slice to sort.</param>
  449. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  450. public unsafe static void Sort<T>(this NativeSlice<T> slice)
  451. where T : unmanaged, IComparable<T>
  452. {
  453. slice.Sort(new DefaultComparer<T>());
  454. }
  455. /// <summary>
  456. /// Sorts this slice using a custom comparison.
  457. /// </summary>
  458. /// <typeparam name="T">The type of the elements.</typeparam>
  459. /// <typeparam name="U">The type of the comparer.</typeparam>
  460. /// <param name="slice">The slice to sort.</param>
  461. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  462. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  463. public unsafe static void Sort<T, U>(this NativeSlice<T> slice, U comp)
  464. where T : unmanaged
  465. where U : IComparer<T>
  466. {
  467. var ptr = (T*)slice.GetUnsafePtr();
  468. var len = slice.Length;
  469. CheckComparer(ptr, len, comp);
  470. CheckStrideMatchesSize<T>(slice.Stride);
  471. IntroSortStruct<T, U>(ptr, len, comp);
  472. }
  473. /// <summary>
  474. /// Returns a job which will sort this slice in ascending order.
  475. /// </summary>
  476. /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
  477. /// <typeparam name="T">The type of the elements.</typeparam>
  478. /// <param name="slice">The slice to sort.</param>
  479. /// <returns>A job for sorting this slice.</returns>
  480. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
  481. public unsafe static SortJob<T, DefaultComparer<T>> SortJob<T>(this NativeSlice<T> slice)
  482. where T : unmanaged, IComparable<T>
  483. {
  484. CheckStrideMatchesSize<T>(slice.Stride);
  485. return SortJob((T*)slice.GetUnsafePtr(), slice.Length, new DefaultComparer<T>());
  486. }
  487. /// <summary>
  488. /// Returns a job which will sort this slice using a custom comparison.
  489. /// </summary>
  490. /// <remarks>This method does not schedule the job. Scheduling the job is left to you.</remarks>
  491. /// <typeparam name="T">The type of the elements.</typeparam>
  492. /// <typeparam name="U">The type of the comparer.</typeparam>
  493. /// <param name="slice">The slice to sort.</param>
  494. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  495. /// <returns>A job for sorting this slice.</returns>
  496. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
  497. public unsafe static SortJob<T, U> SortJob<T, U>(this NativeSlice<T> slice, U comp)
  498. where T : unmanaged
  499. where U : IComparer<T>
  500. {
  501. CheckStrideMatchesSize<T>(slice.Stride);
  502. return SortJob((T*)slice.GetUnsafePtr(), slice.Length, comp);
  503. }
  504. /// <summary>
  505. /// Finds a value in this sorted slice by binary search.
  506. /// </summary>
  507. /// <remarks>If this slice is not sorted, the value might not be found, even if it's present in this slice.</remarks>
  508. /// <typeparam name="T">The type of the elements.</typeparam>
  509. /// <param name="slice">The slice to search.</param>
  510. /// <param name="value">The value to locate.</param>
  511. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  512. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
  513. public static int BinarySearch<T>(this NativeSlice<T> slice, T value)
  514. where T : unmanaged, IComparable<T>
  515. {
  516. return slice.BinarySearch(value, new DefaultComparer<T>());
  517. }
  518. /// <summary>
  519. /// Finds a value in this sorted slice by binary search using a custom comparison.
  520. /// </summary>
  521. /// <remarks>If this slice is not sorted, the value might not be found, even if it's present in this slice.</remarks>
  522. /// <typeparam name="T">The type of the elements.</typeparam>
  523. /// <typeparam name="U">The type of the comparer.</typeparam>
  524. /// <param name="slice">The slice to search.</param>
  525. /// <param name="value">The value to locate.</param>
  526. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  527. /// <returns>If found, the index of the located value. If not found, the return value is negative.</returns>
  528. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  529. public unsafe static int BinarySearch<T, U>(this NativeSlice<T> slice, T value, U comp)
  530. where T : unmanaged
  531. where U : IComparer<T>
  532. {
  533. return BinarySearch((T*)slice.GetUnsafeReadOnlyPtr(), slice.Length, value, comp);
  534. }
  535. /// -- Internals
  536. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  537. unsafe internal static void IntroSort<T, U>(void* array, int length, U comp)
  538. where T : unmanaged
  539. where U : IComparer<T>
  540. {
  541. CheckComparer((T*)array, length, comp);
  542. IntroSort_R<T, U>(array, 0, length - 1, 2 * CollectionHelper.Log2Floor(length), comp);
  543. }
  544. const int k_IntrosortSizeThreshold = 16;
  545. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(DefaultComparer<int>) })]
  546. unsafe internal static void IntroSort_R<T, U>(void* array, int lo, int hi, int depth, U comp)
  547. where T : unmanaged
  548. where U : IComparer<T>
  549. {
  550. while (hi > lo)
  551. {
  552. int partitionSize = hi - lo + 1;
  553. if (partitionSize <= k_IntrosortSizeThreshold)
  554. {
  555. if (partitionSize == 1)
  556. {
  557. return;
  558. }
  559. if (partitionSize == 2)
  560. {
  561. SwapIfGreaterWithItems<T, U>(array, lo, hi, comp);
  562. return;
  563. }
  564. if (partitionSize == 3)
  565. {
  566. SwapIfGreaterWithItems<T, U>(array, lo, hi - 1, comp);
  567. SwapIfGreaterWithItems<T, U>(array, lo, hi, comp);
  568. SwapIfGreaterWithItems<T, U>(array, hi - 1, hi, comp);
  569. return;
  570. }
  571. InsertionSort<T, U>(array, lo, hi, comp);
  572. return;
  573. }
  574. if (depth == 0)
  575. {
  576. HeapSort<T, U>(array, lo, hi, comp);
  577. return;
  578. }
  579. depth--;
  580. int p = Partition<T, U>(array, lo, hi, comp);
  581. IntroSort_R<T, U>(array, p + 1, hi, depth, comp);
  582. hi = p - 1;
  583. }
  584. }
  585. unsafe static void InsertionSort<T, U>(void* array, int lo, int hi, U comp)
  586. where T : unmanaged
  587. where U : IComparer<T>
  588. {
  589. int i, j;
  590. T t;
  591. for (i = lo; i < hi; i++)
  592. {
  593. j = i;
  594. t = UnsafeUtility.ReadArrayElement<T>(array, i + 1);
  595. while (j >= lo && comp.Compare(t, UnsafeUtility.ReadArrayElement<T>(array, j)) < 0)
  596. {
  597. UnsafeUtility.WriteArrayElement(array, j + 1, UnsafeUtility.ReadArrayElement<T>(array, j));
  598. j--;
  599. }
  600. UnsafeUtility.WriteArrayElement(array, j + 1, t);
  601. }
  602. }
  603. unsafe static int Partition<T, U>(void* array, int lo, int hi, U comp)
  604. where T : unmanaged
  605. where U : IComparer<T>
  606. {
  607. int mid = lo + ((hi - lo) / 2);
  608. SwapIfGreaterWithItems<T, U>(array, lo, mid, comp);
  609. SwapIfGreaterWithItems<T, U>(array, lo, hi, comp);
  610. SwapIfGreaterWithItems<T, U>(array, mid, hi, comp);
  611. T pivot = UnsafeUtility.ReadArrayElement<T>(array, mid);
  612. Swap<T>(array, mid, hi - 1);
  613. int left = lo, right = hi - 1;
  614. while (left < right)
  615. {
  616. while (left < hi && comp.Compare(pivot, UnsafeUtility.ReadArrayElement<T>(array, ++left)) > 0)
  617. {
  618. }
  619. while (right > left && comp.Compare(pivot, UnsafeUtility.ReadArrayElement<T>(array, --right)) < 0)
  620. {
  621. }
  622. if (left >= right)
  623. break;
  624. Swap<T>(array, left, right);
  625. }
  626. Swap<T>(array, left, (hi - 1));
  627. return left;
  628. }
  629. unsafe static void HeapSort<T, U>(void* array, int lo, int hi, U comp)
  630. where T : unmanaged
  631. where U : IComparer<T>
  632. {
  633. int n = hi - lo + 1;
  634. for (int i = n / 2; i >= 1; i--)
  635. {
  636. Heapify<T, U>(array, i, n, lo, comp);
  637. }
  638. for (int i = n; i > 1; i--)
  639. {
  640. Swap<T>(array, lo, lo + i - 1);
  641. Heapify<T, U>(array, 1, i - 1, lo, comp);
  642. }
  643. }
  644. unsafe static void Heapify<T, U>(void* array, int i, int n, int lo, U comp)
  645. where T : unmanaged
  646. where U : IComparer<T>
  647. {
  648. T val = UnsafeUtility.ReadArrayElement<T>(array, lo + i - 1);
  649. int child;
  650. while (i <= n / 2)
  651. {
  652. child = 2 * i;
  653. if (child < n && (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, lo + child - 1), UnsafeUtility.ReadArrayElement<T>(array, (lo + child))) < 0))
  654. {
  655. child++;
  656. }
  657. if (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, (lo + child - 1)), val) < 0)
  658. {
  659. break;
  660. }
  661. UnsafeUtility.WriteArrayElement(array, lo + i - 1, UnsafeUtility.ReadArrayElement<T>(array, lo + child - 1));
  662. i = child;
  663. }
  664. UnsafeUtility.WriteArrayElement(array, lo + i - 1, val);
  665. }
  666. unsafe static void Swap<T>(void* array, int lhs, int rhs) where T : unmanaged
  667. {
  668. T val = UnsafeUtility.ReadArrayElement<T>(array, lhs);
  669. UnsafeUtility.WriteArrayElement(array, lhs, UnsafeUtility.ReadArrayElement<T>(array, rhs));
  670. UnsafeUtility.WriteArrayElement(array, rhs, val);
  671. }
  672. unsafe static void SwapIfGreaterWithItems<T, U>(void* array, int lhs, int rhs, U comp)
  673. where T : unmanaged
  674. where U : IComparer<T>
  675. {
  676. if (lhs != rhs)
  677. {
  678. if (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, lhs), UnsafeUtility.ReadArrayElement<T>(array, rhs)) > 0)
  679. {
  680. Swap<T>(array, lhs, rhs);
  681. }
  682. }
  683. }
  684. unsafe static void IntroSortStruct<T, U>(void* array, int length, U comp)
  685. where T : unmanaged
  686. where U : IComparer<T>
  687. {
  688. IntroSortStruct_R<T, U>(array, 0, length - 1, 2 * CollectionHelper.Log2Floor(length), comp);
  689. }
  690. unsafe static void IntroSortStruct_R<T, U>(void* array, in int lo, in int _hi, int depth, U comp)
  691. where T : unmanaged
  692. where U : IComparer<T>
  693. {
  694. var hi = _hi;
  695. while (hi > lo)
  696. {
  697. int partitionSize = hi - lo + 1;
  698. if (partitionSize <= k_IntrosortSizeThreshold)
  699. {
  700. if (partitionSize == 1)
  701. {
  702. return;
  703. }
  704. if (partitionSize == 2)
  705. {
  706. SwapIfGreaterWithItemsStruct<T, U>(array, lo, hi, comp);
  707. return;
  708. }
  709. if (partitionSize == 3)
  710. {
  711. SwapIfGreaterWithItemsStruct<T, U>(array, lo, hi - 1, comp);
  712. SwapIfGreaterWithItemsStruct<T, U>(array, lo, hi, comp);
  713. SwapIfGreaterWithItemsStruct<T, U>(array, hi - 1, hi, comp);
  714. return;
  715. }
  716. InsertionSortStruct<T, U>(array, lo, hi, comp);
  717. return;
  718. }
  719. if (depth == 0)
  720. {
  721. HeapSortStruct<T, U>(array, lo, hi, comp);
  722. return;
  723. }
  724. depth--;
  725. int p = PartitionStruct<T, U>(array, lo, hi, comp);
  726. IntroSortStruct_R<T, U>(array, p + 1, hi, depth, comp);
  727. hi = p - 1;
  728. }
  729. }
  730. unsafe static void InsertionSortStruct<T, U>(void* array, in int lo, in int hi, U comp)
  731. where T : unmanaged
  732. where U : IComparer<T>
  733. {
  734. int i, j;
  735. T t;
  736. for (i = lo; i < hi; i++)
  737. {
  738. j = i;
  739. t = UnsafeUtility.ReadArrayElement<T>(array, i + 1);
  740. while (j >= lo && comp.Compare(t, UnsafeUtility.ReadArrayElement<T>(array, j)) < 0)
  741. {
  742. UnsafeUtility.WriteArrayElement(array, j + 1, UnsafeUtility.ReadArrayElement<T>(array, j));
  743. j--;
  744. }
  745. UnsafeUtility.WriteArrayElement(array, j + 1, t);
  746. }
  747. }
  748. unsafe static int PartitionStruct<T, U>(void* array, in int lo, in int hi, U comp)
  749. where T : unmanaged
  750. where U : IComparer<T>
  751. {
  752. int mid = lo + ((hi - lo) / 2);
  753. SwapIfGreaterWithItemsStruct<T, U>(array, lo, mid, comp);
  754. SwapIfGreaterWithItemsStruct<T, U>(array, lo, hi, comp);
  755. SwapIfGreaterWithItemsStruct<T, U>(array, mid, hi, comp);
  756. T pivot = UnsafeUtility.ReadArrayElement<T>(array, mid);
  757. SwapStruct<T>(array, mid, hi - 1);
  758. int left = lo, right = hi - 1;
  759. while (left < right)
  760. {
  761. while (left < hi && comp.Compare(pivot, UnsafeUtility.ReadArrayElement<T>(array, ++left)) > 0)
  762. {
  763. }
  764. while (right > left && comp.Compare(pivot, UnsafeUtility.ReadArrayElement<T>(array, --right)) < 0)
  765. {
  766. }
  767. if (left >= right)
  768. break;
  769. SwapStruct<T>(array, left, right);
  770. }
  771. SwapStruct<T>(array, left, (hi - 1));
  772. return left;
  773. }
  774. unsafe static void HeapSortStruct<T, U>(void* array, in int lo, in int hi, U comp)
  775. where T : unmanaged
  776. where U : IComparer<T>
  777. {
  778. int n = hi - lo + 1;
  779. for (int i = n / 2; i >= 1; i--)
  780. {
  781. HeapifyStruct<T, U>(array, i, n, lo, comp);
  782. }
  783. for (int i = n; i > 1; i--)
  784. {
  785. SwapStruct<T>(array, lo, lo + i - 1);
  786. HeapifyStruct<T, U>(array, 1, i - 1, lo, comp);
  787. }
  788. }
  789. unsafe static void HeapifyStruct<T, U>(void* array, int i, int n, in int lo, U comp)
  790. where T : unmanaged
  791. where U : IComparer<T>
  792. {
  793. T val = UnsafeUtility.ReadArrayElement<T>(array, lo + i - 1);
  794. int child;
  795. while (i <= n / 2)
  796. {
  797. child = 2 * i;
  798. if (child < n && (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, lo + child - 1), UnsafeUtility.ReadArrayElement<T>(array, (lo + child))) < 0))
  799. {
  800. child++;
  801. }
  802. if (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, (lo + child - 1)), val) < 0)
  803. {
  804. break;
  805. }
  806. UnsafeUtility.WriteArrayElement(array, lo + i - 1, UnsafeUtility.ReadArrayElement<T>(array, lo + child - 1));
  807. i = child;
  808. }
  809. UnsafeUtility.WriteArrayElement(array, lo + i - 1, val);
  810. }
  811. unsafe static void SwapStruct<T>(void* array, int lhs, int rhs)
  812. where T : unmanaged
  813. {
  814. T val = UnsafeUtility.ReadArrayElement<T>(array, lhs);
  815. UnsafeUtility.WriteArrayElement(array, lhs, UnsafeUtility.ReadArrayElement<T>(array, rhs));
  816. UnsafeUtility.WriteArrayElement(array, rhs, val);
  817. }
  818. unsafe static void SwapIfGreaterWithItemsStruct<T, U>(void* array, int lhs, int rhs, U comp)
  819. where T : unmanaged
  820. where U : IComparer<T>
  821. {
  822. if (lhs != rhs)
  823. {
  824. if (comp.Compare(UnsafeUtility.ReadArrayElement<T>(array, lhs), UnsafeUtility.ReadArrayElement<T>(array, rhs)) > 0)
  825. {
  826. SwapStruct<T>(array, lhs, rhs);
  827. }
  828. }
  829. }
  830. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
  831. static void CheckStrideMatchesSize<T>(int stride) where T : unmanaged
  832. {
  833. if (stride != UnsafeUtility.SizeOf<T>())
  834. {
  835. throw new InvalidOperationException("Sort requires that stride matches the size of the source type");
  836. }
  837. }
  838. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
  839. unsafe static void CheckComparer<T, U>(T* array, int length, U comp)
  840. where T : unmanaged
  841. where U : IComparer<T>
  842. {
  843. if (length > 0)
  844. {
  845. T a = array[0];
  846. if (0 != comp.Compare(a, a))
  847. {
  848. throw new InvalidOperationException("Comparison function is incorrect. Compare(a, a) must return 0/equal.");
  849. }
  850. for (int i = 1, len = math.min(length, 8); i < len; ++i)
  851. {
  852. T b = array[i];
  853. if (0 == comp.Compare(a, b) &&
  854. 0 == comp.Compare(b, a))
  855. {
  856. continue;
  857. }
  858. if (0 == comp.Compare(a, b))
  859. {
  860. throw new InvalidOperationException("Comparison function is incorrect. Compare(a, b) of two different values should not return 0/equal.");
  861. }
  862. if (0 == comp.Compare(b, a))
  863. {
  864. throw new InvalidOperationException("Comparison function is incorrect. Compare(b, a) of two different values should not return 0/equal.");
  865. }
  866. if (comp.Compare(a, b) == comp.Compare(b, a))
  867. {
  868. 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).");
  869. }
  870. break;
  871. }
  872. }
  873. }
  874. }
  875. /// <summary>
  876. /// Returned by the `SortJob` methods of <see cref="Unity.Collections.NativeSortExtension"/>. Call `Schedule` to schedule the sorting.
  877. /// </summary>
  878. /// <remarks>
  879. /// When `RegisterGenericJobType` is used on SortJob, to complete registration you must register `SortJob&lt;T,U&gt;.SegmentSort` and `SortJob&lt;T,U&gt;.SegmentSortMerge`.
  880. /// </remarks>
  881. /// <typeparam name="T">The type of the elements to sort.</typeparam>
  882. /// <typeparam name="U">The type of the comparer.</typeparam>
  883. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(NativeSortExtension.DefaultComparer<int>) }, RequiredUnityDefine = "UNITY_2020_2_OR_NEWER" /* Due to job scheduling on 2020.1 using statics */)]
  884. public unsafe struct SortJob<T, U>
  885. where T : unmanaged
  886. where U : IComparer<T>
  887. {
  888. /// <summary>
  889. /// The data to sort.
  890. /// </summary>
  891. public T* Data;
  892. /// <summary>
  893. /// Comparison function.
  894. /// </summary>
  895. public U Comp;
  896. /// <summary>
  897. /// The length to sort.
  898. /// </summary>
  899. public int Length;
  900. /// <summary>
  901. /// <undoc />
  902. /// </summary>
  903. [BurstCompile]
  904. public struct SegmentSort : IJobParallelFor
  905. {
  906. [NativeDisableUnsafePtrRestriction]
  907. internal T* Data;
  908. internal U Comp;
  909. internal int Length;
  910. internal int SegmentWidth;
  911. /// <summary>
  912. /// <undoc />
  913. /// </summary>
  914. /// <param name="index"><undoc /></param>
  915. public void Execute(int index)
  916. {
  917. var startIndex = index * SegmentWidth;
  918. var segmentLength = ((Length - startIndex) < SegmentWidth) ? (Length - startIndex) : SegmentWidth;
  919. NativeSortExtension.Sort(Data + startIndex, segmentLength, Comp);
  920. }
  921. }
  922. /// <summary>
  923. /// <undoc />
  924. /// </summary>
  925. [BurstCompile]
  926. public struct SegmentSortMerge : IJob
  927. {
  928. [NativeDisableUnsafePtrRestriction]
  929. internal T* Data;
  930. internal U Comp;
  931. internal int Length;
  932. internal int SegmentWidth;
  933. /// <summary>
  934. /// <undoc />
  935. /// </summary>
  936. public void Execute()
  937. {
  938. var segmentCount = (Length + (SegmentWidth - 1)) / SegmentWidth;
  939. var segmentIndex = stackalloc int[segmentCount];
  940. var resultCopy = (T*)Memory.Unmanaged.Allocate(UnsafeUtility.SizeOf<T>() * Length, 16, Allocator.Temp);
  941. for (int sortIndex = 0; sortIndex < Length; sortIndex++)
  942. {
  943. // find next best
  944. int bestSegmentIndex = -1;
  945. T bestValue = default(T);
  946. for (int i = 0; i < segmentCount; i++)
  947. {
  948. var startIndex = i * SegmentWidth;
  949. var offset = segmentIndex[i];
  950. var segmentLength = ((Length - startIndex) < SegmentWidth) ? (Length - startIndex) : SegmentWidth;
  951. if (offset == segmentLength)
  952. continue;
  953. var nextValue = Data[startIndex + offset];
  954. if (bestSegmentIndex != -1)
  955. {
  956. if (Comp.Compare(nextValue, bestValue) > 0)
  957. continue;
  958. }
  959. bestValue = nextValue;
  960. bestSegmentIndex = i;
  961. }
  962. segmentIndex[bestSegmentIndex]++;
  963. resultCopy[sortIndex] = bestValue;
  964. }
  965. UnsafeUtility.MemCpy(Data, resultCopy, UnsafeUtility.SizeOf<T>() * Length);
  966. }
  967. }
  968. /// <summary>
  969. /// Schedules this job.
  970. /// </summary>
  971. /// <param name="inputDeps">Handle of a job to depend upon.</param>
  972. /// <returns>The handle of this newly scheduled job.</returns>
  973. public JobHandle Schedule(JobHandle inputDeps = default)
  974. {
  975. if (Length == 0)
  976. return inputDeps;
  977. var segmentCount = (Length + 1023) / 1024;
  978. #if UNITY_2022_2_14F1_OR_NEWER
  979. int maxThreadCount = JobsUtility.ThreadIndexCount;
  980. #else
  981. int maxThreadCount = JobsUtility.MaxJobThreadCount;
  982. #endif
  983. var workerCount = math.max(1, maxThreadCount);
  984. var workerSegmentCount = segmentCount / workerCount;
  985. var segmentSortJob = new SegmentSort { Data = Data, Comp = Comp, Length = Length, SegmentWidth = 1024 };
  986. var segmentSortJobHandle = segmentSortJob.Schedule(segmentCount, workerSegmentCount, inputDeps);
  987. var segmentSortMergeJob = new SegmentSortMerge { Data = Data, Comp = Comp, Length = Length, SegmentWidth = 1024 };
  988. var segmentSortMergeJobHandle = segmentSortMergeJob.Schedule(segmentSortJobHandle);
  989. return segmentSortMergeJobHandle;
  990. }
  991. }
  992. }