using System;
using System.Diagnostics;
namespace Unity.Collections.LowLevel.Unsafe
{
///
/// A fixed-size buffer from which you can make allocations.
///
/// Allocations from a scratch allocator are not individually deallocated.
/// Instead, when you're done using all the allocations from a scratch allocator, you dispose the allocator as a whole.
[GenerateTestsForBurstCompatibility]
public unsafe struct UnsafeScratchAllocator
{
void* m_Pointer;
int m_LengthInBytes;
readonly int m_CapacityInBytes;
///
/// Initializes and returns an instance of UnsafeScratchAllocator.
///
/// An existing buffer to use as the allocator's internal buffer.
/// The size in bytes of the internal buffer.
public UnsafeScratchAllocator(void* ptr, int capacityInBytes)
{
m_Pointer = ptr;
m_LengthInBytes = 0;
m_CapacityInBytes = capacityInBytes;
}
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
void CheckAllocationDoesNotExceedCapacity(ulong requestedSize)
{
if (requestedSize > (ulong)m_CapacityInBytes)
throw new ArgumentException($"Cannot allocate more than provided size in UnsafeScratchAllocator. Requested: {requestedSize} Size: {m_LengthInBytes} Capacity: {m_CapacityInBytes}");
}
///
/// Returns an allocation from the allocator's internal buffer.
///
/// The size of the new allocation.
/// The alignment of the new allocation.
/// A pointer to the new allocation.
/// Thrown if the new allocation would exceed the capacity of the allocator.
public void* Allocate(int sizeInBytes, int alignmentInBytes)
{
if (sizeInBytes == 0)
return null;
var alignmentMask = (ulong)(alignmentInBytes - 1);
var end = (ulong)(IntPtr)m_Pointer + (ulong)m_LengthInBytes;
end = (end + alignmentMask) & ~alignmentMask;
var lengthInBytes = (byte*)(IntPtr)end - (byte*)m_Pointer;
lengthInBytes += sizeInBytes;
CheckAllocationDoesNotExceedCapacity((ulong)lengthInBytes);
m_LengthInBytes = (int)lengthInBytes;
return (void*)(IntPtr)end;
}
///
/// Returns an allocation from the allocator's internal buffer.
///
/// The allocation size in bytes is at least `count * sizeof(T)`. The space consumed by the allocation may be a little larger than this size due to alignment.
/// The type of element to allocate space for.
/// The number of elements to allocate space for. Defaults to 1.
/// A pointer to the new allocation.
/// Thrown if the new allocation would exceed the capacity of the allocator.
[GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
public void* Allocate(int count = 1) where T : unmanaged
{
return Allocate(UnsafeUtility.SizeOf() * count, UnsafeUtility.AlignOf());
}
}
}