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.

ArraySlice.cs 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. using System;
  2. using Unity.Collections;
  3. using System.Diagnostics;
  4. using System.Runtime.InteropServices;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. namespace UnityEngine.U2D.Common.UTess
  7. {
  8. [StructLayout(LayoutKind.Sequential)]
  9. [DebuggerDisplay("Length = {Length}")]
  10. [DebuggerTypeProxy(typeof(ArraySliceDebugView<>))]
  11. internal unsafe struct ArraySlice<T> : System.IEquatable<ArraySlice<T>> where T : struct
  12. {
  13. [NativeDisableUnsafePtrRestriction] internal byte* m_Buffer;
  14. internal int m_Stride;
  15. internal int m_Length;
  16. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  17. internal int m_MinIndex;
  18. internal int m_MaxIndex;
  19. internal AtomicSafetyHandle m_Safety;
  20. #endif
  21. public ArraySlice(NativeArray<T> array, int start, int length)
  22. {
  23. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  24. if (start < 0)
  25. throw new ArgumentOutOfRangeException(nameof(start), $"Slice start {start} < 0.");
  26. if (length < 0)
  27. throw new ArgumentOutOfRangeException(nameof(length), $"Slice length {length} < 0.");
  28. if (start + length > array.Length)
  29. throw new ArgumentException(
  30. $"Slice start + length ({start + length}) range must be <= array.Length ({array.Length})");
  31. m_MinIndex = 0;
  32. m_MaxIndex = length - 1;
  33. m_Safety = Unity.Collections.LowLevel.Unsafe.NativeArrayUnsafeUtility.GetAtomicSafetyHandle(array);
  34. #endif
  35. m_Stride = UnsafeUtility.SizeOf<T>();
  36. var ptr = (byte*)array.GetUnsafePtr() + m_Stride * start;
  37. m_Buffer = ptr;
  38. m_Length = length;
  39. }
  40. public ArraySlice(Array<T> array, int start, int length)
  41. {
  42. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  43. if (start < 0)
  44. throw new ArgumentOutOfRangeException(nameof(start), $"Slice start {start} < 0.");
  45. if (length < 0)
  46. throw new ArgumentOutOfRangeException(nameof(length), $"Slice length {length} < 0.");
  47. if (start + length > array.Length)
  48. throw new ArgumentException(
  49. $"Slice start + length ({start + length}) range must be <= array.Length ({array.Length})");
  50. m_MinIndex = 0;
  51. m_MaxIndex = length - 1;
  52. m_Safety = Unity.Collections.LowLevel.Unsafe.NativeArrayUnsafeUtility.GetAtomicSafetyHandle(array.m_Array);
  53. #endif
  54. m_Stride = UnsafeUtility.SizeOf<T>();
  55. var ptr = (byte*)array.UnsafePtr + m_Stride * start;
  56. m_Buffer = ptr;
  57. m_Length = length;
  58. }
  59. public bool Equals(ArraySlice<T> other)
  60. {
  61. return m_Buffer == other.m_Buffer && m_Stride == other.m_Stride && m_Length == other.m_Length;
  62. }
  63. public override bool Equals(object obj)
  64. {
  65. if (ReferenceEquals(null, obj)) return false;
  66. return obj is ArraySlice<T> && Equals((ArraySlice<T>)obj);
  67. }
  68. public override int GetHashCode()
  69. {
  70. unchecked
  71. {
  72. var hashCode = (int)m_Buffer;
  73. hashCode = (hashCode * 397) ^ m_Stride;
  74. hashCode = (hashCode * 397) ^ m_Length;
  75. return hashCode;
  76. }
  77. }
  78. public static bool operator ==(ArraySlice<T> left, ArraySlice<T> right)
  79. {
  80. return left.Equals(right);
  81. }
  82. public static bool operator !=(ArraySlice<T> left, ArraySlice<T> right)
  83. {
  84. return !left.Equals(right);
  85. }
  86. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  87. // These are double-whammy excluded to we can elide bounds checks in the Burst disassembly view
  88. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  89. void CheckReadIndex(int index)
  90. {
  91. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  92. if (index < m_MinIndex || index > m_MaxIndex)
  93. FailOutOfRangeError(index);
  94. #endif
  95. }
  96. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  97. void CheckWriteIndex(int index)
  98. {
  99. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  100. if (index < m_MinIndex || index > m_MaxIndex)
  101. FailOutOfRangeError(index);
  102. #endif
  103. }
  104. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  105. private void FailOutOfRangeError(int index)
  106. {
  107. if (index < Length && (m_MinIndex != 0 || m_MaxIndex != Length - 1))
  108. throw new System.IndexOutOfRangeException(
  109. $"Index {index} is out of restricted IJobParallelFor range [{m_MinIndex}...{m_MaxIndex}] in ReadWriteBuffer.\n" +
  110. "ReadWriteBuffers are restricted to only read & write the element at the job index. " +
  111. "You can use double buffering strategies to avoid race conditions due to " +
  112. "reading & writing in parallel to the same elements from a job.");
  113. throw new System.IndexOutOfRangeException($"Index {index} is out of range of '{Length}' Length.");
  114. }
  115. #endif
  116. public static unsafe ArraySlice<T> ConvertExistingDataToArraySlice(void* dataPointer, int stride, int length)
  117. {
  118. if (length < 0)
  119. throw new System.ArgumentException($"Invalid length of '{length}'. It must be greater than 0.",
  120. nameof(length));
  121. if (stride < 0)
  122. throw new System.ArgumentException($"Invalid stride '{stride}'. It must be greater than 0.",
  123. nameof(stride));
  124. var newSlice = new ArraySlice<T>
  125. {
  126. m_Stride = stride,
  127. m_Buffer = (byte*)dataPointer,
  128. m_Length = length,
  129. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  130. m_MinIndex = 0,
  131. m_MaxIndex = length - 1,
  132. #endif
  133. };
  134. return newSlice;
  135. }
  136. public T this[int index]
  137. {
  138. get
  139. {
  140. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  141. CheckReadIndex(index);
  142. #endif
  143. return UnsafeUtility.ReadArrayElementWithStride<T>(m_Buffer, index, m_Stride);
  144. }
  145. [WriteAccessRequired]
  146. set
  147. {
  148. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  149. CheckWriteIndex(index);
  150. #endif
  151. UnsafeUtility.WriteArrayElementWithStride(m_Buffer, index, m_Stride, value);
  152. }
  153. }
  154. internal unsafe void* GetUnsafeReadOnlyPtr()
  155. {
  156. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  157. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  158. #endif
  159. return m_Buffer;
  160. }
  161. internal void CopyTo(T[] array)
  162. {
  163. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  164. if (Length != array.Length)
  165. throw new ArgumentException($"array.Length ({array.Length}) does not match the Length of this instance ({Length}).", nameof(array));
  166. #endif
  167. unsafe
  168. {
  169. GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
  170. IntPtr addr = handle.AddrOfPinnedObject();
  171. var sizeOf = UnsafeUtility.SizeOf<T>();
  172. UnsafeUtility.MemCpyStride((byte*)addr, sizeOf, this.GetUnsafeReadOnlyPtr(), Stride, sizeOf, m_Length);
  173. handle.Free();
  174. }
  175. }
  176. internal T[] ToArray()
  177. {
  178. var array = new T[Length];
  179. CopyTo(array);
  180. return array;
  181. }
  182. public int Stride => m_Stride;
  183. public int Length => m_Length;
  184. }
  185. /// <summary>
  186. /// DebuggerTypeProxy for <see cref="ArraySlice{T}"/>
  187. /// </summary>
  188. internal sealed class ArraySliceDebugView<T> where T : struct
  189. {
  190. ArraySlice<T> m_Slice;
  191. public ArraySliceDebugView(ArraySlice<T> slice)
  192. {
  193. m_Slice = slice;
  194. }
  195. public T[] Items
  196. {
  197. get { return m_Slice.ToArray(); }
  198. }
  199. }
  200. }