Aucune description
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

DynamicArray.cs 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. namespace UnityEngine.Rendering
  5. {
  6. /// <summary>
  7. /// Generic growable array.
  8. /// </summary>
  9. /// <typeparam name="T">Type of the array.</typeparam>
  10. [DebuggerDisplay("Size = {size} Capacity = {capacity}")]
  11. public class DynamicArray<T> where T : new()
  12. {
  13. /// <summary>
  14. /// The C# array memory used to store the DynamicArray values in. This array's Length may be longer than the DynamicArrayLength. Objects beyond the length should not be referenced.
  15. /// </summary>
  16. protected T[] m_Array = null;
  17. /// <summary>
  18. /// Number of elements in the array. There may be more elements allocated. Use `capacity` to query the number of allocated items.
  19. /// </summary>
  20. public int size { get; protected set; }
  21. /// <summary>
  22. /// Allocated size of the array.
  23. /// </summary>
  24. public int capacity { get { return m_Array.Length; } }
  25. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  26. /// <summary>
  27. /// This keeps track of structural modifications to this array and allows us to raise exceptions when modifying during enumeration
  28. /// </summary>
  29. protected internal int version { get; protected set; }
  30. #endif
  31. /// <summary>
  32. /// Constructor.
  33. /// Defaults to a capacity of 32 elements. The size will be 0.
  34. /// </summary>
  35. public DynamicArray()
  36. {
  37. m_Array = new T[32];
  38. size = 0;
  39. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  40. version = 0;
  41. #endif
  42. }
  43. /// <summary>
  44. /// Constructor. This constructor allocates memory and sets the size of the array to the specified number of elements.
  45. /// </summary>
  46. /// <param name="size">Number of elements. The elements are initialized to the default value of the element type, 0 for integers.</param>
  47. public DynamicArray(int size)
  48. {
  49. m_Array = new T[size];
  50. this.size = size;
  51. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  52. version = 0;
  53. #endif
  54. }
  55. /// <summary>
  56. /// Constructor. This overload allows you to only allocate memory without setting the size.
  57. /// </summary>
  58. /// <param name="capacity">The number of elements to allocate.</param>
  59. /// <param name="resize">If true, also set the size of the array to the passed in capacity. If false, only allocate data but keep the size at 0.</param>
  60. public DynamicArray(int capacity, bool resize)
  61. {
  62. m_Array = new T[capacity];
  63. this.size = (resize) ? capacity : 0;
  64. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  65. version = 0;
  66. #endif
  67. }
  68. /// <summary>
  69. /// Constructor. This constructor allocates memory and does a deep copy of the provided array.
  70. /// </summary>
  71. /// <param name="deepCopy">Array to be copied</param>
  72. public DynamicArray(DynamicArray<T> deepCopy)
  73. {
  74. m_Array = new T[deepCopy.size];
  75. size = deepCopy.size;
  76. Array.Copy(deepCopy.m_Array, m_Array, size);
  77. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  78. version = 0;
  79. #endif
  80. }
  81. /// <summary>
  82. /// Clear the array of all elements.
  83. /// </summary>
  84. public void Clear()
  85. {
  86. size = 0;
  87. }
  88. /// <summary>
  89. /// Determines whether the DynamicArray contains a specific value.
  90. /// </summary>
  91. /// <param name="item">The object to locate in the DynamicArray.</param>
  92. /// <returns>true if item is found in the DynamicArray; otherwise, false.</returns>
  93. public bool Contains(T item)
  94. {
  95. return IndexOf(item) != -1;
  96. }
  97. /// <summary>
  98. /// Add an element to the array.
  99. /// </summary>
  100. /// <param name="value">Element to add to the array.</param>
  101. /// <returns>The index of the element.</returns>
  102. public int Add(in T value)
  103. {
  104. int index = size;
  105. // Grow array if needed;
  106. if (index >= m_Array.Length)
  107. {
  108. var newArray = new T[Math.Max(m_Array.Length * 2,1)];
  109. Array.Copy(m_Array, newArray, m_Array.Length);
  110. m_Array = newArray;
  111. }
  112. m_Array[index] = value;
  113. size++;
  114. BumpVersion();
  115. return index;
  116. }
  117. /// <summary>
  118. /// Adds the elements of the specified collection to the end of the DynamicArray.
  119. /// </summary>
  120. /// <param name="array">The array whose elements should be added to the end of the DynamicArray. The array itself cannot be null, but it can contain elements that are null, if type T is a reference type.</param>
  121. public void AddRange(DynamicArray<T> array)
  122. {
  123. // Save the size before reserve. Otherwise things break when self-appending i.e. `a.AddRange(a)`
  124. var addedSize = array.size;
  125. Reserve(size + addedSize, true);
  126. for (int i = 0; i < addedSize; ++i)
  127. m_Array[size++] = array[i];
  128. BumpVersion();
  129. }
  130. /// <summary>
  131. /// Insert an item in the DynamicArray.
  132. /// </summary>
  133. /// <param name="index">Index where the item should be inserted.</param>
  134. /// <param name="item">Item to be inserted in the DynamicArray.</param>
  135. public void Insert(int index, T item)
  136. {
  137. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  138. if (index < 0 || index > size)
  139. throw new IndexOutOfRangeException();
  140. #endif
  141. if (index == size)
  142. Add(item);
  143. else
  144. {
  145. Resize(size + 1, true);
  146. Array.Copy(m_Array, index, m_Array, index + 1, size - index);
  147. m_Array[index] = item;
  148. }
  149. }
  150. /// <summary>
  151. /// Removes the first occurrence of a specific object from the DynamicArray.
  152. /// </summary>
  153. /// <param name="item">The object to remove from the DynamicArray. The value can be null for reference types.</param>
  154. /// <returns>true if item is successfully removed; otherwise, false. This method also returns false if item was not found in the DynamicArray.</returns>
  155. public bool Remove(T item)
  156. {
  157. int index = IndexOf(item);
  158. if (index != -1)
  159. {
  160. RemoveAt(index);
  161. return true;
  162. }
  163. return false;
  164. }
  165. /// <summary>
  166. /// Removes the element at the specified index of the DynamicArray.
  167. /// </summary>
  168. /// <param name="index">The zero-based index of the element to remove.</param>
  169. public void RemoveAt(int index)
  170. {
  171. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  172. if (index < 0 || index >= size)
  173. throw new IndexOutOfRangeException();
  174. #endif
  175. if (index != size - 1)
  176. Array.Copy(m_Array, index + 1, m_Array, index, size - index - 1);
  177. size--;
  178. BumpVersion();
  179. }
  180. /// <summary>
  181. /// Removes a range of elements from the DynamicArray.
  182. /// </summary>
  183. /// <param name="index">The zero-based starting index of the range of elements to remove.</param>
  184. /// <param name="count">The number of elements to remove.</param>
  185. public void RemoveRange(int index, int count)
  186. {
  187. if (count == 0)
  188. return;
  189. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  190. if (index < 0 || index >= size || count < 0 || index + count > size)
  191. throw new ArgumentOutOfRangeException();
  192. #endif
  193. Array.Copy(m_Array, index + count, m_Array, index, size - index - count);
  194. size -= count;
  195. BumpVersion();
  196. }
  197. /// <summary>
  198. /// Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the range of elements in the DynamicArray that starts at the specified index and contains the specified number of elements.
  199. /// </summary>
  200. /// <param name="startIndex">The zero-based starting index of the search.</param>
  201. /// <param name="count">The number of elements in the section to search.</param>
  202. /// <param name="match">The Predicate delegate that defines the conditions of the element to search for.</param>
  203. /// <returns>The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, -1.</returns>
  204. public int FindIndex(int startIndex, int count, Predicate<T> match)
  205. {
  206. for (int i = startIndex; i < size; ++i)
  207. {
  208. if (match(m_Array[i]))
  209. {
  210. return i;
  211. }
  212. }
  213. return -1;
  214. }
  215. /// <summary>
  216. /// Searches for the specified object and returns the zero-based index of the first occurrence within the range of elements in the DynamicArray that starts at the specified index and contains the specified number of elements.
  217. /// </summary>
  218. /// <param name="item">The object to locate in the DynamicArray. The value can be null for reference types.</param>
  219. /// <param name="index">The zero-based starting index of the search. 0 (zero) is valid in an empty list.</param>
  220. /// <param name="count">The number of elements in the section to search.</param>
  221. /// <returns>The index of the first occurrence of the object within the range of elements, or -1 if not found.</returns>
  222. public int IndexOf(T item, int index, int count)
  223. {
  224. for (int i = index; i < size && count > 0; ++i, --count)
  225. {
  226. if (m_Array[i].Equals(item))
  227. {
  228. return i;
  229. }
  230. }
  231. return -1;
  232. }
  233. /// <summary>
  234. /// Searches for the specified object and returns the zero-based index of the first occurrence within the range of elements in the DynamicArray that extends from the specified index to the last element.
  235. /// </summary>
  236. /// <param name="item">The object to locate in the DynamicArray. The value can be null for reference types.</param>
  237. /// <param name="index">The zero-based starting index of the search. 0 (zero) is valid in an empty list.</param>
  238. /// <returns>The zero-based index of the first occurrence of item within the range of elements in the DynamicArray that extends from index to the last element, if found; otherwise, -1.</returns>
  239. public int IndexOf(T item, int index)
  240. {
  241. for (int i = index; i < size; ++i)
  242. {
  243. if (m_Array[i].Equals(item))
  244. {
  245. return i;
  246. }
  247. }
  248. return -1;
  249. }
  250. /// <summary>
  251. /// Searches for the specified object and returns the zero-based index of the first occurrence within the entire DynamicArray.
  252. /// </summary>
  253. /// <param name="item">The object to locate in the DynamicArray. The value can be null for reference types.</param>
  254. /// <returns>he zero-based index of the first occurrence of item within the entire DynamicArray, if found; otherwise, -1.</returns>
  255. public int IndexOf(T item)
  256. {
  257. return IndexOf(item, 0);
  258. }
  259. /// <summary>
  260. /// Resize the Dynamic Array.
  261. /// This will reallocate memory if necessary and set the current size of the array to the provided size.
  262. /// Note: The memory is not cleared so the elements may contain invalid data.
  263. /// </summary>
  264. /// <param name="newSize">New size for the array.</param>
  265. /// <param name="keepContent">Set to true if you want the current content of the array to be kept.</param>
  266. public void Resize(int newSize, bool keepContent = false)
  267. {
  268. Reserve(newSize, keepContent);
  269. size = newSize;
  270. BumpVersion();
  271. }
  272. /// <summary>
  273. /// Resize the Dynamic Array.
  274. /// This will reallocate memory if necessary and set the current size of the array to the provided size.
  275. /// The elements are initialized to the default value of the element type, e.g. 0 for integers.
  276. /// </summary>
  277. /// <param name="newSize">New size for the array.</param>
  278. public void ResizeAndClear(int newSize)
  279. {
  280. if (newSize > m_Array.Length)
  281. {
  282. // Reserve will allocate a whole new array that is cleared as part of the allocation
  283. Reserve(newSize, false);
  284. }
  285. else
  286. {
  287. // We're not reallocating anything we need to clear the old values to the default.
  288. Array.Clear(m_Array, 0, newSize);
  289. }
  290. size = newSize;
  291. BumpVersion();
  292. }
  293. /// <summary>
  294. /// Sets the total number of elements the internal data structure can hold without resizing.
  295. /// </summary>
  296. /// <param name="newCapacity">New capacity for the array.</param>
  297. /// <param name="keepContent">Set to true if you want the current content of the array to be kept.</param>
  298. public void Reserve(int newCapacity, bool keepContent = false)
  299. {
  300. if (newCapacity > m_Array.Length)
  301. {
  302. if (keepContent)
  303. {
  304. var newArray = new T[newCapacity];
  305. Array.Copy(m_Array, newArray, m_Array.Length);
  306. m_Array = newArray;
  307. }
  308. else
  309. {
  310. m_Array = new T[newCapacity];
  311. }
  312. }
  313. }
  314. /// <summary>
  315. /// ref access to an element.
  316. /// </summary>
  317. /// <param name="index">Element index</param>
  318. /// <value>The requested element.</value>
  319. public ref T this[int index]
  320. {
  321. get
  322. {
  323. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  324. if (index < 0 || index >= size)
  325. throw new IndexOutOfRangeException();
  326. #endif
  327. return ref m_Array[index];
  328. }
  329. }
  330. /// <summary>
  331. /// Implicit conversion to regular array.
  332. /// </summary>
  333. /// <param name="array">Input DynamicArray.</param>
  334. /// <returns>The internal array.</returns>
  335. [Obsolete("This is deprecated because it returns an incorrect value. It may returns an array with elements beyond the size. Please use Span/ReadOnly if you want safe raw access to the DynamicArray memory.",false)]
  336. public static implicit operator T[](DynamicArray<T> array) => array.m_Array;
  337. /// <summary>
  338. /// Implicit conversion to ReadOnlySpan.
  339. /// </summary>
  340. /// <param name="array">Input DynamicArray.</param>
  341. /// <returns>The internal array.</returns>
  342. public static implicit operator ReadOnlySpan<T>(DynamicArray<T> array) => new ReadOnlySpan<T>(array.m_Array, 0, array.size);
  343. /// <summary>
  344. /// Implicit conversion to Span.
  345. /// </summary>
  346. /// <param name="array">Input DynamicArray.</param>
  347. /// <returns>The internal array.</returns>
  348. public static implicit operator Span<T>(DynamicArray<T> array) => new Span<T>(array.m_Array, 0, array.size);
  349. /// <summary>
  350. /// IEnumerator-like struct used to loop over this entire array. See the IEnumerator docs for more info:
  351. /// <a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.ienumerator">IEnumerator</a>
  352. /// </summary>
  353. /// <remarks>
  354. /// This struct intentionally does not explicitly implement the IEnumarable/IEnumerator interfaces it just follows
  355. /// the same function signatures. This means the duck typing used by <c>foreach</c> on the compiler level will
  356. /// pick it up as IEnumerable but at the same time avoids generating Garbage.
  357. /// For more info, see the C# language specification of the <c>foreach</c> statement.
  358. /// </remarks>
  359. /// <seealso cref="RangeIterator"/>
  360. public struct Iterator
  361. {
  362. private readonly DynamicArray<T> owner;
  363. private int index;
  364. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  365. private int localVersion;
  366. #endif
  367. /// <summary>
  368. /// Creates an iterator to iterate over an array.
  369. /// </summary>
  370. /// <param name="setOwner">The array to iterate over.</param>
  371. /// <exception cref="ArgumentNullException">Thrown if the array is null.</exception>
  372. public Iterator(DynamicArray<T> setOwner)
  373. {
  374. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  375. if (setOwner == null)
  376. throw new ArgumentNullException();
  377. #endif
  378. owner = setOwner;
  379. index = -1;
  380. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  381. localVersion = owner.version;
  382. #endif
  383. }
  384. /// <summary>
  385. /// Gets the element in the DynamicArray at the current position of the iterator.
  386. /// </summary>
  387. public ref T Current
  388. {
  389. get
  390. {
  391. return ref owner[index];
  392. }
  393. }
  394. /// <summary>
  395. /// Advances the iterator to the next element of the DynamicArray.
  396. /// </summary>
  397. /// <returns>Returns <c>true</c> if the iterator has successfully advanced to the next element; <c>false</c> if the iterator has passed the end of the DynamicArray.</returns>
  398. /// <exception cref="InvalidOperationException">An operation changed the DynamicArray after the creation of this iterator.</exception>
  399. public bool MoveNext()
  400. {
  401. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  402. if (owner.version != localVersion)
  403. {
  404. throw new InvalidOperationException("DynamicArray was modified during enumeration");
  405. }
  406. #endif
  407. index++;
  408. return index < owner.size;
  409. }
  410. /// <summary>
  411. /// Sets the iterator to its initial position, which is before the first element in the DynamicArray.
  412. /// </summary>
  413. public void Reset()
  414. {
  415. index = -1;
  416. }
  417. }
  418. /// <summary>
  419. /// Returns an enumerator that iterates through of this array.
  420. /// See the IEnumerable docs for more info: <a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.ienumerable" >IEnumerable</a>
  421. /// </summary>
  422. /// <remarks>
  423. /// The returned struct intentionally does not explicitly implement the IEnumarable/IEnumerator interfaces it just follows
  424. /// the same function signatures. This means the duck typing used by <c>foreach</c> on the compiler level will
  425. /// pick it up as IEnumerable but at the same time avoids generating Garbage.
  426. /// For more info, see the C# language specification of the <c>foreach</c> statement.
  427. /// </remarks>
  428. /// <returns>Iterator pointing before the first element in the array.</returns>
  429. public Iterator GetEnumerator()
  430. {
  431. return new Iterator(this);
  432. }
  433. /// <summary>
  434. /// IEnumerable-like struct used to iterate through a subsection of this array.
  435. /// See the IEnumerable docs for more info: <a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.ienumerable">IEnumerable</a>
  436. /// </summary>
  437. /// <remarks>
  438. /// This struct intentionally does not explicitly implement the IEnumarable/IEnumerator interfaces it just follows
  439. /// the same function signatures. This means the duck typing used by <c>foreach</c> on the compiler level will
  440. /// pick it up as IEnumerable but at the same time avoids generating Garbage.
  441. /// For more info, see the C# language specification of the <c>foreach</c> statement.
  442. /// </remarks>
  443. /// <seealso cref="SubRange"/>
  444. public struct RangeEnumerable
  445. {
  446. /// <summary>
  447. /// IEnumerator-like struct used to iterate through a subsection of this array.
  448. /// See the IEnumerator docs for more info: <a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.ienumerator">IEnumerator</a>
  449. /// </summary>
  450. /// <remarks>
  451. /// This struct intentionally does not explicitly implement the IEnumarable/IEnumerator interfaces it just follows
  452. /// the same function signatures. This means the duck typing used by <c>foreach</c> on the compiler level will
  453. /// pick it up as <c>IEnumarable</c> but at the same time avoids generating Garbage.
  454. /// For more info, see the C# language specification of the <c>foreach</c> statement.
  455. /// </remarks>
  456. /// <seealso cref="SubRange"/>
  457. public struct RangeIterator
  458. {
  459. private readonly DynamicArray<T> owner;
  460. private int index;
  461. private int first;
  462. private int last;
  463. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  464. private int localVersion;
  465. #endif
  466. /// <summary>
  467. /// Create an iterator to iterate over the given range in the array.
  468. /// </summary>
  469. /// <param name="setOwner">The array to iterate over.</param>
  470. /// <param name="first">The index of the first item in the array.</param>
  471. /// <param name="numItems">The number of array members to iterate through.</param>
  472. /// <exception cref="ArgumentNullException">Thrown if the array is null.</exception>
  473. public RangeIterator(DynamicArray<T> setOwner, int first, int numItems)
  474. {
  475. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  476. if (setOwner == null)
  477. throw new ArgumentNullException();
  478. if (first < 0 || first > setOwner.size || (first + numItems) > setOwner.size)
  479. throw new IndexOutOfRangeException();
  480. #endif
  481. owner = setOwner;
  482. this.first = first;
  483. index = first-1;
  484. last = first + numItems;
  485. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  486. localVersion = owner.version;
  487. #endif
  488. }
  489. /// <summary>
  490. /// Gets the element in the DynamicArray at the current position of the iterator.
  491. /// </summary>
  492. public ref T Current
  493. {
  494. get
  495. {
  496. return ref owner[index];
  497. }
  498. }
  499. /// <summary>
  500. /// Advances the iterator to the next element of the DynamicArray.
  501. /// </summary>
  502. /// <returns>Returs <c>true</c> if the iterator successfully advanced to the next element; returns <c>false</c> if the iterator has passed the end of the range.</returns>
  503. /// <exception cref="InvalidOperationException">The DynamicArray was modified after the iterator was created.</exception>
  504. public bool MoveNext()
  505. {
  506. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  507. if (owner.version != localVersion)
  508. {
  509. throw new InvalidOperationException("DynamicArray was modified during enumeration");
  510. }
  511. #endif
  512. index++;
  513. return index < last;
  514. }
  515. /// <summary>
  516. /// Sets the iterator to its initial position, which is before the first element in the range.
  517. /// </summary>
  518. public void Reset()
  519. {
  520. index = first-1;
  521. }
  522. }
  523. /// <summary>
  524. /// The iterator associated with this Enumerable.
  525. /// </summary>
  526. public RangeIterator iterator;
  527. /// <summary>
  528. /// Returns an enumerator that iterates through this array.
  529. /// </summary>
  530. /// <remarks>
  531. /// The returned struct intentionally does not explicitly implement the IEnumarable/IEnumerator interfaces it just follows
  532. /// the same function signatures. This means the duck typing used by <c>foreach</c> on the compiler level will
  533. /// pick it up as IEnumerable but at the same time avoids generating Garbage.
  534. /// For more info, see the C# language specification of the <c>foreach</c> statement.
  535. /// </remarks>
  536. /// <returns>Iterator pointing before the first element in the range.</returns>
  537. public RangeIterator GetEnumerator()
  538. {
  539. return iterator;
  540. }
  541. }
  542. /// <summary>
  543. /// Returns an IEnumeralbe-Like object that iterates through a subsection of this array.
  544. /// </summary>
  545. /// <remarks>
  546. /// The returned struct intentionally does not explicitly implement the IEnumarable/IEnumerator interfaces it just follows
  547. /// the same function signatures. This means the duck typing used by <c>foreach</c> on the compiler level will
  548. /// pick it up as IEnumerable but at the same time avoids generating Garbage.
  549. /// For more info, see the C# language specification of the <c>foreach</c> statement.
  550. /// </remarks>
  551. /// <param name="first">The index of the first item</param>
  552. /// <param name="numItems">The number of items to iterate</param>
  553. /// <returns><c>RangeEnumerable</c> that can be used to enumerate the given range.</returns>
  554. /// <seealso cref="RangeIterator"/>
  555. public RangeEnumerable SubRange(int first, int numItems)
  556. {
  557. RangeEnumerable r = new RangeEnumerable { iterator = new RangeEnumerable.RangeIterator(this, first, numItems) };
  558. return r;
  559. }
  560. /// <summary>
  561. /// Increments the internal version counter.
  562. /// </summary>
  563. protected internal void BumpVersion()
  564. {
  565. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  566. version++;
  567. #endif
  568. }
  569. /// <summary>
  570. /// Delegate for custom sorting comparison.
  571. /// </summary>
  572. /// <param name="x">First object.</param>
  573. /// <param name="y">Second object.</param>
  574. /// <returns>-1 if x smaller than y, 1 if x bigger than y and 0 otherwise.</returns>
  575. public delegate int SortComparer(T x, T y);
  576. }
  577. /// <summary>
  578. /// Extension class for DynamicArray
  579. /// </summary>
  580. public static class DynamicArrayExtensions
  581. {
  582. static int Partition<T>(Span<T> data, int left, int right) where T : IComparable<T>, new()
  583. {
  584. var pivot = data[left];
  585. --left;
  586. ++right;
  587. while (true)
  588. {
  589. var c = 0;
  590. var lvalue = default(T);
  591. do
  592. {
  593. ++left;
  594. lvalue = data[left];
  595. c = lvalue.CompareTo(pivot);
  596. }
  597. while (c < 0);
  598. var rvalue = default(T);
  599. do
  600. {
  601. --right;
  602. rvalue = data[right];
  603. c = rvalue.CompareTo(pivot);
  604. }
  605. while (c > 0);
  606. if (left < right)
  607. {
  608. data[right] = lvalue;
  609. data[left] = rvalue;
  610. }
  611. else
  612. {
  613. return right;
  614. }
  615. }
  616. }
  617. static void QuickSort<T>(Span<T> data, int left, int right) where T : IComparable<T>, new()
  618. {
  619. if (left < right)
  620. {
  621. int pivot = Partition(data, left, right);
  622. if (pivot >= 1)
  623. QuickSort(data, left, pivot);
  624. if (pivot + 1 < right)
  625. QuickSort(data, pivot + 1, right);
  626. }
  627. }
  628. // C# SUCKS
  629. // Had to copy paste because it's apparently impossible to pass a sort delegate where T is Comparable<T>, otherwise some boxing happens and allocates...
  630. // So two identical versions of the function, one with delegate but no Comparable and the other with just the comparable.
  631. static int Partition<T>(Span<T> data, int left, int right, DynamicArray<T>.SortComparer comparer) where T : new()
  632. {
  633. var pivot = data[left];
  634. --left;
  635. ++right;
  636. while (true)
  637. {
  638. var c = 0;
  639. var lvalue = default(T);
  640. do
  641. {
  642. ++left;
  643. lvalue = data[left];
  644. c = comparer(lvalue, pivot);
  645. }
  646. while (c < 0);
  647. var rvalue = default(T);
  648. do
  649. {
  650. --right;
  651. rvalue = data[right];
  652. c = comparer(rvalue, pivot);
  653. }
  654. while (c > 0);
  655. if (left < right)
  656. {
  657. data[right] = lvalue;
  658. data[left] = rvalue;
  659. }
  660. else
  661. {
  662. return right;
  663. }
  664. }
  665. }
  666. static void QuickSort<T>(Span<T> data, int left, int right, DynamicArray<T>.SortComparer comparer) where T : new()
  667. {
  668. if (left < right)
  669. {
  670. int pivot = Partition(data, left, right, comparer);
  671. if (pivot >= 1)
  672. QuickSort(data, left, pivot, comparer);
  673. if (pivot + 1 < right)
  674. QuickSort(data, pivot + 1, right, comparer);
  675. }
  676. }
  677. /// <summary>
  678. /// Perform a quick sort on the DynamicArray
  679. /// </summary>
  680. /// <typeparam name="T">Type of the array.</typeparam>
  681. /// <param name="array">Array on which to perform the quick sort.</param>
  682. public static void QuickSort<T>(this DynamicArray<T> array) where T : IComparable<T>, new()
  683. {
  684. QuickSort<T>(array, 0, array.size - 1);
  685. array.BumpVersion();
  686. }
  687. /// <summary>
  688. /// Perform a quick sort on the DynamicArray
  689. /// </summary>
  690. /// <typeparam name="T">Type of the array.</typeparam>
  691. /// <param name="array">Array on which to perform the quick sort.</param>
  692. /// <param name="comparer">Comparer used for sorting.</param>
  693. public static void QuickSort<T>(this DynamicArray<T> array, DynamicArray<T>.SortComparer comparer) where T : new()
  694. {
  695. QuickSort<T>(array, 0, array.size - 1, comparer);
  696. array.BumpVersion();
  697. }
  698. }
  699. }