A game about forced loneliness, made by TACStudios
at master 167 lines 6.3 kB view raw
1// Example code used in trunk, unity/Documentation/ApiDocs/Unity.Collections.LowLevel.Unsafe/NativeContainerAttribute.mem.xml 2 3using System.Diagnostics; 4using System; 5using Unity.Collections.LowLevel.Unsafe; 6using Unity.Collections; 7using Unity.Burst; 8 9// Marks our struct as a NativeContainer. 10// If ENABLE_UNITY_COLLECTIONS_CHECKS is enabled, 11// it is required that m_Safety with exactly this name. 12[NativeContainer] 13// The [NativeContainerSupportsMinMaxWriteRestriction] enables 14// a common jobification pattern where an IJobParallelFor is split into ranges 15// And the job is only allowed to access the index range being Executed by that worker thread. 16// Effectively limiting access of the array to the specific index passed into the Execute(int index) method 17// This attribute requires m_MinIndex & m_MaxIndex to exist. 18// and the container is expected to perform out of bounds checks against it. 19// m_MinIndex & m_MaxIndex will be set by the job scheduler before Execute is called on the worker thread. 20[NativeContainerSupportsMinMaxWriteRestriction] 21// It is recommended to always implement a Debugger proxy 22// to visualize the contents of the array in VisualStudio and other tools. 23[DebuggerDisplay("Length = {Length}")] 24[DebuggerTypeProxy(typeof(NativeCustomArrayDebugView<>))] 25internal unsafe struct NativeCustomArray<T> : IDisposable where T : unmanaged 26{ 27 internal void* m_Buffer; 28 internal int m_Length; 29 30#if ENABLE_UNITY_COLLECTIONS_CHECKS 31 internal int m_MinIndex; 32 internal int m_MaxIndex; 33 internal AtomicSafetyHandle m_Safety; 34 internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<NativeCustomArray<T>>(); 35#endif 36 37 internal Allocator m_AllocatorLabel; 38 39 public NativeCustomArray(int length, Allocator allocator) 40 { 41 int totalSize = UnsafeUtility.SizeOf<T>() * length; 42 43#if ENABLE_UNITY_COLLECTIONS_CHECKS 44 // Native allocation is only valid for Temp, TempJob, Persistent or registered custom allocator 45 if (allocator <= Allocator.None) 46 throw new ArgumentException("Allocator must be Temp, TempJob, Persistent or registered custom allcoator", "allocator"); 47 if (length < 0) 48 throw new ArgumentOutOfRangeException("length", "Length must be >= 0"); 49 if (!UnsafeUtility.IsBlittable<T>()) 50 throw new ArgumentException(string.Format("{0} used in NativeCustomArray<{0}> must be blittable", typeof(T))); 51#endif 52 53 m_Buffer = AllocatorManager.Allocate(allocator, totalSize, UnsafeUtility.AlignOf<T>()); 54 UnsafeUtility.MemClear(m_Buffer, totalSize); 55 56 m_Length = length; 57 m_AllocatorLabel = allocator; 58 59#if ENABLE_UNITY_COLLECTIONS_CHECKS 60 m_MinIndex = 0; 61 m_MaxIndex = length - 1; 62 m_Safety = CollectionHelper.CreateSafetyHandle(allocator); 63 CollectionHelper.SetStaticSafetyId<NativeCustomArray<T>>(ref m_Safety, ref s_staticSafetyId.Data); 64#endif 65 } 66 67 public int Length { get { return m_Length; } } 68 69 public unsafe T this[int index] 70 { 71 get 72 { 73#if ENABLE_UNITY_COLLECTIONS_CHECKS 74 // If the container is currently not allowed to read from the buffer 75 // then this will throw an exception. 76 // This handles all cases, from already disposed containers 77 // to safe multithreaded access. 78 AtomicSafetyHandle.CheckReadAndThrow(m_Safety); 79 80 // Perform out of range checks based on 81 // the NativeContainerSupportsMinMaxWriteRestriction policy 82 if (index < m_MinIndex || index > m_MaxIndex) 83 FailOutOfRangeError(index); 84#endif 85 // Read the element from the allocated native memory 86 return UnsafeUtility.ReadArrayElement<T>(m_Buffer, index); 87 } 88 89 set 90 { 91#if ENABLE_UNITY_COLLECTIONS_CHECKS 92 // If the container is currently not allowed to write to the buffer 93 // then this will throw an exception. 94 // This handles all cases, from already disposed containers 95 // to safe multithreaded access. 96 AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); 97 98 // Perform out of range checks based on 99 // the NativeContainerSupportsMinMaxWriteRestriction policy 100 if (index < m_MinIndex || index > m_MaxIndex) 101 FailOutOfRangeError(index); 102#endif 103 // Writes value to the allocated native memory 104 UnsafeUtility.WriteArrayElement(m_Buffer, index, value); 105 } 106 } 107 108 public T[] ToArray() 109 { 110#if ENABLE_UNITY_COLLECTIONS_CHECKS 111 AtomicSafetyHandle.CheckReadAndThrow(m_Safety); 112#endif 113 114 var array = new T[Length]; 115 for (var i = 0; i < Length; i++) 116 array[i] = UnsafeUtility.ReadArrayElement<T>(m_Buffer, i); 117 return array; 118 } 119 120 public bool IsCreated 121 { 122 get { return m_Buffer != null; } 123 } 124 125 public void Dispose() 126 { 127#if ENABLE_UNITY_COLLECTIONS_CHECKS 128 CollectionHelper.DisposeSafetyHandle(ref m_Safety); 129#endif 130 131 AllocatorManager.Free(m_AllocatorLabel, m_Buffer); 132 m_Buffer = null; 133 m_Length = 0; 134 } 135 136#if ENABLE_UNITY_COLLECTIONS_CHECKS 137 private void FailOutOfRangeError(int index) 138 { 139 if (index < Length && (m_MinIndex != 0 || m_MaxIndex != Length - 1)) 140 throw new IndexOutOfRangeException(string.Format( 141 "Index {0} is out of restricted IJobParallelFor range [{1}...{2}] in ReadWriteBuffer.\n" + 142 "ReadWriteBuffers are restricted to only read & write the element at the job index. " + 143 "You can use double buffering strategies to avoid race conditions due to " + 144 "reading & writing in parallel to the same elements from a job.", 145 index, m_MinIndex, m_MaxIndex)); 146 147 throw new IndexOutOfRangeException(string.Format("Index {0} is out of range of '{1}' Length.", index, Length)); 148 } 149 150#endif 151} 152 153// Visualizes the custom array in the C# debugger 154internal sealed class NativeCustomArrayDebugView<T> where T : unmanaged 155{ 156 private NativeCustomArray<T> m_Array; 157 158 public NativeCustomArrayDebugView(NativeCustomArray<T> array) 159 { 160 m_Array = array; 161 } 162 163 public T[] Items 164 { 165 get { return m_Array.ToArray(); } 166 } 167}