using System; using System.Collections.Generic; namespace UnityEngine.Rendering { /// /// Generic growable array. /// /// Type of the array. public class DynamicArray where T : new() { T[] m_Array = null; /// /// Number of elements in the array. /// public int size { get; private set; } /// /// Allocated size of the array. /// public int capacity { get { return m_Array.Length; } } /// /// Constructor. /// Defaults to a size of 32 elements. /// public DynamicArray() { m_Array = new T[32]; size = 0; } /// /// Constructor /// /// Number of elements. public DynamicArray(int size) { m_Array = new T[size]; this.size = size; } /// /// Clear the array of all elements. /// public void Clear() { size = 0; } /// /// Determines whether the DynamicArray contains a specific value. /// /// The object to locate in the DynamicArray. /// true if item is found in the DynamicArray; otherwise, false. public bool Contains(T item) { return IndexOf(item) != -1; } /// /// Add an element to the array. /// /// Element to add to the array. /// The index of the element. public int Add(in T value) { int index = size; // Grow array if needed; if (index >= m_Array.Length) { var newArray = new T[m_Array.Length * 2]; Array.Copy(m_Array, newArray, m_Array.Length); m_Array = newArray; } m_Array[index] = value; size++; return index; } /// /// Adds the elements of the specified collection to the end of the DynamicArray. /// /// 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. public void AddRange(DynamicArray array) { Reserve(size + array.size, true); for (int i = 0; i < array.size; ++i) m_Array[size++] = array[i]; } /// /// Removes the first occurrence of a specific object from the DynamicArray. /// /// The object to remove from the DynamicArray. The value can be null for reference types. /// true if item is successfully removed; otherwise, false. This method also returns false if item was not found in the DynamicArray. public bool Remove(T item) { int index = IndexOf(item); if (index != -1) { RemoveAt(index); return true; } return false; } /// /// Removes the element at the specified index of the DynamicArray. /// /// The zero-based index of the element to remove. public void RemoveAt(int index) { if (index < 0 || index >= size) throw new IndexOutOfRangeException(); if (index != size - 1) Array.Copy(m_Array, index + 1, m_Array, index, size - index - 1); size--; } /// /// Removes a range of elements from the DynamicArray. /// /// The zero-based starting index of the range of elements to remove. /// The number of elements to remove. public void RemoveRange(int index, int count) { if (index < 0 || index >= size || count < 0 || index + count > size) throw new ArgumentOutOfRangeException(); Array.Copy(m_Array, index + count, m_Array, index, size - index - count); size -= count; } /// /// 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. /// /// The zero-based starting index of the search. /// The number of elements in the section to search. /// The Predicate delegate that defines the conditions of the element to search for. /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, -1. public int FindIndex(int startIndex, int count, Predicate match) { for (int i = startIndex; i < size; ++i) { if (match(m_Array[i])) { return i; } } return -1; } /// /// 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. /// /// The object to locate in the DynamicArray. The value can be null for reference types. /// The zero-based starting index of the search. 0 (zero) is valid in an empty list. /// The number of elements in the section to search. /// public int IndexOf(T item, int index, int count) { for (int i = index; i < size && count > 0; ++i, --count) { if (m_Array[i].Equals(item)) { return i; } } return -1; } /// /// 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. /// /// The object to locate in the DynamicArray. The value can be null for reference types. /// The zero-based starting index of the search. 0 (zero) is valid in an empty list. /// 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. public int IndexOf(T item, int index) { for (int i = index; i < size; ++i) { if (m_Array[i].Equals(item)) { return i; } } return -1; } /// /// Searches for the specified object and returns the zero-based index of the first occurrence within the entire DynamicArray. /// /// The object to locate in the DynamicArray. The value can be null for reference types. /// he zero-based index of the first occurrence of item within the entire DynamicArray, if found; otherwise, -1. public int IndexOf(T item) { return IndexOf(item, 0); } /// /// Resize the Dynamic Array. /// This will reallocate memory if necessary and set the current size of the array to the provided size. /// /// New size for the array. /// Set to true if you want the current content of the array to be kept. public void Resize(int newSize, bool keepContent = false) { Reserve(newSize, keepContent); size = newSize; } /// /// Sets the total number of elements the internal data structure can hold without resizing. /// /// New capacity for the array. /// Set to true if you want the current content of the array to be kept. public void Reserve(int newCapacity, bool keepContent = false) { if (newCapacity > m_Array.Length) { if (keepContent) { var newArray = new T[newCapacity]; Array.Copy(m_Array, newArray, m_Array.Length); m_Array = newArray; } else { m_Array = new T[newCapacity]; } } } /// /// ref access to an element. /// /// Element index /// The requested element. public ref T this[int index] { get { #if DEVELOPMENT_BUILD || UNITY_EDITOR if (index >= size) throw new IndexOutOfRangeException(); #endif return ref m_Array[index]; } } /// /// Implicit conversion to regular array. /// /// Input DynamicArray. /// The internal array. public static implicit operator T[](DynamicArray array) => array.m_Array; } /// /// Extension class for DynamicArray /// public static class DynamicArrayExtensions { static int Partition(T[] data, int left, int right) where T : IComparable, new() { var pivot = data[left]; --left; ++right; while (true) { var c = 0; var lvalue = default(T); do { ++left; lvalue = data[left]; c = lvalue.CompareTo(pivot); } while (c < 0); var rvalue = default(T); do { --right; rvalue = data[right]; c = rvalue.CompareTo(pivot); } while (c > 0); if (left < right) { data[right] = lvalue; data[left] = rvalue; } else { return right; } } } static void QuickSort(T[] data, int left, int right) where T : IComparable, new() { if (left < right) { int pivot = Partition(data, left, right); if (pivot >= 1) QuickSort(data, left, pivot); if (pivot + 1 < right) QuickSort(data, pivot + 1, right); } } /// /// Perform a quick sort on the DynamicArray /// /// Type of the array. /// Array on which to perform the quick sort. public static void QuickSort(this DynamicArray array) where T : IComparable, new() { QuickSort(array, 0, array.size - 1); } } }