No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CustomContainerTests.cs 6.2KB

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