using System; using System.Diagnostics; using Unity.Collections.LowLevel.Unsafe; using Unity.Burst; using static Unity.Collections.AllocatorManager; namespace Unity.Collections { /// /// Extension methods for NativeArray. /// [BurstCompatible] public unsafe static class NativeArrayExtensions { public struct NativeArrayStaticId where T : struct { internal static readonly SharedStatic s_staticSafetyId = SharedStatic.GetOrCreate>(); } /// /// Returns true if a particular value is present in this array. /// /// The type of elements in this array. /// The value type. /// The array to search. /// The value to locate. /// True if the value is present in this array. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })] public static bool Contains(this NativeArray array, U value) where T : struct, IEquatable { return IndexOf(array.GetUnsafeReadOnlyPtr(), array.Length, value) != -1; } /// /// Finds the index of the first occurrence of a particular value in this array. /// /// The type of elements in this array. /// The value type. /// The array to search. /// The value to locate. /// The index of the first occurrence of the value in this array. Returns -1 if no occurrence is found. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })] public static int IndexOf(this NativeArray array, U value) where T : struct, IEquatable { return IndexOf(array.GetUnsafeReadOnlyPtr(), array.Length, value); } /// /// Returns true if a particular value is present in this array. /// /// The type of elements in this array. /// The value type. /// The array to search. /// The value to locate. /// True if the value is present in this array. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })] public static bool Contains(this NativeArray.ReadOnly array, U value) where T : struct, IEquatable { return IndexOf(array.m_Buffer, array.m_Length, value) != -1; } /// /// Finds the index of the first occurrence of a particular value in this array. /// /// The type of elements in this array. /// The type of value to locate. /// The array to search. /// The value to locate. /// The index of the first occurrence of the value in this array. Returns -1 if no occurrence is found. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })] public static int IndexOf(this NativeArray.ReadOnly array, U value) where T : struct, IEquatable { return IndexOf(array.m_Buffer, array.m_Length, value); } /// /// Returns true if a particular value is present in this list. /// /// The type of elements in this list. /// The value type. /// The list to search. /// The value to locate. /// True if the value is present in this list. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })] public static bool Contains(this NativeList list, U value) where T : unmanaged, IEquatable { return IndexOf(list.GetUnsafeReadOnlyPtr(), list.Length, value) != -1; } /// /// Finds the index of the first occurrence of a particular value in this list. /// /// The type of elements in the list. /// The value type. /// The list to search. /// The value to locate. /// The index of the first occurrence of the value in this list. Returns -1 if no occurrence is found. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })] public static int IndexOf(this NativeList list, U value) where T : unmanaged, IEquatable { return IndexOf(list.GetUnsafeReadOnlyPtr(), list.Length, value); } /// /// Returns true if a particular value is present in a buffer. /// /// The type of elements in the buffer. /// The value type. /// The buffer. /// Number of elements in the buffer. /// The value to locate. /// True if the value is present in the buffer. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })] public static bool Contains(void* ptr, int length, U value) where T : struct, IEquatable { return IndexOf(ptr, length, value) != -1; } /// /// Finds the index of the first occurrence of a particular value in a buffer. /// /// The type of elements in the buffer. /// The value type. /// A buffer. /// Number of elements in the buffer. /// The value to locate. /// The index of the first occurrence of the value in the buffer. Returns -1 if no occurrence is found. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })] public static int IndexOf(void* ptr, int length, U value) where T : struct, IEquatable { for (int i = 0; i != length; i++) { if (UnsafeUtility.ReadArrayElement(ptr, i).Equals(value)) return i; } return -1; } /// /// Returns the reinterpretation of this array into another kind of NativeArray. /// See [Array reinterpretation](https://docs.unity3d.com/Packages/com.unity.collections@latest?subfolder=/manual/allocation.html#array-reinterpretation). /// /// The array to reinterpret. /// Type of elements in the array. /// Type of elements in the reinterpreted array. /// The reinterpretation of this array into another kind of NativeArray. /// Thrown if this array's capacity cannot be evenly divided by `sizeof(U)`. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })] public static NativeArray Reinterpret(this NativeArray array) where U : struct where T : struct { var tSize = UnsafeUtility.SizeOf(); var uSize = UnsafeUtility.SizeOf(); var byteLen = ((long)array.Length) * tSize; var uLen = byteLen / uSize; CheckReinterpretSize(ref array); var ptr = NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(array); var result = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(ptr, (int)uLen, Allocator.None); #if ENABLE_UNITY_COLLECTIONS_CHECKS var handle = NativeArrayUnsafeUtility.GetAtomicSafetyHandle(array); NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref result, handle); #endif return result; } /// /// Returns true if this array and another have equal length and content. /// /// The type of the source array's elements. /// The array to compare for equality. /// The other array to compare for equality. /// True if the arrays have equal length and content. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })] public static bool ArraysEqual(this NativeArray array, NativeArray other) where T : struct, IEquatable { if (array.Length != other.Length) return false; for (int i = 0; i != array.Length; i++) { if (!array[i].Equals(other[i])) return false; } return true; } /// /// Returns true if this array and another have equal length and content. /// /// The type of the source array's elements. /// The array to compare for equality. /// The other array to compare for equality. /// True if the arrays have equal length and content. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })] public static bool ArraysEqual(this NativeList array, NativeArray other) where T : unmanaged, IEquatable { return ArraysEqual(array.AsArray(), other); } [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")] static void CheckReinterpretSize(ref NativeArray array) where U : struct where T : struct { var tSize = UnsafeUtility.SizeOf(); var uSize = UnsafeUtility.SizeOf(); var byteLen = ((long)array.Length) * tSize; var uLen = byteLen / uSize; if (uLen * uSize != byteLen) { throw new InvalidOperationException($"Types {typeof(T)} (array length {array.Length}) and {typeof(U)} cannot be aliased due to size constraints. The size of the types and lengths involved must line up."); } } [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })] internal static void Initialize(ref this NativeArray array, int length, AllocatorManager.AllocatorHandle allocator, NativeArrayOptions options = NativeArrayOptions.UninitializedMemory) where T : struct { AllocatorHandle handle = allocator; array.m_Buffer = handle.AllocateStruct(default(T), length); array.m_Length = length; array.m_AllocatorLabel = Allocator.None; if (options == NativeArrayOptions.ClearMemory) { UnsafeUtility.MemClear(array.m_Buffer, array.m_Length * UnsafeUtility.SizeOf()); } #if ENABLE_UNITY_COLLECTIONS_CHECKS array.m_MinIndex = 0; array.m_MaxIndex = length - 1; DisposeSentinel.Create(out array.m_Safety, out array.m_DisposeSentinel, 1, handle.ToAllocator); DisposeSentinel.Clear(ref array.m_DisposeSentinel); CollectionHelper.SetStaticSafetyId>(ref array.m_Safety, ref NativeArrayStaticId.s_staticSafetyId.Data); handle.AddSafetyHandle(array.m_Safety); #endif } [BurstCompatible(GenericTypeArguments = new[] { typeof(int), typeof(AllocatorManager.AllocatorHandle) })] internal static void Initialize(ref this NativeArray array, int length, ref U allocator, NativeArrayOptions options = NativeArrayOptions.ClearMemory) where T : struct where U : unmanaged, AllocatorManager.IAllocator { array.m_Buffer = allocator.AllocateStruct(default(T), length); array.m_Length = length; array.m_AllocatorLabel = Allocator.None; if (options == NativeArrayOptions.ClearMemory) { UnsafeUtility.MemClear(array.m_Buffer, array.m_Length * UnsafeUtility.SizeOf()); } #if ENABLE_UNITY_COLLECTIONS_CHECKS array.m_MinIndex = 0; array.m_MaxIndex = length - 1; DisposeSentinel.Create(out array.m_Safety, out array.m_DisposeSentinel, 1, allocator.ToAllocator); DisposeSentinel.Clear(ref array.m_DisposeSentinel); CollectionHelper.SetStaticSafetyId>(ref array.m_Safety, ref NativeArrayStaticId.s_staticSafetyId.Data); allocator.Handle.AddSafetyHandle(array.m_Safety); #endif } } }