ArraySlice.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. using System;
  2. using System.Diagnostics;
  3. using System.Runtime.InteropServices;
  4. using Unity.Collections;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. namespace UnityEngine.U2D
  7. {
  8. namespace UTess
  9. {
  10. [StructLayout(LayoutKind.Sequential)]
  11. [DebuggerDisplay("Length = {Length}")]
  12. internal unsafe struct ArraySlice<T> : System.IEquatable<ArraySlice<T>> where T : struct
  13. {
  14. [NativeDisableUnsafePtrRestriction] internal byte* m_Buffer;
  15. internal int m_Stride;
  16. internal int m_Length;
  17. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  18. internal int m_MinIndex;
  19. internal int m_MaxIndex;
  20. internal AtomicSafetyHandle m_Safety;
  21. #endif
  22. public ArraySlice(NativeArray<T> array, int start, int length)
  23. {
  24. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  25. if (start < 0)
  26. throw new ArgumentOutOfRangeException(nameof(start), $"Slice start {start} < 0.");
  27. if (length < 0)
  28. throw new ArgumentOutOfRangeException(nameof(length), $"Slice length {length} < 0.");
  29. if (start + length > array.Length)
  30. throw new ArgumentException(
  31. $"Slice start + length ({start + length}) range must be <= array.Length ({array.Length})");
  32. m_MinIndex = 0;
  33. m_MaxIndex = length - 1;
  34. m_Safety = Unity.Collections.LowLevel.Unsafe.NativeArrayUnsafeUtility.GetAtomicSafetyHandle(array);
  35. #endif
  36. m_Stride = UnsafeUtility.SizeOf<T>();
  37. var ptr = (byte*) array.GetUnsafePtr() + m_Stride * start;
  38. m_Buffer = ptr;
  39. m_Length = length;
  40. }
  41. public bool Equals(ArraySlice<T> other)
  42. {
  43. return m_Buffer == other.m_Buffer && m_Stride == other.m_Stride && m_Length == other.m_Length;
  44. }
  45. public override bool Equals(object obj)
  46. {
  47. if (ReferenceEquals(null, obj)) return false;
  48. return obj is ArraySlice<T> && Equals((ArraySlice<T>) obj);
  49. }
  50. public override int GetHashCode()
  51. {
  52. unchecked
  53. {
  54. var hashCode = (int) m_Buffer;
  55. hashCode = (hashCode * 397) ^ m_Stride;
  56. hashCode = (hashCode * 397) ^ m_Length;
  57. return hashCode;
  58. }
  59. }
  60. public static bool operator ==(ArraySlice<T> left, ArraySlice<T> right)
  61. {
  62. return left.Equals(right);
  63. }
  64. public static bool operator !=(ArraySlice<T> left, ArraySlice<T> right)
  65. {
  66. return !left.Equals(right);
  67. }
  68. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  69. // These are double-whammy excluded to we can elide bounds checks in the Burst disassembly view
  70. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  71. void CheckReadIndex(int index)
  72. {
  73. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  74. if (index < m_MinIndex || index > m_MaxIndex)
  75. FailOutOfRangeError(index);
  76. #endif
  77. }
  78. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  79. void CheckWriteIndex(int index)
  80. {
  81. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  82. if (index < m_MinIndex || index > m_MaxIndex)
  83. FailOutOfRangeError(index);
  84. #endif
  85. }
  86. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  87. private void FailOutOfRangeError(int index)
  88. {
  89. if (index < Length && (m_MinIndex != 0 || m_MaxIndex != Length - 1))
  90. throw new System.IndexOutOfRangeException(
  91. $"Index {index} is out of restricted IJobParallelFor range [{m_MinIndex}...{m_MaxIndex}] in ReadWriteBuffer.\n" +
  92. "ReadWriteBuffers are restricted to only read & write the element at the job index. " +
  93. "You can use double buffering strategies to avoid race conditions due to " +
  94. "reading & writing in parallel to the same elements from a job.");
  95. throw new System.IndexOutOfRangeException($"Index {index} is out of range of '{Length}' Length.");
  96. }
  97. #endif
  98. public static unsafe ArraySlice<T> ConvertExistingDataToArraySlice(void* dataPointer, int stride, int length)
  99. {
  100. if (length < 0)
  101. throw new System.ArgumentException($"Invalid length of '{length}'. It must be greater than 0.",
  102. nameof(length));
  103. if (stride < 0)
  104. throw new System.ArgumentException($"Invalid stride '{stride}'. It must be greater than 0.",
  105. nameof(stride));
  106. var newSlice = new ArraySlice<T>
  107. {
  108. m_Stride = stride,
  109. m_Buffer = (byte*) dataPointer,
  110. m_Length = length,
  111. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  112. m_MinIndex = 0,
  113. m_MaxIndex = length - 1,
  114. #endif
  115. };
  116. return newSlice;
  117. }
  118. public T this[int index]
  119. {
  120. get
  121. {
  122. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  123. CheckReadIndex(index);
  124. #endif
  125. return UnsafeUtility.ReadArrayElementWithStride<T>(m_Buffer, index, m_Stride);
  126. }
  127. [WriteAccessRequired]
  128. set
  129. {
  130. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  131. CheckWriteIndex(index);
  132. #endif
  133. UnsafeUtility.WriteArrayElementWithStride(m_Buffer, index, m_Stride, value);
  134. }
  135. }
  136. public int Stride => m_Stride;
  137. public int Length => m_Length;
  138. }
  139. }
  140. }