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