Keine Beschreibung
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

ArrayHelpers.cs 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Unity.Collections;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. namespace UnityEngine.InputSystem.Utilities
  7. {
  8. /// <summary>
  9. /// A collection of utility functions for working with arrays.
  10. /// </summary>
  11. /// <remarks>
  12. /// The goal of this collection is to make it easy to use arrays directly rather than resorting to
  13. /// <see cref="List{T}"/>.
  14. /// </remarks>
  15. internal static class ArrayHelpers
  16. {
  17. public static int LengthSafe<TValue>(this TValue[] array)
  18. {
  19. if (array == null)
  20. return 0;
  21. return array.Length;
  22. }
  23. public static void Clear<TValue>(this TValue[] array)
  24. {
  25. if (array == null)
  26. return;
  27. Array.Clear(array, 0, array.Length);
  28. }
  29. public static void Clear<TValue>(this TValue[] array, int count)
  30. {
  31. if (array == null)
  32. return;
  33. Array.Clear(array, 0, count);
  34. }
  35. public static void Clear<TValue>(this TValue[] array, ref int count)
  36. {
  37. if (array == null)
  38. return;
  39. Array.Clear(array, 0, count);
  40. count = 0;
  41. }
  42. public static void EnsureCapacity<TValue>(ref TValue[] array, int count, int capacity, int capacityIncrement = 10)
  43. {
  44. if (capacity == 0)
  45. return;
  46. if (array == null)
  47. {
  48. array = new TValue[Math.Max(capacity, capacityIncrement)];
  49. return;
  50. }
  51. var currentCapacity = array.Length - count;
  52. if (currentCapacity >= capacity)
  53. return;
  54. DuplicateWithCapacity(ref array, count, capacity, capacityIncrement);
  55. }
  56. public static void DuplicateWithCapacity<TValue>(ref TValue[] array, int count, int capacity, int capacityIncrement = 10)
  57. {
  58. if (array == null)
  59. {
  60. array = new TValue[Math.Max(capacity, capacityIncrement)];
  61. return;
  62. }
  63. var newSize = count + Math.Max(capacity, capacityIncrement);
  64. var newArray = new TValue[newSize];
  65. Array.Copy(array, newArray, count);
  66. array = newArray;
  67. }
  68. public static bool Contains<TValue>(TValue[] array, TValue value)
  69. {
  70. if (array == null)
  71. return false;
  72. var comparer = EqualityComparer<TValue>.Default;
  73. for (var i = 0; i < array.Length; ++i)
  74. if (comparer.Equals(array[i], value))
  75. return true;
  76. return false;
  77. }
  78. public static bool ContainsReference<TValue>(this TValue[] array, TValue value)
  79. where TValue : class
  80. {
  81. if (array == null)
  82. return false;
  83. return ContainsReference(array, array.Length, value);
  84. }
  85. public static bool ContainsReference<TFirst, TSecond>(this TFirst[] array, int count, TSecond value)
  86. where TSecond : class
  87. where TFirst : TSecond
  88. {
  89. return IndexOfReference(array, value, count) != -1;
  90. }
  91. public static bool ContainsReference<TFirst, TSecond>(this TFirst[] array, int startIndex, int count, TSecond value)
  92. where TSecond : class
  93. where TFirst : TSecond
  94. {
  95. return IndexOfReference(array, value, startIndex, count) != -1;
  96. }
  97. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Keep this for future implementation")]
  98. public static bool HaveDuplicateReferences<TFirst>(this TFirst[] first, int index, int count)
  99. {
  100. for (var i = 0; i < count; ++i)
  101. {
  102. var element = first[i];
  103. for (var n = i + 1; n < count - i; ++n)
  104. {
  105. if (ReferenceEquals(element, first[n]))
  106. return true;
  107. }
  108. }
  109. return false;
  110. }
  111. public static bool HaveEqualElements<TValue>(TValue[] first, TValue[] second, int count = int.MaxValue)
  112. {
  113. if (first == null || second == null)
  114. return second == first;
  115. var lengthFirst = Math.Min(count, first.Length);
  116. var lengthSecond = Math.Min(count, second.Length);
  117. if (lengthFirst != lengthSecond)
  118. return false;
  119. var comparer = EqualityComparer<TValue>.Default;
  120. for (var i = 0; i < lengthFirst; ++i)
  121. if (!comparer.Equals(first[i], second[i]))
  122. return false;
  123. return true;
  124. }
  125. ////REVIEW: remove this to get rid of default equality comparer?
  126. public static int IndexOf<TValue>(TValue[] array, TValue value, int startIndex = 0, int count = -1)
  127. {
  128. if (array == null)
  129. return -1;
  130. if (count < 0)
  131. count = array.Length - startIndex;
  132. var comparer = EqualityComparer<TValue>.Default;
  133. for (var i = startIndex; i < startIndex + count; ++i)
  134. if (comparer.Equals(array[i], value))
  135. return i;
  136. return -1;
  137. }
  138. public static int IndexOf<TValue>(this TValue[] array, Predicate<TValue> predicate)
  139. {
  140. if (array == null)
  141. return -1;
  142. var length = array.Length;
  143. for (var i = 0; i < length; ++i)
  144. if (predicate(array[i]))
  145. return i;
  146. return -1;
  147. }
  148. public static int IndexOf<TValue>(this TValue[] array, Predicate<TValue> predicate, int startIndex = 0, int count = -1)
  149. {
  150. if (array == null)
  151. return -1;
  152. var end = startIndex + (count < 0 ? array.Length - startIndex : count);
  153. for (var i = startIndex; i < end; ++i)
  154. {
  155. if (predicate(array[i]))
  156. return i;
  157. }
  158. return -1;
  159. }
  160. public static int IndexOfReference<TFirst, TSecond>(this TFirst[] array, TSecond value, int count = -1)
  161. where TSecond : class
  162. where TFirst : TSecond
  163. {
  164. return IndexOfReference(array, value, 0, count);
  165. }
  166. public static int IndexOfReference<TFirst, TSecond>(this TFirst[] array, TSecond value, int startIndex, int count)
  167. where TSecond : class
  168. where TFirst : TSecond
  169. {
  170. if (array == null)
  171. return -1;
  172. if (count < 0)
  173. count = array.Length - startIndex;
  174. for (var i = startIndex; i < startIndex + count; ++i)
  175. if (ReferenceEquals(array[i], value))
  176. return i;
  177. return -1;
  178. }
  179. public static int IndexOfValue<TValue>(this TValue[] array, TValue value, int startIndex = 0, int count = -1)
  180. where TValue : struct, IEquatable<TValue>
  181. {
  182. if (array == null)
  183. return -1;
  184. if (count < 0)
  185. count = array.Length - startIndex;
  186. for (var i = startIndex; i < startIndex + count; ++i)
  187. if (value.Equals(array[i]))
  188. return i;
  189. return -1;
  190. }
  191. public static unsafe void Resize<TValue>(ref NativeArray<TValue> array, int newSize, Allocator allocator)
  192. where TValue : struct
  193. {
  194. var oldSize = array.Length;
  195. if (oldSize == newSize)
  196. return;
  197. if (newSize == 0)
  198. {
  199. if (array.IsCreated)
  200. array.Dispose();
  201. array = new NativeArray<TValue>();
  202. return;
  203. }
  204. var newArray = new NativeArray<TValue>(newSize, allocator);
  205. if (oldSize != 0)
  206. {
  207. // Copy contents from old array.
  208. UnsafeUtility.MemCpy(newArray.GetUnsafePtr(), array.GetUnsafeReadOnlyPtr(),
  209. UnsafeUtility.SizeOf<TValue>() * (newSize < oldSize ? newSize : oldSize));
  210. array.Dispose();
  211. }
  212. array = newArray;
  213. }
  214. public static int Append<TValue>(ref TValue[] array, TValue value)
  215. {
  216. if (array == null)
  217. {
  218. array = new TValue[1];
  219. array[0] = value;
  220. return 0;
  221. }
  222. var length = array.Length;
  223. Array.Resize(ref array, length + 1);
  224. array[length] = value;
  225. return length;
  226. }
  227. public static int Append<TValue>(ref TValue[] array, IEnumerable<TValue> values)
  228. {
  229. if (array == null)
  230. {
  231. array = values.ToArray();
  232. return 0;
  233. }
  234. var oldLength = array.Length;
  235. var valueCount = values.Count();
  236. Array.Resize(ref array, oldLength + valueCount);
  237. var index = oldLength;
  238. foreach (var value in values)
  239. array[index++] = value;
  240. return oldLength;
  241. }
  242. // Append to an array that is considered immutable. This allows using 'values' as is
  243. // if 'array' is null.
  244. // Returns the index of the first newly added element in the resulting array.
  245. public static int AppendToImmutable<TValue>(ref TValue[] array, TValue[] values)
  246. {
  247. if (array == null)
  248. {
  249. array = values;
  250. return 0;
  251. }
  252. if (values != null && values.Length > 0)
  253. {
  254. var oldCount = array.Length;
  255. var valueCount = values.Length;
  256. Array.Resize(ref array, oldCount + valueCount);
  257. Array.Copy(values, 0, array, oldCount, valueCount);
  258. return oldCount;
  259. }
  260. return array.Length;
  261. }
  262. public static int AppendWithCapacity<TValue>(ref TValue[] array, ref int count, TValue value, int capacityIncrement = 10)
  263. {
  264. if (array == null)
  265. {
  266. array = new TValue[capacityIncrement];
  267. array[0] = value;
  268. ++count;
  269. return 0;
  270. }
  271. var capacity = array.Length;
  272. if (capacity == count)
  273. {
  274. capacity += capacityIncrement;
  275. Array.Resize(ref array, capacity);
  276. }
  277. var index = count;
  278. array[index] = value;
  279. ++count;
  280. return index;
  281. }
  282. public static int AppendListWithCapacity<TValue, TValues>(ref TValue[] array, ref int length, TValues values, int capacityIncrement = 10)
  283. where TValues : IReadOnlyList<TValue>
  284. {
  285. var numToAdd = values.Count;
  286. if (array == null)
  287. {
  288. var size = Math.Max(numToAdd, capacityIncrement);
  289. array = new TValue[size];
  290. for (var i = 0; i < numToAdd; ++i)
  291. array[i] = values[i];
  292. length += numToAdd;
  293. return 0;
  294. }
  295. var capacity = array.Length;
  296. if (capacity < length + numToAdd)
  297. {
  298. capacity += Math.Max(length + numToAdd, capacityIncrement);
  299. Array.Resize(ref array, capacity);
  300. }
  301. var index = length;
  302. for (var i = 0; i < numToAdd; ++i)
  303. array[index + i] = values[i];
  304. length += numToAdd;
  305. return index;
  306. }
  307. public static int AppendWithCapacity<TValue>(ref NativeArray<TValue> array, ref int count, TValue value,
  308. int capacityIncrement = 10, Allocator allocator = Allocator.Persistent)
  309. where TValue : struct
  310. {
  311. var capacity = array.Length;
  312. if (capacity == count)
  313. GrowBy(ref array, capacityIncrement > 1 ? capacityIncrement : 1, allocator);
  314. var index = count;
  315. array[index] = value;
  316. ++count;
  317. return index;
  318. }
  319. public static void InsertAt<TValue>(ref TValue[] array, int index, TValue value)
  320. {
  321. if (array == null)
  322. {
  323. ////REVIEW: allow growing array to specific size by inserting at arbitrary index?
  324. if (index != 0)
  325. throw new ArgumentOutOfRangeException(nameof(index));
  326. array = new TValue[1];
  327. array[0] = value;
  328. return;
  329. }
  330. // Reallocate.
  331. var oldLength = array.Length;
  332. Array.Resize(ref array, oldLength + 1);
  333. // Make room for element.
  334. if (index != oldLength)
  335. Array.Copy(array, index, array, index + 1, oldLength - index);
  336. array[index] = value;
  337. }
  338. public static void InsertAtWithCapacity<TValue>(ref TValue[] array, ref int count, int index, TValue value, int capacityIncrement = 10)
  339. {
  340. EnsureCapacity(ref array, count, count + 1, capacityIncrement);
  341. if (index != count)
  342. Array.Copy(array, index, array, index + 1, count - index);
  343. array[index] = value;
  344. ++count;
  345. }
  346. public static void PutAtIfNotSet<TValue>(ref TValue[] array, int index, Func<TValue> valueFn)
  347. {
  348. if (array.LengthSafe() < index + 1)
  349. Array.Resize(ref array, index + 1);
  350. if (EqualityComparer<TValue>.Default.Equals(array[index], default(TValue)))
  351. array[index] = valueFn();
  352. }
  353. // Adds 'count' entries to the array. Returns first index of newly added entries.
  354. public static int GrowBy<TValue>(ref TValue[] array, int count)
  355. {
  356. if (array == null)
  357. {
  358. array = new TValue[count];
  359. return 0;
  360. }
  361. var oldLength = array.Length;
  362. Array.Resize(ref array, oldLength + count);
  363. return oldLength;
  364. }
  365. public static unsafe int GrowBy<TValue>(ref NativeArray<TValue> array, int count, Allocator allocator = Allocator.Persistent)
  366. where TValue : struct
  367. {
  368. var length = array.Length;
  369. if (length == 0)
  370. {
  371. array = new NativeArray<TValue>(count, allocator);
  372. return 0;
  373. }
  374. var newArray = new NativeArray<TValue>(length + count, allocator);
  375. // CopyFrom() expects length to match. Copy manually.
  376. UnsafeUtility.MemCpy(newArray.GetUnsafePtr(), array.GetUnsafeReadOnlyPtr(), (long)length * UnsafeUtility.SizeOf<TValue>());
  377. array.Dispose();
  378. array = newArray;
  379. return length;
  380. }
  381. public static int GrowWithCapacity<TValue>(ref TValue[] array, ref int count, int growBy, int capacityIncrement = 10)
  382. {
  383. var length = array != null ? array.Length : 0;
  384. if (length < count + growBy)
  385. {
  386. if (capacityIncrement < growBy)
  387. capacityIncrement = growBy;
  388. GrowBy(ref array, capacityIncrement);
  389. }
  390. var offset = count;
  391. count += growBy;
  392. return offset;
  393. }
  394. public static int GrowWithCapacity<TValue>(ref NativeArray<TValue> array, ref int count, int growBy,
  395. int capacityIncrement = 10, Allocator allocator = Allocator.Persistent)
  396. where TValue : struct
  397. {
  398. var length = array.Length;
  399. if (length < count + growBy)
  400. {
  401. if (capacityIncrement < growBy)
  402. capacityIncrement = growBy;
  403. GrowBy(ref array, capacityIncrement, allocator);
  404. }
  405. var offset = count;
  406. count += growBy;
  407. return offset;
  408. }
  409. public static TValue[] Join<TValue>(TValue value, params TValue[] values)
  410. {
  411. // Determine length.
  412. var length = 0;
  413. if (value != null)
  414. ++length;
  415. if (values != null)
  416. length += values.Length;
  417. if (length == 0)
  418. return null;
  419. var array = new TValue[length];
  420. // Populate.
  421. var index = 0;
  422. if (value != null)
  423. array[index++] = value;
  424. if (values != null)
  425. Array.Copy(values, 0, array, index, values.Length);
  426. return array;
  427. }
  428. public static TValue[] Merge<TValue>(TValue[] first, TValue[] second)
  429. where TValue : IEquatable<TValue>
  430. {
  431. if (first == null)
  432. return second;
  433. if (second == null)
  434. return first;
  435. var merged = new List<TValue>();
  436. merged.AddRange(first);
  437. for (var i = 0; i < second.Length; ++i)
  438. {
  439. var secondValue = second[i];
  440. if (!merged.Exists(x => x.Equals(secondValue)))
  441. {
  442. merged.Add(secondValue);
  443. }
  444. }
  445. return merged.ToArray();
  446. }
  447. public static TValue[] Merge<TValue>(TValue[] first, TValue[] second, IEqualityComparer<TValue> comparer)
  448. {
  449. if (first == null)
  450. return second;
  451. if (second == null)
  452. return null;
  453. var merged = new List<TValue>();
  454. merged.AddRange(first);
  455. for (var i = 0; i < second.Length; ++i)
  456. {
  457. var secondValue = second[i];
  458. if (!merged.Exists(x => comparer.Equals(secondValue)))
  459. {
  460. merged.Add(secondValue);
  461. }
  462. }
  463. return merged.ToArray();
  464. }
  465. public static void EraseAt<TValue>(ref TValue[] array, int index)
  466. {
  467. Debug.Assert(array != null);
  468. Debug.Assert(index >= 0 && index < array.Length);
  469. var length = array.Length;
  470. if (index == 0 && length == 1)
  471. {
  472. array = null;
  473. return;
  474. }
  475. if (index < length - 1)
  476. Array.Copy(array, index + 1, array, index, length - index - 1);
  477. Array.Resize(ref array, length - 1);
  478. }
  479. public static void EraseAtWithCapacity<TValue>(this TValue[] array, ref int count, int index)
  480. {
  481. Debug.Assert(array != null);
  482. Debug.Assert(count <= array.Length);
  483. Debug.Assert(index >= 0 && index < count);
  484. // If we're erasing from the beginning or somewhere in the middle, move
  485. // the array contents down from after the index.
  486. if (index < count - 1)
  487. {
  488. Array.Copy(array, index + 1, array, index, count - index - 1);
  489. }
  490. array[count - 1] = default; // Tail has been moved down by one.
  491. --count;
  492. }
  493. public static unsafe void EraseAtWithCapacity<TValue>(NativeArray<TValue> array, ref int count, int index)
  494. where TValue : struct
  495. {
  496. Debug.Assert(array.IsCreated);
  497. Debug.Assert(count <= array.Length);
  498. Debug.Assert(index >= 0 && index < count);
  499. // If we're erasing from the beginning or somewhere in the middle, move
  500. // the array contents down from after the index.
  501. if (index < count - 1)
  502. {
  503. var elementSize = UnsafeUtility.SizeOf<TValue>();
  504. var arrayPtr = (byte*)array.GetUnsafePtr();
  505. UnsafeUtility.MemCpy(arrayPtr + elementSize * index, arrayPtr + elementSize * (index + 1),
  506. (count - index - 1) * elementSize);
  507. }
  508. --count;
  509. }
  510. public static bool Erase<TValue>(ref TValue[] array, TValue value)
  511. {
  512. var index = IndexOf(array, value);
  513. if (index != -1)
  514. {
  515. EraseAt(ref array, index);
  516. return true;
  517. }
  518. return false;
  519. }
  520. /// <summary>
  521. /// Erase an element from the array by moving the tail element into its place.
  522. /// </summary>
  523. /// <param name="array">Array to modify. May be not <c>null</c>.</param>
  524. /// <param name="count">Current number of elements inside of array. May be less than <c>array.Length</c>.</param>
  525. /// <param name="index">Index of element to remove. Tail element will get moved into its place.</param>
  526. /// <typeparam name="TValue"></typeparam>
  527. /// <remarks>
  528. /// This method does not re-allocate the array. Instead <paramref name="count"/> is used
  529. /// to keep track of how many elements there actually are in the array.
  530. /// </remarks>
  531. public static void EraseAtByMovingTail<TValue>(TValue[] array, ref int count, int index)
  532. {
  533. Debug.Assert(array != null);
  534. Debug.Assert(index >= 0 && index < array.Length);
  535. Debug.Assert(count >= 0 && count <= array.Length);
  536. Debug.Assert(index < count);
  537. // Move tail, if necessary.
  538. if (index != count - 1)
  539. array[index] = array[count - 1];
  540. // Destroy current tail.
  541. if (count >= 1)
  542. array[count - 1] = default;
  543. --count;
  544. }
  545. public static TValue[] Copy<TValue>(TValue[] array)
  546. {
  547. if (array == null)
  548. return null;
  549. var length = array.Length;
  550. var result = new TValue[length];
  551. Array.Copy(array, result, length);
  552. return result;
  553. }
  554. public static TValue[] Clone<TValue>(TValue[] array)
  555. where TValue : ICloneable
  556. {
  557. if (array == null)
  558. return null;
  559. var count = array.Length;
  560. var result = new TValue[count];
  561. for (var i = 0; i < count; ++i)
  562. result[i] = (TValue)array[i].Clone();
  563. return result;
  564. }
  565. public static TNew[] Select<TOld, TNew>(TOld[] array, Func<TOld, TNew> converter)
  566. {
  567. if (array == null)
  568. return null;
  569. var length = array.Length;
  570. var result = new TNew[length];
  571. for (var i = 0; i < length; ++i)
  572. result[i] = converter(array[i]);
  573. return result;
  574. }
  575. private static void Swap<TValue>(ref TValue first, ref TValue second)
  576. {
  577. var temp = first;
  578. first = second;
  579. second = temp;
  580. }
  581. /// <summary>
  582. /// Move a slice in the array to a different place without allocating a temporary array.
  583. /// </summary>
  584. /// <param name="array"></param>
  585. /// <param name="sourceIndex"></param>
  586. /// <param name="destinationIndex"></param>
  587. /// <param name="count"></param>
  588. /// <typeparam name="TValue"></typeparam>
  589. /// <remarks>
  590. /// The slice is moved by repeatedly swapping slices until all the slices are where they
  591. /// are supposed to go. This is not super efficient but avoids having to allocate a temporary
  592. /// array on the heap.
  593. /// </remarks>
  594. public static void MoveSlice<TValue>(TValue[] array, int sourceIndex, int destinationIndex, int count)
  595. {
  596. if (count <= 0 || sourceIndex == destinationIndex)
  597. return;
  598. // Determine the number of elements in the window.
  599. int elementCount;
  600. if (destinationIndex > sourceIndex)
  601. elementCount = destinationIndex + count - sourceIndex;
  602. else
  603. elementCount = sourceIndex + count - destinationIndex;
  604. // If the source and target slice are right next to each other, just go
  605. // and swap out the elements in both slices.
  606. if (elementCount == count * 2)
  607. {
  608. for (var i = 0; i < count; ++i)
  609. Swap(ref array[sourceIndex + i], ref array[destinationIndex + i]);
  610. }
  611. else
  612. {
  613. // There's elements in-between the two slices.
  614. //
  615. // The easiest way to picture this operation is as a rotation of the elements within
  616. // the window given by sourceIndex, destination, and count. Within that window, we are
  617. // simply treating it as a wrap-around buffer and then sliding the elements clockwise
  618. // or counter-clockwise (depending on whether we move up or down, respectively) through
  619. // the window.
  620. //
  621. // Unfortunately, we can't just memcopy the slices within that window as we have to
  622. // have a temporary copy in place in order to preserve element values. So instead, we
  623. // go and swap elements one by one, something that doesn't require anything other than
  624. // a single value temporary copy.
  625. // Determine the number of swaps we need to achieve the desired order. Swaps
  626. // operate in pairs so it's one less than the number of elements in the range.
  627. var swapCount = elementCount - 1;
  628. // We simply take sourceIndex as fixed and do all swaps from there until all
  629. // the elements in the window are in the right order. Each swap will put one
  630. // element in its final place.
  631. var dst = destinationIndex;
  632. for (var i = 0; i < swapCount; ++i)
  633. {
  634. // Swap source into its destination place. This puts the current sourceIndex
  635. // element in its final place.
  636. Swap(ref array[dst], ref array[sourceIndex]);
  637. // Find out where the element that we now swapped into sourceIndex should
  638. // actually go.
  639. if (destinationIndex > sourceIndex)
  640. {
  641. // Rotating clockwise.
  642. dst -= count;
  643. if (dst < sourceIndex)
  644. dst = destinationIndex + count - Math.Abs(sourceIndex - dst); // Wrap around.
  645. }
  646. else
  647. {
  648. // Rotating counter-clockwise.
  649. dst += count;
  650. if (dst >= sourceIndex + count)
  651. dst = destinationIndex + (dst - (sourceIndex + count)); // Wrap around.
  652. }
  653. }
  654. }
  655. }
  656. public static void EraseSliceWithCapacity<TValue>(ref TValue[] array, ref int length, int index, int count)
  657. {
  658. // Move elements down.
  659. if (count < length)
  660. Array.Copy(array, index + count, array, index, length - index - count);
  661. // Erase now vacant slots.
  662. for (var i = 0; i < count; ++i)
  663. array[length - i - 1] = default;
  664. length -= count;
  665. }
  666. public static void SwapElements<TValue>(this TValue[] array, int index1, int index2)
  667. {
  668. MemoryHelpers.Swap(ref array[index1], ref array[index2]);
  669. }
  670. public static void SwapElements<TValue>(this NativeArray<TValue> array, int index1, int index2)
  671. where TValue : struct
  672. {
  673. var temp = array[index1];
  674. array[index1] = array[index2];
  675. array[index2] = temp;
  676. }
  677. }
  678. }