123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- // Example code used in trunk, unity/Documentation/ApiDocs/Unity.Collections.LowLevel.Unsafe/NativeContainerAttribute.mem.xml
-
- using System.Diagnostics;
- using System;
- using Unity.Collections.LowLevel.Unsafe;
- using Unity.Collections;
- using Unity.Burst;
-
- // Marks our struct as a NativeContainer.
- // If ENABLE_UNITY_COLLECTIONS_CHECKS is enabled,
- // it is required that m_Safety with exactly this name.
- [NativeContainer]
- // The [NativeContainerSupportsMinMaxWriteRestriction] enables
- // a common jobification pattern where an IJobParallelFor is split into ranges
- // And the job is only allowed to access the index range being Executed by that worker thread.
- // Effectively limiting access of the array to the specific index passed into the Execute(int index) method
- // This attribute requires m_MinIndex & m_MaxIndex to exist.
- // and the container is expected to perform out of bounds checks against it.
- // m_MinIndex & m_MaxIndex will be set by the job scheduler before Execute is called on the worker thread.
- [NativeContainerSupportsMinMaxWriteRestriction]
- // It is recommended to always implement a Debugger proxy
- // to visualize the contents of the array in VisualStudio and other tools.
- [DebuggerDisplay("Length = {Length}")]
- [DebuggerTypeProxy(typeof(NativeCustomArrayDebugView<>))]
- internal unsafe struct NativeCustomArray<T> : IDisposable where T : unmanaged
- {
- internal void* m_Buffer;
- internal int m_Length;
-
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- internal int m_MinIndex;
- internal int m_MaxIndex;
- internal AtomicSafetyHandle m_Safety;
- internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<NativeCustomArray<T>>();
- #endif
-
- internal Allocator m_AllocatorLabel;
-
- public NativeCustomArray(int length, Allocator allocator)
- {
- int totalSize = UnsafeUtility.SizeOf<T>() * length;
-
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- // Native allocation is only valid for Temp, TempJob, Persistent or registered custom allocator
- if (allocator <= Allocator.None)
- throw new ArgumentException("Allocator must be Temp, TempJob, Persistent or registered custom allcoator", "allocator");
- if (length < 0)
- throw new ArgumentOutOfRangeException("length", "Length must be >= 0");
- if (!UnsafeUtility.IsBlittable<T>())
- throw new ArgumentException(string.Format("{0} used in NativeCustomArray<{0}> must be blittable", typeof(T)));
- #endif
-
- m_Buffer = AllocatorManager.Allocate(allocator, totalSize, UnsafeUtility.AlignOf<T>());
- UnsafeUtility.MemClear(m_Buffer, totalSize);
-
- m_Length = length;
- m_AllocatorLabel = allocator;
-
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- m_MinIndex = 0;
- m_MaxIndex = length - 1;
- m_Safety = CollectionHelper.CreateSafetyHandle(allocator);
- CollectionHelper.SetStaticSafetyId<NativeCustomArray<T>>(ref m_Safety, ref s_staticSafetyId.Data);
- #endif
- }
-
- public int Length { get { return m_Length; } }
-
- public unsafe T this[int index]
- {
- get
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- // If the container is currently not allowed to read from the buffer
- // then this will throw an exception.
- // This handles all cases, from already disposed containers
- // to safe multithreaded access.
- AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
-
- // Perform out of range checks based on
- // the NativeContainerSupportsMinMaxWriteRestriction policy
- if (index < m_MinIndex || index > m_MaxIndex)
- FailOutOfRangeError(index);
- #endif
- // Read the element from the allocated native memory
- return UnsafeUtility.ReadArrayElement<T>(m_Buffer, index);
- }
-
- set
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- // If the container is currently not allowed to write to the buffer
- // then this will throw an exception.
- // This handles all cases, from already disposed containers
- // to safe multithreaded access.
- AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
-
- // Perform out of range checks based on
- // the NativeContainerSupportsMinMaxWriteRestriction policy
- if (index < m_MinIndex || index > m_MaxIndex)
- FailOutOfRangeError(index);
- #endif
- // Writes value to the allocated native memory
- UnsafeUtility.WriteArrayElement(m_Buffer, index, value);
- }
- }
-
- public T[] ToArray()
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
- #endif
-
- var array = new T[Length];
- for (var i = 0; i < Length; i++)
- array[i] = UnsafeUtility.ReadArrayElement<T>(m_Buffer, i);
- return array;
- }
-
- public bool IsCreated
- {
- get { return m_Buffer != null; }
- }
-
- public void Dispose()
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- CollectionHelper.DisposeSafetyHandle(ref m_Safety);
- #endif
-
- AllocatorManager.Free(m_AllocatorLabel, m_Buffer);
- m_Buffer = null;
- m_Length = 0;
- }
-
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- private void FailOutOfRangeError(int index)
- {
- if (index < Length && (m_MinIndex != 0 || m_MaxIndex != Length - 1))
- throw new IndexOutOfRangeException(string.Format(
- "Index {0} is out of restricted IJobParallelFor range [{1}...{2}] in ReadWriteBuffer.\n" +
- "ReadWriteBuffers are restricted to only read & write the element at the job index. " +
- "You can use double buffering strategies to avoid race conditions due to " +
- "reading & writing in parallel to the same elements from a job.",
- index, m_MinIndex, m_MaxIndex));
-
- throw new IndexOutOfRangeException(string.Format("Index {0} is out of range of '{1}' Length.", index, Length));
- }
-
- #endif
- }
-
- // Visualizes the custom array in the C# debugger
- internal sealed class NativeCustomArrayDebugView<T> where T : unmanaged
- {
- private NativeCustomArray<T> m_Array;
-
- public NativeCustomArrayDebugView(NativeCustomArray<T> array)
- {
- m_Array = array;
- }
-
- public T[] Items
- {
- get { return m_Array.ToArray(); }
- }
- }
|