Nav apraksta
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

NativeArrayExtensions.cs 15KB

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