123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- using System;
- using Unity.Collections;
- using System.Diagnostics;
- using System.Runtime.InteropServices;
- using Unity.Collections.LowLevel.Unsafe;
-
- namespace UnityEngine.U2D.Common.UTess
- {
-
- [StructLayout(LayoutKind.Sequential)]
- [DebuggerDisplay("Length = {Length}")]
- [DebuggerTypeProxy(typeof(ArraySliceDebugView<>))]
- internal unsafe struct ArraySlice<T> : System.IEquatable<ArraySlice<T>> where T : struct
- {
- [NativeDisableUnsafePtrRestriction] internal byte* m_Buffer;
- internal int m_Stride;
- internal int m_Length;
-
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- internal int m_MinIndex;
- internal int m_MaxIndex;
- internal AtomicSafetyHandle m_Safety;
- #endif
-
- public ArraySlice(NativeArray<T> array, int start, int length)
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- if (start < 0)
- throw new ArgumentOutOfRangeException(nameof(start), $"Slice start {start} < 0.");
- if (length < 0)
- throw new ArgumentOutOfRangeException(nameof(length), $"Slice length {length} < 0.");
- if (start + length > array.Length)
- throw new ArgumentException(
- $"Slice start + length ({start + length}) range must be <= array.Length ({array.Length})");
- m_MinIndex = 0;
- m_MaxIndex = length - 1;
- m_Safety = Unity.Collections.LowLevel.Unsafe.NativeArrayUnsafeUtility.GetAtomicSafetyHandle(array);
- #endif
-
- m_Stride = UnsafeUtility.SizeOf<T>();
- var ptr = (byte*)array.GetUnsafePtr() + m_Stride * start;
- m_Buffer = ptr;
- m_Length = length;
- }
-
- public ArraySlice(Array<T> array, int start, int length)
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- if (start < 0)
- throw new ArgumentOutOfRangeException(nameof(start), $"Slice start {start} < 0.");
- if (length < 0)
- throw new ArgumentOutOfRangeException(nameof(length), $"Slice length {length} < 0.");
- if (start + length > array.Length)
- throw new ArgumentException(
- $"Slice start + length ({start + length}) range must be <= array.Length ({array.Length})");
- m_MinIndex = 0;
- m_MaxIndex = length - 1;
- m_Safety = Unity.Collections.LowLevel.Unsafe.NativeArrayUnsafeUtility.GetAtomicSafetyHandle(array.m_Array);
- #endif
-
- m_Stride = UnsafeUtility.SizeOf<T>();
- var ptr = (byte*)array.UnsafePtr + m_Stride * start;
- m_Buffer = ptr;
- m_Length = length;
- }
-
- public bool Equals(ArraySlice<T> other)
- {
- return m_Buffer == other.m_Buffer && m_Stride == other.m_Stride && m_Length == other.m_Length;
- }
-
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- return obj is ArraySlice<T> && Equals((ArraySlice<T>)obj);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- var hashCode = (int)m_Buffer;
- hashCode = (hashCode * 397) ^ m_Stride;
- hashCode = (hashCode * 397) ^ m_Length;
- return hashCode;
- }
- }
-
- public static bool operator ==(ArraySlice<T> left, ArraySlice<T> right)
- {
- return left.Equals(right);
- }
-
- public static bool operator !=(ArraySlice<T> left, ArraySlice<T> right)
- {
- return !left.Equals(right);
- }
-
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- // These are double-whammy excluded to we can elide bounds checks in the Burst disassembly view
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- void CheckReadIndex(int index)
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- if (index < m_MinIndex || index > m_MaxIndex)
- FailOutOfRangeError(index);
- #endif
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- void CheckWriteIndex(int index)
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- if (index < m_MinIndex || index > m_MaxIndex)
- FailOutOfRangeError(index);
- #endif
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- private void FailOutOfRangeError(int index)
- {
- if (index < Length && (m_MinIndex != 0 || m_MaxIndex != Length - 1))
- throw new System.IndexOutOfRangeException(
- $"Index {index} is out of restricted IJobParallelFor range [{m_MinIndex}...{m_MaxIndex}] 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.");
-
- throw new System.IndexOutOfRangeException($"Index {index} is out of range of '{Length}' Length.");
- }
-
- #endif
-
- public static unsafe ArraySlice<T> ConvertExistingDataToArraySlice(void* dataPointer, int stride, int length)
- {
- if (length < 0)
- throw new System.ArgumentException($"Invalid length of '{length}'. It must be greater than 0.",
- nameof(length));
- if (stride < 0)
- throw new System.ArgumentException($"Invalid stride '{stride}'. It must be greater than 0.",
- nameof(stride));
-
- var newSlice = new ArraySlice<T>
- {
- m_Stride = stride,
- m_Buffer = (byte*)dataPointer,
- m_Length = length,
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- m_MinIndex = 0,
- m_MaxIndex = length - 1,
- #endif
- };
-
- return newSlice;
- }
-
- public T this[int index]
- {
- get
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- CheckReadIndex(index);
- #endif
- return UnsafeUtility.ReadArrayElementWithStride<T>(m_Buffer, index, m_Stride);
- }
-
- [WriteAccessRequired]
- set
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- CheckWriteIndex(index);
- #endif
- UnsafeUtility.WriteArrayElementWithStride(m_Buffer, index, m_Stride, value);
- }
- }
-
- internal unsafe void* GetUnsafeReadOnlyPtr()
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
- #endif
- return m_Buffer;
- }
-
- internal void CopyTo(T[] array)
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- if (Length != array.Length)
- throw new ArgumentException($"array.Length ({array.Length}) does not match the Length of this instance ({Length}).", nameof(array));
- #endif
- unsafe
- {
- GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
- IntPtr addr = handle.AddrOfPinnedObject();
-
- var sizeOf = UnsafeUtility.SizeOf<T>();
- UnsafeUtility.MemCpyStride((byte*)addr, sizeOf, this.GetUnsafeReadOnlyPtr(), Stride, sizeOf, m_Length);
-
- handle.Free();
- }
- }
-
- internal T[] ToArray()
- {
- var array = new T[Length];
- CopyTo(array);
- return array;
- }
-
- public int Stride => m_Stride;
- public int Length => m_Length;
-
- }
-
- /// <summary>
- /// DebuggerTypeProxy for <see cref="ArraySlice{T}"/>
- /// </summary>
- internal sealed class ArraySliceDebugView<T> where T : struct
- {
- ArraySlice<T> m_Slice;
-
- public ArraySliceDebugView(ArraySlice<T> slice)
- {
- m_Slice = slice;
- }
-
- public T[] Items
- {
- get { return m_Slice.ToArray(); }
- }
- }
-
- }
|