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
}
}
}