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);
}
}
}
}