#region allocator-rewindable-example using System; using NUnit.Framework; using Unity.Collections; // This is the example code used in // Packages/com.unity.collections/Documentation~/allocator/allocator-rewindable.md // Example user structure internal struct ExampleStruct { // Use AllocatorHelper to help creating a rewindable alloctor AllocatorHelper rwdAllocatorHelper; // Rewindable allocator property for accessibility public ref RewindableAllocator RwdAllocator => ref rwdAllocatorHelper.Allocator; // Create the rewindable allocator void CreateRewindableAllocator(AllocatorManager.AllocatorHandle backgroundAllocator, int initialBlockSize, bool enableBlockFree = false) { // Allocate the rewindable allocator from backgroundAllocator and register the allocator rwdAllocatorHelper = new AllocatorHelper(backgroundAllocator); // Allocate the first memory block with initialBlockSize in bytes, and indicate whether // to enable the rewindable allocator with individual block free through enableBlockFree RwdAllocator.Initialize(initialBlockSize, enableBlockFree); } // Constructor of user structure public ExampleStruct(int initialBlockSize) { this = default; CreateRewindableAllocator(Allocator.Persistent, initialBlockSize, false); } // Dispose the user structure public void Dispose() { DisposeRewindableAllocator(); } #region allocator-rewindable-use // Sample code to use rewindable allocator to allocate containers public unsafe void UseRewindableAllocator(out NativeArray nativeArray, out NativeList nativeList, out byte* bytePtr) { // Use rewindable allocator to allocate a native array, no need to dispose the array manually // CollectionHelper is required to create/allocate native array from a custom allocator. nativeArray = CollectionHelper.CreateNativeArray(100, ref RwdAllocator); nativeArray[0] = 0xFE; // Use rewindable allocator to allocate a native list, do not need to dispose the list manually nativeList = new NativeList(RwdAllocator.Handle); for (int i = 0; i < 50; i++) { nativeList.Add(i); } // Use custom allocator to allocate a byte buffer. bytePtr = (byte*)AllocatorManager.Allocate(ref RwdAllocator, sizeof(byte), sizeof(byte), 10); bytePtr[0] = 0xAB; } #endregion // allocator-rewindable-use #region allocator-rewindable-free // Free all allocations from the rewindable allocator public void FreeRewindableAllocator() { RwdAllocator.Rewind(); } #endregion // allocator-rewindable-free #region allocator-rewindable-dispose // Dispose the rewindable allocator void DisposeRewindableAllocator() { // Dispose all the memory blocks in the rewindable allocator RwdAllocator.Dispose(); // Unregister the rewindable allocator and dispose it rwdAllocatorHelper.Dispose(); } #endregion // allocator-rewindable-dispose } internal class ExampleStructSampleUsage { // Initial block size of the rewindable allocator. const int IntialBlockSize = 128 * 1024; [Test] public unsafe void UseRewindableAllocator_Works() { ExampleStruct exampleStruct = new ExampleStruct(IntialBlockSize); // Allocate native array and native list from rewindable allocator exampleStruct.UseRewindableAllocator(out NativeArray nativeArray, out NativeList nativeList, out byte* bytePtr); // Still able to access the native array, native list and byte buffer Assert.AreEqual(nativeArray[0], 0xFE); Assert.AreEqual(nativeList[10], 10); Assert.AreEqual(bytePtr[0], 0xAB); // Free all memories allocated from the rewindable allocator // No need to dispose the native array and native list exampleStruct.FreeRewindableAllocator(); #if ENABLE_UNITY_COLLECTIONS_CHECKS // Object disposed exception throws because nativeArray is already disposed Assert.Throws(() => { nativeArray[0] = 0xEF; }); // Object disposed exception throws because nativeList is already disposed Assert.Throws(() => { nativeList[10] = 0x10; }); #endif // Dispose the user structure exampleStruct.Dispose(); } } #endregion // allocator-rewindable-example