Geen omschrijving
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 53KB

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