暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

NativeArrayExtensions.cs 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. using System;
  2. using System.Diagnostics;
  3. using Unity.Collections.LowLevel.Unsafe;
  4. using Unity.Burst;
  5. using static Unity.Collections.AllocatorManager;
  6. namespace Unity.Collections
  7. {
  8. /// <summary>
  9. /// Extension methods for NativeArray.
  10. /// </summary>
  11. [BurstCompatible]
  12. public unsafe static class NativeArrayExtensions
  13. {
  14. public struct NativeArrayStaticId<T>
  15. where T : struct
  16. {
  17. internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<NativeArray<T>>();
  18. }
  19. /// <summary>
  20. /// Returns true if a particular value is present in this array.
  21. /// </summary>
  22. /// <typeparam name="T">The type of elements in this array.</typeparam>
  23. /// <typeparam name="U">The value type.</typeparam>
  24. /// <param name="array">The array to search.</param>
  25. /// <param name="value">The value to locate.</param>
  26. /// <returns>True if the value is present in this array.</returns>
  27. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  28. public static bool Contains<T, U>(this NativeArray<T> array, U value) where T : struct, IEquatable<U>
  29. {
  30. return IndexOf<T, U>(array.GetUnsafeReadOnlyPtr(), array.Length, value) != -1;
  31. }
  32. /// <summary>
  33. /// Finds the index of the first occurrence of a particular value in this array.
  34. /// </summary>
  35. /// <typeparam name="T">The type of elements in this array.</typeparam>
  36. /// <typeparam name="U">The value type.</typeparam>
  37. /// <param name="array">The array to search.</param>
  38. /// <param name="value">The value to locate.</param>
  39. /// <returns>The index of the first occurrence of the value in this array. Returns -1 if no occurrence is found.</returns>
  40. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  41. public static int IndexOf<T, U>(this NativeArray<T> array, U value) where T : struct, IEquatable<U>
  42. {
  43. return IndexOf<T, U>(array.GetUnsafeReadOnlyPtr(), array.Length, value);
  44. }
  45. /// <summary>
  46. /// Returns true if a particular value is present in this array.
  47. /// </summary>
  48. /// <typeparam name="T">The type of elements in this array.</typeparam>
  49. /// <typeparam name="U">The value type.</typeparam>
  50. /// <param name="array">The array to search.</param>
  51. /// <param name="value">The value to locate.</param>
  52. /// <returns>True if the value is present in this array.</returns>
  53. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  54. public static bool Contains<T, U>(this NativeArray<T>.ReadOnly array, U value) where T : struct, IEquatable<U>
  55. {
  56. return IndexOf<T, U>(array.m_Buffer, array.m_Length, value) != -1;
  57. }
  58. /// <summary>
  59. /// Finds the index of the first occurrence of a particular value in this array.
  60. /// </summary>
  61. /// <typeparam name="T">The type of elements in this array.</typeparam>
  62. /// <typeparam name="U">The type of value to locate.</typeparam>
  63. /// <param name="array">The array to search.</param>
  64. /// <param name="value">The value to locate.</param>
  65. /// <returns>The index of the first occurrence of the value in this array. Returns -1 if no occurrence is found.</returns>
  66. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  67. public static int IndexOf<T, U>(this NativeArray<T>.ReadOnly array, U value) where T : struct, IEquatable<U>
  68. {
  69. return IndexOf<T, U>(array.m_Buffer, array.m_Length, value);
  70. }
  71. /// <summary>
  72. /// Returns true if a particular value is present in this list.
  73. /// </summary>
  74. /// <typeparam name="T">The type of elements in this list.</typeparam>
  75. /// <typeparam name="U">The value type.</typeparam>
  76. /// <param name="list">The list to search.</param>
  77. /// <param name="value">The value to locate.</param>
  78. /// <returns>True if the value is present in this list.</returns>
  79. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  80. public static bool Contains<T, U>(this NativeList<T> list, U value) where T : unmanaged, IEquatable<U>
  81. {
  82. return IndexOf<T, U>(list.GetUnsafeReadOnlyPtr(), list.Length, value) != -1;
  83. }
  84. /// <summary>
  85. /// Finds the index of the first occurrence of a particular value in this list.
  86. /// </summary>
  87. /// <typeparam name="T">The type of elements in the list.</typeparam>
  88. /// <typeparam name="U">The value type.</typeparam>
  89. /// <param name="list">The list to search.</param>
  90. /// <param name="value">The value to locate.</param>
  91. /// <returns>The index of the first occurrence of the value in this list. Returns -1 if no occurrence is found.</returns>
  92. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  93. public static int IndexOf<T, U>(this NativeList<T> list, U value) where T : unmanaged, IEquatable<U>
  94. {
  95. return IndexOf<T, U>(list.GetUnsafeReadOnlyPtr(), list.Length, value);
  96. }
  97. /// <summary>
  98. /// Returns true if a particular value is present in a buffer.
  99. /// </summary>
  100. /// <typeparam name="T">The type of elements in the buffer.</typeparam>
  101. /// <typeparam name="U">The value type.</typeparam>
  102. /// <param name="ptr">The buffer.</param>
  103. /// <param name="length">Number of elements in the buffer.</param>
  104. /// <param name="value">The value to locate.</param>
  105. /// <returns>True if the value is present in the buffer.</returns>
  106. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  107. public static bool Contains<T, U>(void* ptr, int length, U value) where T : struct, IEquatable<U>
  108. {
  109. return IndexOf<T, U>(ptr, length, value) != -1;
  110. }
  111. /// <summary>
  112. /// Finds the index of the first occurrence of a particular value in a buffer.
  113. /// </summary>
  114. /// <typeparam name="T">The type of elements in the buffer.</typeparam>
  115. /// <typeparam name="U">The value type.</typeparam>
  116. /// <param name="ptr">A buffer.</param>
  117. /// <param name="length">Number of elements in the buffer.</param>
  118. /// <param name="value">The value to locate.</param>
  119. /// <returns>The index of the first occurrence of the value in the buffer. Returns -1 if no occurrence is found.</returns>
  120. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  121. public static int IndexOf<T, U>(void* ptr, int length, U value) where T : struct, IEquatable<U>
  122. {
  123. for (int i = 0; i != length; i++)
  124. {
  125. if (UnsafeUtility.ReadArrayElement<T>(ptr, i).Equals(value))
  126. return i;
  127. }
  128. return -1;
  129. }
  130. /// <summary>
  131. /// Returns the reinterpretation of this array into another kind of NativeArray.
  132. /// See [Array reinterpretation](https://docs.unity3d.com/Packages/com.unity.collections@latest?subfolder=/manual/allocation.html#array-reinterpretation).
  133. /// </summary>
  134. /// <param name="array">The array to reinterpret.</param>
  135. /// <typeparam name="T">Type of elements in the array.</typeparam>
  136. /// <typeparam name="U">Type of elements in the reinterpreted array.</typeparam>
  137. /// <returns>The reinterpretation of this array into another kind of NativeArray.</returns>
  138. /// <exception cref="InvalidOperationException">Thrown if this array's capacity cannot be evenly divided by `sizeof(U)`.</exception>
  139. [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  140. public static NativeArray<U> Reinterpret<T, U>(this NativeArray<T> array) where U : struct where T : struct
  141. {
  142. var tSize = UnsafeUtility.SizeOf<T>();
  143. var uSize = UnsafeUtility.SizeOf<U>();
  144. var byteLen = ((long)array.Length) * tSize;
  145. var uLen = byteLen / uSize;
  146. CheckReinterpretSize<T, U>(ref array);
  147. var ptr = NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(array);
  148. var result = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<U>(ptr, (int)uLen, Allocator.None);
  149. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  150. var handle = NativeArrayUnsafeUtility.GetAtomicSafetyHandle(array);
  151. NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref result, handle);
  152. #endif
  153. return result;
  154. }
  155. /// <summary>
  156. /// Returns true if this array and another have equal length and content.
  157. /// </summary>
  158. /// <typeparam name="T">The type of the source array's elements.</typeparam>
  159. /// <param name="array">The array to compare for equality.</param>
  160. /// <param name="other">The other array to compare for equality.</param>
  161. /// <returns>True if the arrays have equal length and content.</returns>
  162. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  163. public static bool ArraysEqual<T>(this NativeArray<T> array, NativeArray<T> other) where T : struct, IEquatable<T>
  164. {
  165. if (array.Length != other.Length)
  166. return false;
  167. for (int i = 0; i != array.Length; i++)
  168. {
  169. if (!array[i].Equals(other[i]))
  170. return false;
  171. }
  172. return true;
  173. }
  174. /// <summary>
  175. /// Returns true if this array and another have equal length and content.
  176. /// </summary>
  177. /// <typeparam name="T">The type of the source array's elements.</typeparam>
  178. /// <param name="array">The array to compare for equality.</param>
  179. /// <param name="other">The other array to compare for equality.</param>
  180. /// <returns>True if the arrays have equal length and content.</returns>
  181. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  182. public static bool ArraysEqual<T>(this NativeList<T> array, NativeArray<T> other) where T : unmanaged, IEquatable<T>
  183. {
  184. return ArraysEqual(array.AsArray(), other);
  185. }
  186. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  187. static void CheckReinterpretSize<T, U>(ref NativeArray<T> array) where U : struct where T : struct
  188. {
  189. var tSize = UnsafeUtility.SizeOf<T>();
  190. var uSize = UnsafeUtility.SizeOf<U>();
  191. var byteLen = ((long)array.Length) * tSize;
  192. var uLen = byteLen / uSize;
  193. if (uLen * uSize != byteLen)
  194. {
  195. 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.");
  196. }
  197. }
  198. [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
  199. internal static void Initialize<T>(ref this NativeArray<T> array,
  200. int length,
  201. AllocatorManager.AllocatorHandle allocator,
  202. NativeArrayOptions options = NativeArrayOptions.UninitializedMemory)
  203. where T : struct
  204. {
  205. AllocatorHandle handle = allocator;
  206. array.m_Buffer = handle.AllocateStruct(default(T), length);
  207. array.m_Length = length;
  208. array.m_AllocatorLabel = Allocator.None;
  209. if (options == NativeArrayOptions.ClearMemory)
  210. {
  211. UnsafeUtility.MemClear(array.m_Buffer, array.m_Length * UnsafeUtility.SizeOf<T>());
  212. }
  213. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  214. array.m_MinIndex = 0;
  215. array.m_MaxIndex = length - 1;
  216. DisposeSentinel.Create(out array.m_Safety, out array.m_DisposeSentinel, 1, handle.ToAllocator);
  217. DisposeSentinel.Clear(ref array.m_DisposeSentinel);
  218. CollectionHelper.SetStaticSafetyId<NativeArray<T>>(ref array.m_Safety, ref NativeArrayStaticId<T>.s_staticSafetyId.Data);
  219. handle.AddSafetyHandle(array.m_Safety);
  220. #endif
  221. }
  222. [BurstCompatible(GenericTypeArguments = new[] { typeof(int), typeof(AllocatorManager.AllocatorHandle) })]
  223. internal static void Initialize<T, U>(ref this NativeArray<T> array,
  224. int length,
  225. ref U allocator,
  226. NativeArrayOptions options = NativeArrayOptions.ClearMemory)
  227. where T : struct
  228. where U : unmanaged, AllocatorManager.IAllocator
  229. {
  230. array.m_Buffer = allocator.AllocateStruct(default(T), length);
  231. array.m_Length = length;
  232. array.m_AllocatorLabel = Allocator.None;
  233. if (options == NativeArrayOptions.ClearMemory)
  234. {
  235. UnsafeUtility.MemClear(array.m_Buffer, array.m_Length * UnsafeUtility.SizeOf<T>());
  236. }
  237. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  238. array.m_MinIndex = 0;
  239. array.m_MaxIndex = length - 1;
  240. DisposeSentinel.Create(out array.m_Safety, out array.m_DisposeSentinel, 1, allocator.ToAllocator);
  241. DisposeSentinel.Clear(ref array.m_DisposeSentinel);
  242. CollectionHelper.SetStaticSafetyId<NativeArray<T>>(ref array.m_Safety, ref NativeArrayStaticId<T>.s_staticSafetyId.Data);
  243. allocator.Handle.AddSafetyHandle(array.m_Safety);
  244. #endif
  245. }
  246. }
  247. }