暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

NativeList.cs 47KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Runtime.InteropServices;
  6. using System.Threading;
  7. using Unity.Burst;
  8. using Unity.Collections.LowLevel.Unsafe;
  9. using Unity.Jobs;
  10. namespace Unity.Collections
  11. {
  12. /// <summary>
  13. /// An indexable collection.
  14. /// </summary>
  15. /// <typeparam name="T">The type of the elements in the collection.</typeparam>
  16. public interface IIndexable<T> where T : struct
  17. {
  18. /// <summary>
  19. /// The current number of elements in the collection.
  20. /// </summary>
  21. /// <value>The current number of elements in the collection.</value>
  22. int Length { get; set; }
  23. /// <summary>
  24. /// Returns a reference to the element at a given index.
  25. /// </summary>
  26. /// <param name="index">The index to access. Must be in the range of [0..Length).</param>
  27. /// <returns>A reference to the element at the index.</returns>
  28. ref T ElementAt(int index);
  29. }
  30. /// <summary>
  31. /// A resizable list.
  32. /// </summary>
  33. /// <typeparam name="T">The type of the elements.</typeparam>
  34. public interface INativeList<T> : IIndexable<T> where T : struct
  35. {
  36. /// <summary>
  37. /// The number of elements that fit in the current allocation.
  38. /// </summary>
  39. /// <value>The number of elements that fit in the current allocation.</value>
  40. /// <param name="value">A new capacity.</param>
  41. int Capacity { get; set; }
  42. /// <summary>
  43. /// Whether this list is empty.
  44. /// </summary>
  45. /// <value>True if this list is empty.</value>
  46. bool IsEmpty { get; }
  47. /// <summary>
  48. /// The element at an index.
  49. /// </summary>
  50. /// <param name="index">An index.</param>
  51. /// <value>The element at the index.</value>
  52. /// <exception cref="IndexOutOfRangeException">Thrown if index is out of bounds.</exception>
  53. T this[int index] { get; set; }
  54. /// <summary>
  55. /// Sets the length to 0.
  56. /// </summary>
  57. /// <remarks>Does not change the capacity.</remarks>
  58. void Clear();
  59. }
  60. /// <summary>
  61. /// An unmanaged, resizable list.
  62. /// </summary>
  63. /// <remarks>The elements are stored contiguously in a buffer rather than as linked nodes.</remarks>
  64. /// <typeparam name="T">The type of the elements.</typeparam>
  65. [StructLayout(LayoutKind.Sequential)]
  66. [NativeContainer]
  67. [DebuggerDisplay("Length = {Length}")]
  68. [DebuggerTypeProxy(typeof(NativeListDebugView<>))]
  69. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  70. public unsafe struct NativeList<T>
  71. : INativeDisposable
  72. , INativeList<T>
  73. , IEnumerable<T> // Used by collection initializers.
  74. where T : unmanaged
  75. {
  76. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  77. internal AtomicSafetyHandle m_Safety;
  78. internal int m_SafetyIndexHint;
  79. internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<NativeList<T>>();
  80. #if REMOVE_DISPOSE_SENTINEL
  81. #else
  82. [NativeSetClassTypeToNullOnSchedule]
  83. internal DisposeSentinel m_DisposeSentinel;
  84. #endif
  85. #endif
  86. [NativeDisableUnsafePtrRestriction]
  87. internal UnsafeList<T>* m_ListData;
  88. //@TODO: Unity.Physics currently relies on the specific layout of NativeList in order to
  89. // workaround a bug in 19.1 & 19.2 with atomic safety handle in jobified Dispose.
  90. internal AllocatorManager.AllocatorHandle m_DeprecatedAllocator;
  91. /// <summary>
  92. /// Initializes and returns a NativeList with a capacity of one.
  93. /// </summary>
  94. /// <param name="allocator">The allocator to use.</param>
  95. public NativeList(AllocatorManager.AllocatorHandle allocator)
  96. : this(1, allocator, 2)
  97. {
  98. }
  99. /// <summary>
  100. /// Initializes and returns a NativeList.
  101. /// </summary>
  102. /// <param name="initialCapacity">The initial capacity of the list.</param>
  103. /// <param name="allocator">The allocator to use.</param>
  104. public NativeList(int initialCapacity, AllocatorManager.AllocatorHandle allocator)
  105. : this(initialCapacity, allocator, 2)
  106. {
  107. }
  108. [BurstCompatible(GenericTypeArguments = new [] { typeof(AllocatorManager.AllocatorHandle) })]
  109. internal void Initialize<U>(int initialCapacity, ref U allocator, int disposeSentinelStackDepth) where U : unmanaged, AllocatorManager.IAllocator
  110. {
  111. var totalSize = sizeof(T) * (long)initialCapacity;
  112. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  113. CollectionHelper.CheckAllocator(allocator.Handle);
  114. CheckInitialCapacity(initialCapacity);
  115. CollectionHelper.CheckIsUnmanaged<T>();
  116. CheckTotalSize(initialCapacity, totalSize);
  117. #if REMOVE_DISPOSE_SENTINEL
  118. m_Safety = CollectionHelper.CreateSafetyHandle(allocator.Handle);
  119. #else
  120. if (allocator.IsCustomAllocator)
  121. {
  122. m_Safety = AtomicSafetyHandle.Create();
  123. m_DisposeSentinel = null;
  124. }
  125. else
  126. {
  127. DisposeSentinel.Create(out m_Safety, out m_DisposeSentinel, disposeSentinelStackDepth, allocator.ToAllocator);
  128. }
  129. #endif
  130. CollectionHelper.SetStaticSafetyId<NativeList<T>>(ref m_Safety, ref s_staticSafetyId.Data);
  131. m_SafetyIndexHint = (allocator.Handle).AddSafetyHandle(m_Safety);
  132. #endif
  133. m_ListData = UnsafeList<T>.Create(initialCapacity, ref allocator);
  134. m_DeprecatedAllocator = allocator.Handle;
  135. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  136. AtomicSafetyHandle.SetBumpSecondaryVersionOnScheduleWrite(m_Safety, true);
  137. #endif
  138. }
  139. [BurstCompatible(GenericTypeArguments = new [] { typeof(AllocatorManager.AllocatorHandle) })]
  140. internal static NativeList<T> New<U>(int initialCapacity, ref U allocator, int disposeSentinelStackDepth) where U : unmanaged, AllocatorManager.IAllocator
  141. {
  142. var nativelist = new NativeList<T>();
  143. nativelist.Initialize(initialCapacity, ref allocator, disposeSentinelStackDepth);
  144. return nativelist;
  145. }
  146. [BurstCompatible(GenericTypeArguments = new [] { typeof(AllocatorManager.AllocatorHandle) })]
  147. internal static NativeList<T> New<U>(int initialCapacity, ref U allocator) where U : unmanaged, AllocatorManager.IAllocator
  148. {
  149. return New(initialCapacity, ref allocator, 2);
  150. }
  151. NativeList(int initialCapacity, AllocatorManager.AllocatorHandle allocator, int disposeSentinelStackDepth)
  152. {
  153. this = default;
  154. AllocatorManager.AllocatorHandle temp = allocator;
  155. Initialize(initialCapacity, ref temp, disposeSentinelStackDepth);
  156. }
  157. /// <summary>
  158. /// The element at a given index.
  159. /// </summary>
  160. /// <param name="index">An index into this list.</param>
  161. /// <value>The value to store at the `index`.</value>
  162. /// <exception cref="IndexOutOfRangeException">Thrown if `index` is out of bounds.</exception>
  163. public T this[int index]
  164. {
  165. get
  166. {
  167. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  168. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  169. #endif
  170. return (*m_ListData)[index];
  171. }
  172. set
  173. {
  174. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  175. AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
  176. #endif
  177. (*m_ListData)[index] = value;
  178. }
  179. }
  180. /// <summary>
  181. /// Returns a reference to the element at an index.
  182. /// </summary>
  183. /// <param name="index">An index.</param>
  184. /// <returns>A reference to the element at the index.</returns>
  185. /// <exception cref="IndexOutOfRangeException">Thrown if index is out of bounds.</exception>
  186. public ref T ElementAt(int index)
  187. {
  188. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  189. AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
  190. #endif
  191. return ref m_ListData->ElementAt(index);
  192. }
  193. /// <summary>
  194. /// The count of elements.
  195. /// </summary>
  196. /// <value>The current count of elements. Always less than or equal to the capacity.</value>
  197. /// <remarks>To decrease the memory used by a list, set <see cref="Capacity"/> after reducing the length of the list.</remarks>
  198. /// <param name="value>">The new length. If the new length is greater than the current capacity, the capacity is increased.
  199. /// Newly allocated memory is cleared.</param>
  200. public int Length
  201. {
  202. get
  203. {
  204. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  205. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  206. #endif
  207. return CollectionHelper.AssumePositive(m_ListData->Length);
  208. }
  209. set
  210. {
  211. m_ListData->Resize(value, NativeArrayOptions.ClearMemory);
  212. }
  213. }
  214. /// <summary>
  215. /// The number of elements that fit in the current allocation.
  216. /// </summary>
  217. /// <value>The number of elements that fit in the current allocation.</value>
  218. /// <param name="value">The new capacity. Must be greater or equal to the length.</param>
  219. /// <exception cref="ArgumentOutOfRangeException">Thrown if the new capacity is smaller than the length.</exception>
  220. public int Capacity
  221. {
  222. get
  223. {
  224. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  225. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  226. #endif
  227. return m_ListData->Capacity;
  228. }
  229. set
  230. {
  231. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  232. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  233. #endif
  234. m_ListData->Capacity = value;
  235. }
  236. }
  237. /// <summary>
  238. /// Returns the internal unsafe list.
  239. /// </summary>
  240. /// <remarks>Internally, the elements of a NativeList are stored in an UnsafeList.</remarks>
  241. /// <returns>The internal unsafe list.</returns>
  242. public UnsafeList<T>* GetUnsafeList() => m_ListData;
  243. /// <summary>
  244. /// Appends an element to the end of this list.
  245. /// </summary>
  246. /// <param name="value">The value to add to the end of this list.</param>
  247. /// <remarks>
  248. /// Length is incremented by 1. Will not increase the capacity.
  249. /// </remarks>
  250. /// <exception cref="Exception">Thrown if incrementing the length would exceed the capacity.</exception>
  251. public void AddNoResize(T value)
  252. {
  253. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  254. AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
  255. #endif
  256. m_ListData->AddNoResize(value);
  257. }
  258. /// <summary>
  259. /// Appends elements from a buffer to the end of this list.
  260. /// </summary>
  261. /// <param name="ptr">The buffer to copy from.</param>
  262. /// <param name="count">The number of elements to copy from the buffer.</param>
  263. /// <remarks>
  264. /// Length is increased by the count. Will not increase the capacity.
  265. /// </remarks>
  266. /// <exception cref="Exception">Thrown if the increased length would exceed the capacity.</exception>
  267. public void AddRangeNoResize(void* ptr, int count)
  268. {
  269. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  270. AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
  271. #endif
  272. CheckArgPositive(count);
  273. m_ListData->AddRangeNoResize(ptr, count);
  274. }
  275. /// <summary>
  276. /// Appends the elements of another list to the end of this list.
  277. /// </summary>
  278. /// <param name="list">The other list to copy from.</param>
  279. /// <remarks>
  280. /// Length is increased by the length of the other list. Will not increase the capacity.
  281. /// </remarks>
  282. /// <exception cref="Exception">Thrown if the increased length would exceed the capacity.</exception>
  283. public void AddRangeNoResize(NativeList<T> list)
  284. {
  285. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  286. AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
  287. #endif
  288. m_ListData->AddRangeNoResize(*list.m_ListData);
  289. }
  290. /// <summary>
  291. /// Appends an element to the end of this list.
  292. /// </summary>
  293. /// <param name="value">The value to add to the end of this list.</param>
  294. /// <remarks>
  295. /// Length is incremented by 1. If necessary, the capacity is increased.
  296. /// </remarks>
  297. public void Add(in T value)
  298. {
  299. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  300. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  301. #endif
  302. m_ListData->Add(value);
  303. }
  304. /// <summary>
  305. /// Appends the elements of an array to the end of this list.
  306. /// </summary>
  307. /// <param name="array">The array to copy from.</param>
  308. /// <remarks>
  309. /// Length is increased by the number of new elements. Does not increase the capacity.
  310. /// </remarks>
  311. /// <exception cref="Exception">Thrown if the increased length would exceed the capacity.</exception>
  312. public void AddRange(NativeArray<T> array)
  313. {
  314. AddRange(array.GetUnsafeReadOnlyPtr(), array.Length);
  315. }
  316. /// <summary>
  317. /// Appends the elements of a buffer to the end of this list.
  318. /// </summary>
  319. /// <param name="ptr">The buffer to copy from.</param>
  320. /// <param name="count">The number of elements to copy from the buffer.</param>
  321. /// <exception cref="ArgumentOutOfRangeException">Thrown if count is negative.</exception>
  322. public void AddRange(void* ptr, int count)
  323. {
  324. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  325. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  326. #endif
  327. CheckArgPositive(count);
  328. m_ListData->AddRange(ptr, CollectionHelper.AssumePositive(count));
  329. }
  330. /// <summary>
  331. /// Shifts elements toward the end of this list, increasing its length.
  332. /// </summary>
  333. /// <remarks>
  334. /// Right-shifts elements in the list so as to create 'free' slots at the beginning or in the middle.
  335. ///
  336. /// The length is increased by `end - begin`. If necessary, the capacity will be increased accordingly.
  337. ///
  338. /// If `end` equals `begin`, the method does nothing.
  339. ///
  340. /// The element at index `begin` will be copied to index `end`, the element at index `begin + 1` will be copied to `end + 1`, and so forth.
  341. ///
  342. /// The indexes `begin` up to `end` are not cleared: they will contain whatever values they held prior.
  343. /// </remarks>
  344. /// <param name="begin">The index of the first element that will be shifted up.</param>
  345. /// <param name="end">The index where the first shifted element will end up.</param>
  346. /// <exception cref="ArgumentException">Thrown if `end &lt; begin`.</exception>
  347. /// <exception cref="ArgumentOutOfRangeException">Thrown if `begin` or `end` are out of bounds.</exception>
  348. public void InsertRangeWithBeginEnd(int begin, int end)
  349. {
  350. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  351. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  352. #endif
  353. m_ListData->InsertRangeWithBeginEnd(CollectionHelper.AssumePositive(begin), CollectionHelper.AssumePositive(end));
  354. }
  355. /// <summary>
  356. /// Copies the last element of this list to the specified index. Decrements the length by 1.
  357. /// </summary>
  358. /// <remarks>Useful as a cheap way to remove an element from this list when you don't care about preserving order.</remarks>
  359. /// <param name="index">The index to overwrite with the last element.</param>
  360. /// <exception cref="IndexOutOfRangeException">Thrown if `index` is out of bounds.</exception>
  361. public void RemoveAtSwapBack(int index)
  362. {
  363. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  364. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  365. #endif
  366. m_ListData->RemoveAtSwapBack(CollectionHelper.AssumePositive(index));
  367. }
  368. /// <summary>
  369. /// Copies the last *N* elements of this list to a range in this list. Decrements the length by *N*.
  370. /// </summary>
  371. /// <remarks>
  372. /// Copies the last `count` elements to the indexes `index` up to `index + count`.
  373. ///
  374. /// Useful as a cheap way to remove elements from a list when you don't care about preserving order.
  375. /// </remarks>
  376. /// <param name="index">The index of the first element to overwrite.</param>
  377. /// <param name="count">The number of elements to copy and remove.</param>
  378. /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds, `count` is negative,
  379. /// or `index + count` exceeds the length.</exception>
  380. public void RemoveRangeSwapBack(int index, int count)
  381. {
  382. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  383. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  384. #endif
  385. m_ListData->RemoveRangeSwapBack(CollectionHelper.AssumePositive(index), CollectionHelper.AssumePositive(count));
  386. }
  387. /// <summary>
  388. /// Copies the last *N* elements of this list to a range in this list. Decrements the length by *N*.
  389. /// </summary>
  390. /// <remarks>
  391. /// Copies the last `end - begin` elements to the indexes `begin` up to `end`.
  392. ///
  393. /// Useful as a cheap way to remove elements from a list when you don't care about preserving order.
  394. ///
  395. /// Does nothing if `end - begin` is less than 1.
  396. /// </remarks>
  397. /// <param name="begin">The index of the first element to overwrite.</param>
  398. /// <param name="end">The index one greater than the last element to overwrite.</param>
  399. /// <exception cref="ArgumentOutOfRangeException">Thrown if `begin` or `end` are out of bounds.</exception>
  400. [Obsolete("RemoveRangeSwapBackWithBeginEnd(begin, end) is deprecated, use RemoveRangeSwapBack(index, count) instead. (RemovedAfter 2021-06-02)", false)]
  401. public void RemoveRangeSwapBackWithBeginEnd(int begin, int end)
  402. {
  403. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  404. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  405. #endif
  406. m_ListData->RemoveRangeSwapBackWithBeginEnd(CollectionHelper.AssumePositive(begin), CollectionHelper.AssumePositive(end));
  407. }
  408. /// <summary>
  409. /// Removes the element at an index, shifting everything above it down by one. Decrements the length by 1.
  410. /// </summary>
  411. /// <param name="index">The index of the item to remove.</param>
  412. /// <remarks>
  413. /// If you don't care about preserving the order of the elements, <see cref="RemoveAtSwapBack(int)"/> is a more efficient way to remove elements.
  414. /// </remarks>
  415. /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds.</exception>
  416. public void RemoveAt(int index)
  417. {
  418. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  419. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  420. #endif
  421. m_ListData->RemoveAt(CollectionHelper.AssumePositive(index));
  422. }
  423. /// <summary>
  424. /// Removes *N* elements in a range, shifting everything above the range down by *N*. Decrements the length by *N*.
  425. /// </summary>
  426. /// <param name="index">The index of the first element to remove.</param>
  427. /// <param name="count">The number of elements to remove.</param>
  428. /// <remarks>
  429. /// If you don't care about preserving the order of the elements, <see cref="RemoveRangeSwapBackWithBeginEnd"/>
  430. /// is a more efficient way to remove elements.
  431. /// </remarks>
  432. /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds, `count` is negative,
  433. /// or `index + count` exceeds the length.</exception>
  434. public void RemoveRange(int index, int count)
  435. {
  436. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  437. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  438. #endif
  439. m_ListData->RemoveRange(index, count);
  440. }
  441. /// <summary>
  442. /// Removes *N* elements in a range, shifting everything above it down by *N*. Decrements the length by *N*.
  443. /// </summary>
  444. /// <param name="begin">The index of the first element to remove.</param>
  445. /// <param name="end">The index one greater than the last element to remove.</param>
  446. /// <remarks>
  447. /// If you don't care about preserving the order of the elements, <see cref="RemoveRangeSwapBackWithBeginEnd"/> is a more efficient way to remove elements.
  448. /// </remarks>
  449. /// <exception cref="ArgumentException">Thrown if `end &lt; begin`.</exception>
  450. /// <exception cref="ArgumentOutOfRangeException">Thrown if `begin` or `end` are out of bounds.</exception>
  451. [Obsolete("RemoveRangeWithBeginEnd(begin, end) is deprecated, use RemoveRange(index, count) instead. (RemovedAfter 2021-06-02)", false)]
  452. public void RemoveRangeWithBeginEnd(int begin, int end)
  453. {
  454. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  455. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  456. #endif
  457. m_ListData->RemoveRangeWithBeginEnd(begin, end);
  458. }
  459. /// <summary>
  460. /// Whether this list is empty.
  461. /// </summary>
  462. /// <value>True if the list is empty or if the list has not been constructed.</value>
  463. public bool IsEmpty => !IsCreated || Length == 0;
  464. /// <summary>
  465. /// Whether this list has been allocated (and not yet deallocated).
  466. /// </summary>
  467. /// <value>True if this list has been allocated (and not yet deallocated).</value>
  468. public bool IsCreated => m_ListData != null;
  469. /// <summary>
  470. /// Releases all resources (memory and safety handles).
  471. /// </summary>
  472. public void Dispose()
  473. {
  474. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  475. m_DeprecatedAllocator.TryRemoveSafetyHandle(m_Safety, m_SafetyIndexHint);
  476. #if REMOVE_DISPOSE_SENTINEL
  477. CollectionHelper.DisposeSafetyHandle(ref m_Safety);
  478. #else
  479. DisposeSentinel.Dispose(ref m_Safety, ref m_DisposeSentinel);
  480. #endif
  481. #endif
  482. UnsafeList<T>.Destroy(m_ListData);
  483. m_ListData = null;
  484. }
  485. /// <summary>
  486. /// Releases all resources (memory and safety handles).
  487. /// <typeparam name="U">The type of allocator.</typeparam>
  488. /// <param name="allocator">The allocator that was used to allocate this list.</param>
  489. /// </summary>
  490. [BurstCompatible(GenericTypeArguments = new[] { typeof(AllocatorManager.AllocatorHandle) })]
  491. internal void Dispose<U>(ref U allocator) where U : unmanaged, AllocatorManager.IAllocator
  492. {
  493. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  494. CheckHandleMatches(allocator.Handle);
  495. m_DeprecatedAllocator.TryRemoveSafetyHandle(m_Safety, m_SafetyIndexHint);
  496. #if REMOVE_DISPOSE_SENTINEL
  497. CollectionHelper.DisposeSafetyHandle(ref m_Safety);
  498. #else
  499. DisposeSentinel.Dispose(ref m_Safety, ref m_DisposeSentinel);
  500. #endif
  501. #endif
  502. UnsafeList<T>.Destroy(m_ListData, ref allocator);
  503. m_ListData = null;
  504. }
  505. /// <summary>
  506. /// Creates and schedules a job that releases all resources (memory and safety handles) of this list.
  507. /// </summary>
  508. /// <param name="inputDeps">The dependency for the new job.</param>
  509. /// <returns>The handle of the new job. The job depends upon `inputDeps` and releases all resources (memory and safety handles) of this list.</returns>
  510. [NotBurstCompatible /* This is not burst compatible because of IJob's use of a static IntPtr. Should switch to IJobBurstSchedulable in the future */]
  511. public JobHandle Dispose(JobHandle inputDeps)
  512. {
  513. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  514. #if REMOVE_DISPOSE_SENTINEL
  515. #else
  516. // [DeallocateOnJobCompletion] is not supported, but we want the deallocation
  517. // to happen in a thread. DisposeSentinel needs to be cleared on main thread.
  518. // AtomicSafetyHandle can be destroyed after the job was scheduled (Job scheduling
  519. // will check that no jobs are writing to the container).
  520. DisposeSentinel.Clear(ref m_DisposeSentinel);
  521. #endif
  522. var jobHandle = new NativeListDisposeJob { Data = new NativeListDispose { m_ListData = (UntypedUnsafeList*)m_ListData, m_Safety = m_Safety } }.Schedule(inputDeps);
  523. AtomicSafetyHandle.Release(m_Safety);
  524. #else
  525. var jobHandle = new NativeListDisposeJob { Data = new NativeListDispose { m_ListData = (UntypedUnsafeList*)m_ListData } }.Schedule(inputDeps);
  526. #endif
  527. m_ListData = null;
  528. return jobHandle;
  529. }
  530. /// <summary>
  531. /// Sets the length to 0.
  532. /// </summary>
  533. /// <remarks>Does not change the capacity.</remarks>
  534. public void Clear()
  535. {
  536. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  537. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  538. #endif
  539. m_ListData->Clear();
  540. }
  541. /// <summary>
  542. /// Returns a native array that aliases the content of a list.
  543. /// </summary>
  544. /// <param name="nativeList">The list to alias.</param>
  545. /// <returns>A native array that aliases the content of the list.</returns>
  546. public static implicit operator NativeArray<T>(NativeList<T> nativeList)
  547. {
  548. return nativeList.AsArray();
  549. }
  550. /// <summary>
  551. /// Returns a native array that aliases the content of this list.
  552. /// </summary>
  553. /// <returns>A native array that aliases the content of this list.</returns>
  554. public NativeArray<T> AsArray()
  555. {
  556. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  557. AtomicSafetyHandle.CheckGetSecondaryDataPointerAndThrow(m_Safety);
  558. var arraySafety = m_Safety;
  559. AtomicSafetyHandle.UseSecondaryVersion(ref arraySafety);
  560. #endif
  561. var array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<T>(m_ListData->Ptr, m_ListData->Length, Allocator.None);
  562. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  563. NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, arraySafety);
  564. #endif
  565. return array;
  566. }
  567. /// <summary>
  568. /// Returns an array that aliases this list. The length of the array is updated when the length of
  569. /// this array is updated in a prior job.
  570. /// </summary>
  571. /// <remarks>
  572. /// Useful when a job populates a list that is then used by another job.
  573. ///
  574. /// If you pass both jobs the same list, you have to complete the first job before you schedule the second:
  575. /// otherwise, the second job doesn't see the first job's changes to the list's length.
  576. ///
  577. /// If instead you pass the second job a deferred array that aliases the list, the array's length is kept in sync with
  578. /// the first job's changes to the list's length. Consequently, the first job doesn't have to
  579. /// be completed before you can schedule the second: the second job simply has to depend upon the first.
  580. /// </remarks>
  581. /// <returns>An array that aliases this list and whose length can be specially modified across jobs.</returns>
  582. /// <example>
  583. /// The following example populates a list with integers in one job and passes that data to a second job as
  584. /// a deferred array. If we tried to pass the list directly to the second job, that job would not see any
  585. /// modifications made to the list by the first job. To avoid this, we instead pass the second job a deferred array that aliases the list.
  586. /// <code>
  587. /// using UnityEngine;
  588. /// using Unity.Jobs;
  589. /// using Unity.Collections;
  590. ///
  591. /// public class DeferredArraySum : MonoBehaviour
  592. ///{
  593. /// public struct Populate : IJob
  594. /// {
  595. /// public NativeList&lt;int&gt; list;
  596. ///
  597. /// public void Execute()
  598. /// {
  599. /// for (int i = list.Length; i &lt; list.Capacity; i++)
  600. /// {
  601. /// list.Add(i);
  602. /// }
  603. /// }
  604. /// }
  605. ///
  606. /// // Sums all numbers from deferred.
  607. /// public struct Sum : IJob
  608. /// {
  609. /// [ReadOnly] public NativeArray&lt;int&gt; deferred;
  610. /// public NativeArray&lt;int&gt; sum;
  611. ///
  612. /// public void Execute()
  613. /// {
  614. /// sum[0] = 0;
  615. /// for (int i = 0; i &lt; deferred.Length; i++)
  616. /// {
  617. /// sum[0] += deferred[i];
  618. /// }
  619. /// }
  620. /// }
  621. ///
  622. /// void Start()
  623. /// {
  624. /// var list = new NativeList&lt;int&gt;(100, Allocator.TempJob);
  625. /// var deferred = list.AsDeferredJobArray(),
  626. /// var output = new NativeArray&lt;int&gt;(1, Allocator.TempJob);
  627. ///
  628. /// // The Populate job increases the list's length from 0 to 100.
  629. /// var populate = new Populate { list = list }.Schedule();
  630. ///
  631. /// // At time of scheduling, the length of the deferred array given to Sum is 0.
  632. /// // When Populate increases the list's length, the deferred array's length field in the
  633. /// // Sum job is also modified, even though it has already been scheduled.
  634. /// var sum = new Sum { deferred = deferred, sum = output }.Schedule(populate);
  635. ///
  636. /// sum.Complete();
  637. ///
  638. /// Debug.Log("Result: " + output[0]);
  639. ///
  640. /// list.Dispose();
  641. /// output.Dispose();
  642. /// }
  643. /// }
  644. /// </code>
  645. /// </example>
  646. public NativeArray<T> AsDeferredJobArray()
  647. {
  648. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  649. AtomicSafetyHandle.CheckExistsAndThrow(m_Safety);
  650. #endif
  651. byte* buffer = (byte*)m_ListData;
  652. // We use the first bit of the pointer to infer that the array is in list mode
  653. // Thus the job scheduling code will need to patch it.
  654. buffer += 1;
  655. var array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<T>(buffer, 0, Allocator.Invalid);
  656. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  657. NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, m_Safety);
  658. #endif
  659. return array;
  660. }
  661. /// <summary>
  662. /// Returns a managed array containing a copy of this list's content.
  663. /// </summary>
  664. /// <returns>A NativeArray containing copies of all the items in the list.</returns>
  665. [NotBurstCompatible /* Deprecated */]
  666. // todo: reenable deprecation warning before release [see: DOTS-DOTS-4217]
  667. // [Obsolete("Please use `ToArrayNBC` from `Unity.Collections.NotBurstCompatible` namespace instead. (RemovedAfter 2021-06-22)", false)]
  668. public T[] ToArray() => NotBurstCompatible.Extensions.ToArrayNBC(this);
  669. /// <summary>
  670. /// Returns an array containing a copy of this list's content.
  671. /// </summary>
  672. /// <param name="allocator">The allocator to use.</param>
  673. /// <returns>An array containing a copy of this list's content.</returns>
  674. public NativeArray<T> ToArray(AllocatorManager.AllocatorHandle allocator)
  675. {
  676. NativeArray<T> result = CollectionHelper.CreateNativeArray<T>(Length, allocator, NativeArrayOptions.UninitializedMemory);
  677. result.CopyFrom(this);
  678. return result;
  679. }
  680. /// <summary>
  681. /// Returns an enumerator over the elements of this list.
  682. /// </summary>
  683. /// <returns>An enumerator over the elements of this list.</returns>
  684. public NativeArray<T>.Enumerator GetEnumerator()
  685. {
  686. var array = AsArray();
  687. return new NativeArray<T>.Enumerator(ref array);
  688. }
  689. /// <summary>
  690. /// This method is not implemented. Use <see cref="GetEnumerator"/> instead.
  691. /// </summary>
  692. /// <returns>Throws NotImplementedException.</returns>
  693. /// <exception cref="NotImplementedException">Method is not implemented.</exception>
  694. IEnumerator IEnumerable.GetEnumerator()
  695. {
  696. throw new NotImplementedException();
  697. }
  698. /// <summary>
  699. /// This method is not implemented. Use <see cref="GetEnumerator"/> instead.
  700. /// </summary>
  701. /// <returns>Throws NotImplementedException.</returns>
  702. /// <exception cref="NotImplementedException">Method is not implemented.</exception>
  703. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  704. {
  705. throw new NotImplementedException();
  706. }
  707. /// <summary>
  708. /// Overwrites the elements of this list with the elements of an equal-length array.
  709. /// </summary>
  710. /// <param name="array">An array to copy into this list.</param>
  711. /// <exception cref="ArgumentException">Thrown if the array and list have unequal length.</exception>
  712. [NotBurstCompatible /* Deprecated */]
  713. [Obsolete("Please use `CopyFromNBC` from `Unity.Collections.NotBurstCompatible` namespace instead. (RemovedAfter 2021-06-22)", false)]
  714. public void CopyFrom(T[] array) => NotBurstCompatible.Extensions.CopyFromNBC(this, array);
  715. /// <summary>
  716. /// Overwrites the elements of this list with the elements of an equal-length array.
  717. /// </summary>
  718. /// <param name="array">An array to copy into this list.</param>
  719. /// <exception cref="ArgumentException">Thrown if the array and list have unequal length.</exception>
  720. public void CopyFrom(NativeArray<T> array)
  721. {
  722. Clear();
  723. Resize(array.Length, NativeArrayOptions.UninitializedMemory);
  724. NativeArray<T> thisArray = AsArray();
  725. thisArray.CopyFrom(array);
  726. }
  727. /// <summary>
  728. /// Sets the length of this list, increasing the capacity if necessary.
  729. /// </summary>
  730. /// <param name="length">The new length of this list.</param>
  731. /// <param name="options">Whether to clear any newly allocated bytes to all zeroes.</param>
  732. public void Resize(int length, NativeArrayOptions options)
  733. {
  734. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  735. AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
  736. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
  737. #endif
  738. m_ListData->Resize(length, options);
  739. }
  740. /// <summary>
  741. /// Sets the length of this list, increasing the capacity if necessary.
  742. /// </summary>
  743. /// <remarks>Does not clear newly allocated bytes.</remarks>
  744. /// <param name="length">The new length of this list.</param>
  745. public void ResizeUninitialized(int length)
  746. {
  747. Resize(length, NativeArrayOptions.UninitializedMemory);
  748. }
  749. /// <summary>
  750. /// Sets the capacity.
  751. /// </summary>
  752. /// <param name="capacity">The new capacity.</param>
  753. public void SetCapacity(int capacity)
  754. {
  755. m_ListData->SetCapacity(capacity);
  756. }
  757. /// <summary>
  758. /// Sets the capacity to match the length.
  759. /// </summary>
  760. public void TrimExcess()
  761. {
  762. m_ListData->TrimExcess();
  763. }
  764. /// <summary>
  765. /// Returns a parallel reader of this list.
  766. /// </summary>
  767. /// <returns>A parallel reader of this list.</returns>
  768. public NativeArray<T>.ReadOnly AsParallelReader()
  769. {
  770. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  771. return new NativeArray<T>.ReadOnly(m_ListData->Ptr, m_ListData->Length, ref m_Safety);
  772. #else
  773. return new NativeArray<T>.ReadOnly(m_ListData->Ptr, m_ListData->Length);
  774. #endif
  775. }
  776. /// <summary>
  777. /// Returns a parallel writer of this list.
  778. /// </summary>
  779. /// <returns>A parallel writer of this list.</returns>
  780. public ParallelWriter AsParallelWriter()
  781. {
  782. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  783. return new ParallelWriter(m_ListData, ref m_Safety);
  784. #else
  785. return new ParallelWriter(m_ListData);
  786. #endif
  787. }
  788. /// <summary>
  789. /// A parallel writer for a NativeList.
  790. /// </summary>
  791. /// <remarks>
  792. /// Use <see cref="AsParallelWriter"/> to create a parallel writer for a list.
  793. /// </remarks>
  794. [NativeContainer]
  795. [NativeContainerIsAtomicWriteOnly]
  796. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  797. public unsafe struct ParallelWriter
  798. {
  799. /// <summary>
  800. /// The data of the list.
  801. /// </summary>
  802. public readonly void* Ptr => ListData->Ptr;
  803. /// <summary>
  804. /// The internal unsafe list.
  805. /// </summary>
  806. /// <value>The internal unsafe list.</value>
  807. [NativeDisableUnsafePtrRestriction]
  808. public UnsafeList<T>* ListData;
  809. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  810. internal AtomicSafetyHandle m_Safety;
  811. internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<ParallelWriter>();
  812. [BurstCompatible(CompileTarget = BurstCompatibleAttribute.BurstCompatibleCompileTarget.Editor)]
  813. internal unsafe ParallelWriter(UnsafeList<T>* listData, ref AtomicSafetyHandle safety)
  814. {
  815. ListData = listData;
  816. m_Safety = safety;
  817. CollectionHelper.SetStaticSafetyId<ParallelWriter>(ref m_Safety, ref s_staticSafetyId.Data);
  818. }
  819. #else
  820. internal unsafe ParallelWriter(UnsafeList<T>* listData)
  821. {
  822. ListData = listData;
  823. }
  824. #endif
  825. /// <summary>
  826. /// Appends an element to the end of this list.
  827. /// </summary>
  828. /// <param name="value">The value to add to the end of this list.</param>
  829. /// <remarks>
  830. /// Increments the length by 1 unless doing so would exceed the current capacity.
  831. /// </remarks>
  832. /// <exception cref="Exception">Thrown if adding an element would exceed the capacity.</exception>
  833. public void AddNoResize(T value)
  834. {
  835. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  836. AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
  837. #endif
  838. var idx = Interlocked.Increment(ref ListData->m_length) - 1;
  839. CheckSufficientCapacity(ListData->Capacity, idx + 1);
  840. UnsafeUtility.WriteArrayElement(ListData->Ptr, idx, value);
  841. }
  842. /// <summary>
  843. /// Appends elements from a buffer to the end of this list.
  844. /// </summary>
  845. /// <param name="ptr">The buffer to copy from.</param>
  846. /// <param name="count">The number of elements to copy from the buffer.</param>
  847. /// <remarks>
  848. /// Increments the length by `count` unless doing so would exceed the current capacity.
  849. /// </remarks>
  850. /// <exception cref="Exception">Thrown if adding the elements would exceed the capacity.</exception>
  851. public void AddRangeNoResize(void* ptr, int count)
  852. {
  853. CheckArgPositive(count);
  854. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  855. AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
  856. #endif
  857. var idx = Interlocked.Add(ref ListData->m_length, count) - count;
  858. CheckSufficientCapacity(ListData->Capacity, idx + count);
  859. var sizeOf = sizeof(T);
  860. void* dst = (byte*)ListData->Ptr + idx * sizeOf;
  861. UnsafeUtility.MemCpy(dst, ptr, count * sizeOf);
  862. }
  863. /// <summary>
  864. /// Appends the elements of another list to the end of this list.
  865. /// </summary>
  866. /// <param name="list">The other list to copy from.</param>
  867. /// <remarks>
  868. /// Increments the length of this list by the length of the other list unless doing so would exceed the current capacity.
  869. /// </remarks>
  870. /// <exception cref="Exception">Thrown if adding the elements would exceed the capacity.</exception>
  871. public void AddRangeNoResize(UnsafeList<T> list)
  872. {
  873. AddRangeNoResize(list.Ptr, list.Length);
  874. }
  875. /// <summary>
  876. /// Appends the elements of another list to the end of this list.
  877. /// </summary>
  878. /// <param name="list">The other list to copy from.</param>
  879. /// <remarks>
  880. /// Increments the length of this list by the length of the other list unless doing so would exceed the current capacity.
  881. /// </remarks>
  882. /// <exception cref="Exception">Thrown if adding the elements would exceed the capacity.</exception>
  883. public void AddRangeNoResize(NativeList<T> list)
  884. {
  885. AddRangeNoResize(*list.m_ListData);
  886. }
  887. }
  888. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  889. static void CheckInitialCapacity(int initialCapacity)
  890. {
  891. if (initialCapacity < 0)
  892. throw new ArgumentOutOfRangeException(nameof(initialCapacity), "Capacity must be >= 0");
  893. }
  894. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  895. static void CheckTotalSize(int initialCapacity, long totalSize)
  896. {
  897. // Make sure we cannot allocate more than int.MaxValue (2,147,483,647 bytes)
  898. // because the underlying UnsafeUtility.Malloc is expecting a int.
  899. // TODO: change UnsafeUtility.Malloc to accept a UIntPtr length instead to match C++ API
  900. if (totalSize > int.MaxValue)
  901. throw new ArgumentOutOfRangeException(nameof(initialCapacity), $"Capacity * sizeof(T) cannot exceed {int.MaxValue} bytes");
  902. }
  903. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  904. static void CheckSufficientCapacity(int capacity, int length)
  905. {
  906. if (capacity < length)
  907. throw new Exception($"Length {length} exceeds capacity Capacity {capacity}");
  908. }
  909. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  910. static void CheckIndexInRange(int value, int length)
  911. {
  912. if (value < 0)
  913. throw new IndexOutOfRangeException($"Value {value} must be positive.");
  914. if ((uint)value >= (uint)length)
  915. throw new IndexOutOfRangeException($"Value {value} is out of range in NativeList of '{length}' Length.");
  916. }
  917. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  918. static void CheckArgPositive(int value)
  919. {
  920. if (value < 0)
  921. throw new ArgumentOutOfRangeException($"Value {value} must be positive.");
  922. }
  923. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  924. void CheckHandleMatches(AllocatorManager.AllocatorHandle handle)
  925. {
  926. if(m_ListData == null)
  927. throw new ArgumentOutOfRangeException($"Allocator handle {handle} can't match because container is not initialized.");
  928. if(m_ListData->Allocator.Index != handle.Index)
  929. throw new ArgumentOutOfRangeException($"Allocator handle {handle} can't match because container handle index doesn't match.");
  930. if(m_ListData->Allocator.Version != handle.Version)
  931. throw new ArgumentOutOfRangeException($"Allocator handle {handle} matches container handle index, but has different version.");
  932. }
  933. }
  934. [NativeContainer]
  935. [BurstCompatible]
  936. internal unsafe struct NativeListDispose
  937. {
  938. [NativeDisableUnsafePtrRestriction]
  939. public UntypedUnsafeList* m_ListData;
  940. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  941. internal AtomicSafetyHandle m_Safety;
  942. #endif
  943. public void Dispose()
  944. {
  945. var listData = (UnsafeList<int>*)m_ListData;
  946. UnsafeList<int>.Destroy(listData);
  947. }
  948. }
  949. [BurstCompile]
  950. [BurstCompatible]
  951. internal unsafe struct NativeListDisposeJob : IJob
  952. {
  953. internal NativeListDispose Data;
  954. public void Execute()
  955. {
  956. Data.Dispose();
  957. }
  958. }
  959. sealed class NativeListDebugView<T> where T : unmanaged
  960. {
  961. NativeList<T> m_Array;
  962. public NativeListDebugView(NativeList<T> array)
  963. {
  964. m_Array = array;
  965. }
  966. public T[] Items => m_Array.AsArray().ToArray();
  967. }
  968. }
  969. namespace Unity.Collections.LowLevel.Unsafe
  970. {
  971. /// <summary>
  972. /// Provides unsafe utility methods for NativeList.
  973. /// </summary>
  974. [BurstCompatible]
  975. public unsafe static class NativeListUnsafeUtility
  976. {
  977. /// <summary>
  978. /// Returns a pointer to this list's internal buffer.
  979. /// </summary>
  980. /// <remarks>Performs a job safety check for read-write access.</remarks>
  981. /// <param name="list">The list.</param>
  982. /// <typeparam name="T">The type of the elements.</typeparam>
  983. /// <returns>A pointer to this list's internal buffer.</returns>
  984. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  985. public static void* GetUnsafePtr<T>(this NativeList<T> list) where T : unmanaged
  986. {
  987. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  988. AtomicSafetyHandle.CheckWriteAndThrow(list.m_Safety);
  989. #endif
  990. return list.m_ListData->Ptr;
  991. }
  992. /// <summary>
  993. /// Returns a pointer to this list's internal buffer.
  994. /// </summary>
  995. /// <remarks>Performs a job safety check for read-only access.</remarks>
  996. /// <param name="list">The list.</param>
  997. /// <typeparam name="T">The type of the elements.</typeparam>
  998. /// <returns>A pointer to this list's internal buffer.</returns>
  999. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  1000. public static unsafe void* GetUnsafeReadOnlyPtr<T>(this NativeList<T> list) where T : unmanaged
  1001. {
  1002. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  1003. AtomicSafetyHandle.CheckReadAndThrow(list.m_Safety);
  1004. #endif
  1005. return list.m_ListData->Ptr;
  1006. }
  1007. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  1008. /// <summary>
  1009. /// Returns this list's <see cref="AtomicSafetyHandle"/>.
  1010. /// </summary>
  1011. /// <param name="list">The list.</param>
  1012. /// <typeparam name="T">The type of the elements.</typeparam>
  1013. /// <returns>The atomic safety handle for this list.</returns>
  1014. /// <remarks>
  1015. /// The job safety checks use a native collection's atomic safety handle to assert safety.
  1016. ///
  1017. /// This method is only available if the symbol `ENABLE_UNITY_COLLECTIONS_CHECKS` is defined.</remarks>
  1018. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) }, RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS", CompileTarget = BurstCompatibleAttribute.BurstCompatibleCompileTarget.Editor)]
  1019. public static AtomicSafetyHandle GetAtomicSafetyHandle<T>(ref NativeList<T> list) where T : unmanaged
  1020. {
  1021. return list.m_Safety;
  1022. }
  1023. #endif
  1024. /// <summary>
  1025. /// Returns a pointer to this list's internal unsafe list.
  1026. /// </summary>
  1027. /// <remarks>Performs no job safety checks.</remarks>
  1028. /// <param name="list">The list.</param>
  1029. /// <typeparam name="T">The type of the elements.</typeparam>
  1030. /// <returns>A pointer to this list's internal unsafe list.</returns>
  1031. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  1032. public static void* GetInternalListDataPtrUnchecked<T>(ref NativeList<T> list) where T : unmanaged
  1033. {
  1034. return list.m_ListData;
  1035. }
  1036. }
  1037. }