A game about forced loneliness, made by TACStudios
1using System;
2using System.Diagnostics;
3
4namespace Unity.Collections.LowLevel.Unsafe
5{
6 /// <summary>
7 /// A fixed-size buffer from which you can make allocations.
8 /// </summary>
9 /// <remarks>Allocations from a scratch allocator are not individually deallocated.
10 /// Instead, when you're done using all the allocations from a scratch allocator, you dispose the allocator as a whole.</remarks>
11 [GenerateTestsForBurstCompatibility]
12 public unsafe struct UnsafeScratchAllocator
13 {
14 void* m_Pointer;
15 int m_LengthInBytes;
16 readonly int m_CapacityInBytes;
17
18 /// <summary>
19 /// Initializes and returns an instance of UnsafeScratchAllocator.
20 /// </summary>
21 /// <param name="ptr">An existing buffer to use as the allocator's internal buffer.</param>
22 /// <param name="capacityInBytes">The size in bytes of the internal buffer.</param>
23 public UnsafeScratchAllocator(void* ptr, int capacityInBytes)
24 {
25 m_Pointer = ptr;
26 m_LengthInBytes = 0;
27 m_CapacityInBytes = capacityInBytes;
28 }
29
30 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
31 void CheckAllocationDoesNotExceedCapacity(ulong requestedSize)
32 {
33 if (requestedSize > (ulong)m_CapacityInBytes)
34 throw new ArgumentException($"Cannot allocate more than provided size in UnsafeScratchAllocator. Requested: {requestedSize} Size: {m_LengthInBytes} Capacity: {m_CapacityInBytes}");
35 }
36
37 /// <summary>
38 /// Returns an allocation from the allocator's internal buffer.
39 /// </summary>
40 /// <param name="sizeInBytes">The size of the new allocation.</param>
41 /// <param name="alignmentInBytes">The alignment of the new allocation.</param>
42 /// <returns>A pointer to the new allocation.</returns>
43 /// <exception cref="ArgumentException">Thrown if the new allocation would exceed the capacity of the allocator.</exception>
44 public void* Allocate(int sizeInBytes, int alignmentInBytes)
45 {
46 if (sizeInBytes == 0)
47 return null;
48 var alignmentMask = (ulong)(alignmentInBytes - 1);
49 var end = (ulong)(IntPtr)m_Pointer + (ulong)m_LengthInBytes;
50 end = (end + alignmentMask) & ~alignmentMask;
51 var lengthInBytes = (byte*)(IntPtr)end - (byte*)m_Pointer;
52 lengthInBytes += sizeInBytes;
53 CheckAllocationDoesNotExceedCapacity((ulong)lengthInBytes);
54 m_LengthInBytes = (int)lengthInBytes;
55 return (void*)(IntPtr)end;
56 }
57
58 /// <summary>
59 /// Returns an allocation from the allocator's internal buffer.
60 /// </summary>
61 /// <remarks>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.</remarks>
62 /// <typeparam name="T">The type of element to allocate space for.</typeparam>
63 /// <param name="count">The number of elements to allocate space for. Defaults to 1.</param>
64 /// <returns>A pointer to the new allocation.</returns>
65 /// <exception cref="ArgumentException">Thrown if the new allocation would exceed the capacity of the allocator.</exception>
66 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
67 public void* Allocate<T>(int count = 1) where T : unmanaged
68 {
69 return Allocate(UnsafeUtility.SizeOf<T>() * count, UnsafeUtility.AlignOf<T>());
70 }
71 }
72}