using System; using Unity.Collections.LowLevel.Unsafe; namespace UnityEngine.Rendering { /// /// A list that stores value on a provided memory buffer. /// /// Usually use this to have a list on stack allocated memory. /// /// The type of the data stored in the list. public unsafe struct ListBuffer where T : unmanaged { private T* m_BufferPtr; private int m_Capacity; private int* m_CountPtr; /// /// The pointer to the memory storage. /// internal T* BufferPtr => m_BufferPtr; /// /// The number of item in the list. /// public int Count => *m_CountPtr; /// /// The maximum number of item stored in this list. /// public int Capacity => m_Capacity; /// /// Instantiate a new list. /// /// The address in memory to store the data. /// The address in memory to store the number of item of this list.. /// The number of that can be stored in the buffer. public ListBuffer(T* bufferPtr, int* countPtr, int capacity) { m_BufferPtr = bufferPtr; m_Capacity = capacity; m_CountPtr = countPtr; } /// /// Get an item from the list. /// /// The index of the item to get. /// A reference to the item. /// If the index is invalid. public ref T this[in int index] { get { if (index < 0 || index >= Count) throw new IndexOutOfRangeException( $"Expected a value between 0 and {Count}, but received {index}."); return ref m_BufferPtr[index]; } } /// /// Get an item from the list. /// /// Safety: index must be inside the bounds of the list. /// /// The index of the item to get. /// A reference to the item. public unsafe ref T GetUnchecked(in int index) => ref m_BufferPtr[index]; /// /// Try to add a value in the list. /// /// A reference to the value to add. /// /// true when the value was added, /// false when the value was not added because the capacity was reached. /// public bool TryAdd(in T value) { if (Count >= m_Capacity) return false; m_BufferPtr[Count] = value; ++*m_CountPtr; return true; } /// /// Copy the content of this list into another buffer in memory. /// /// Safety: /// * The destination must have enough memory to receive the copied data. /// /// The destination buffer of the copy operation. /// The index of the first element that will be copied in the destination buffer. /// The number of item to copy. public unsafe void CopyTo(T* dstBuffer, int startDstIndex, int copyCount) { UnsafeUtility.MemCpy(dstBuffer + startDstIndex, m_BufferPtr, UnsafeUtility.SizeOf() * copyCount); } /// /// Try to copy the list into another list. /// /// The destination of the copy. /// /// * true when the copy was performed. /// * false when the copy was aborted because the destination have a capacity too small. /// public bool TryCopyTo(ListBuffer other) { if (other.Count + Count >= other.m_Capacity) return false; UnsafeUtility.MemCpy(other.m_BufferPtr + other.Count, m_BufferPtr, UnsafeUtility.SizeOf() * Count); *other.m_CountPtr += Count; return true; } /// /// Try to copy the data from a buffer in this list. /// /// The pointer of the source memory to copy. /// The number of item to copy from the source buffer. /// /// * true when the copy was performed. /// * false when the copy was aborted because the capacity of this list is too small. /// public bool TryCopyFrom(T* srcPtr, int count) { if (count + Count > m_Capacity) return false; UnsafeUtility.MemCpy(m_BufferPtr + Count, srcPtr, UnsafeUtility.SizeOf() * count); *m_CountPtr += count; return true; } } /// /// Extensions for . /// public static class ListBufferExtensions { /// /// Perform a quick sort on a . /// /// The list to sort. /// The type of the element in the list. public static void QuickSort(this ListBuffer self) where T : unmanaged, IComparable { unsafe { CoreUnsafeUtils.QuickSort(self.Count, self.BufferPtr); } } } }