Bez popisu
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.

FixedList.tt 54KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  1. <#/*THIS IS A T4 FILE - see t4_text_templating.md for what it is and how to run codegen*/#>
  2. <#@ template debug="True" #>
  3. <#@ output extension=".gen.cs" encoding="utf-8" #>
  4. <#@ assembly name="System.Core" #>
  5. <#@ import namespace="System.Globalization" #>
  6. <#@ import namespace="System.Security.Cryptography" #>
  7. //------------------------------------------------------------------------------
  8. // <auto-generated>
  9. // This code was generated by a tool.
  10. //
  11. // TextTransform Samples/Packages/com.unity.collections/Unity.Collections/FixedList.tt
  12. //
  13. // Changes to this file may cause incorrect behavior and will be lost if
  14. // the code is regenerated.
  15. // </auto-generated>
  16. //------------------------------------------------------------------------------
  17. using System.Collections.Generic;
  18. using System.Collections;
  19. using System.Diagnostics;
  20. using System.Runtime.CompilerServices;
  21. using System.Runtime.InteropServices;
  22. using System;
  23. using Unity.Collections.LowLevel.Unsafe;
  24. using Unity.Mathematics;
  25. using UnityEngine.Internal;
  26. using UnityEngine;
  27. using Unity.Properties;
  28. namespace Unity.Collections
  29. {
  30. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(FixedBytes32Align8) })]
  31. [Serializable]
  32. internal struct FixedList<T,U>
  33. : INativeList<T>
  34. where T : unmanaged
  35. where U : unmanaged
  36. {
  37. [SerializeField] internal U data;
  38. internal ushort length
  39. {
  40. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  41. readonly get
  42. {
  43. unsafe
  44. {
  45. fixed(void* ptr = &data)
  46. return *((ushort*)ptr);
  47. }
  48. }
  49. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  50. set
  51. {
  52. unsafe
  53. {
  54. fixed (void* ptr = &data)
  55. *((ushort*)ptr) = value;
  56. }
  57. }
  58. }
  59. internal readonly unsafe byte* buffer
  60. {
  61. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  62. get
  63. {
  64. unsafe
  65. {
  66. fixed (void* ptr = &data)
  67. return ((byte*)ptr) + UnsafeUtility.SizeOf<ushort>();
  68. }
  69. }
  70. }
  71. /// <summary>
  72. /// The current number of items in this list.
  73. /// </summary>
  74. /// <value>The current number of items in this list.</value>
  75. [CreateProperty]
  76. public int Length
  77. {
  78. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  79. readonly get => length;
  80. set
  81. {
  82. FixedList.CheckResize<U,T>(value);
  83. length = (ushort)value;
  84. }
  85. }
  86. /// <summary>
  87. /// A property in order to display items in the Entity Inspector.
  88. /// </summary>
  89. [CreateProperty] IEnumerable<T> Elements => this.ToArray();
  90. /// <summary>
  91. /// Whether the list is empty.
  92. /// </summary>
  93. /// <value>True if this string has no characters or if the container has not been constructed.</value>
  94. public readonly bool IsEmpty
  95. {
  96. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  97. get => Length == 0;
  98. }
  99. internal readonly int LengthInBytes => Length * UnsafeUtility.SizeOf<T>();
  100. internal readonly unsafe byte* Buffer
  101. {
  102. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  103. get
  104. {
  105. return buffer + FixedList.PaddingBytes<T>();
  106. }
  107. }
  108. /// <summary>
  109. /// The number of elements that can fit in this list.
  110. /// </summary>
  111. /// <value>The number of elements that can fit in this list.</value>
  112. /// <remarks>The capacity of a FixedList cannot be changed. The setter is included only for conformity with <see cref="INativeList{T}"/>.</remarks>
  113. /// <exception cref="ArgumentOutOfRangeException">Thrown if the new value does not match the current capacity.</exception>
  114. public int Capacity
  115. {
  116. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  117. readonly get
  118. {
  119. return FixedList.Capacity<U,T>();
  120. }
  121. set
  122. {
  123. CollectionHelper.CheckCapacityInRange(value, Length);
  124. }
  125. }
  126. /// <summary>
  127. /// The element at a given index.
  128. /// </summary>
  129. /// <param name="index">An index.</param>
  130. /// <value>The value to store at the index.</value>
  131. /// <exception cref="IndexOutOfRangeException">Thrown if the index is out of bounds.</exception>
  132. public T this[int index]
  133. {
  134. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  135. readonly get
  136. {
  137. CollectionHelper.CheckIndexInRange(index, length);
  138. unsafe
  139. {
  140. return UnsafeUtility.ReadArrayElement<T>(Buffer, CollectionHelper.AssumePositive(index));
  141. }
  142. }
  143. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  144. set
  145. {
  146. CollectionHelper.CheckIndexInRange(index, length);
  147. unsafe
  148. {
  149. UnsafeUtility.WriteArrayElement<T>(Buffer, CollectionHelper.AssumePositive(index), value);
  150. }
  151. }
  152. }
  153. /// <summary>
  154. /// Returns the element at a given index.
  155. /// </summary>
  156. /// <param name="index">An index.</param>
  157. /// <returns>A reference to the element at the index.</returns>
  158. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  159. public ref T ElementAt(int index)
  160. {
  161. CollectionHelper.CheckIndexInRange(index, length);
  162. unsafe
  163. {
  164. return ref UnsafeUtility.ArrayElementAsRef<T>(Buffer, index);
  165. }
  166. }
  167. /// <summary>
  168. /// Returns the hash code of this list.
  169. /// </summary>
  170. /// <remarks>
  171. /// Only the content of the list (the bytes of the elements) are included in the hash. Any bytes beyond the length are not part of the hash.</remarks>
  172. /// <returns>The hash code of this list.</returns>
  173. public override int GetHashCode()
  174. {
  175. unsafe
  176. {
  177. return (int)CollectionHelper.Hash(Buffer, LengthInBytes);
  178. }
  179. }
  180. /// <summary>
  181. /// Appends an element to the end of this list. Increments the length by 1.
  182. /// </summary>
  183. /// <remarks>
  184. /// The same as <see cref="AddNoResize"/>. Included only for consistency with the other list types.
  185. /// If the element exceeds the capacity, throws cref="IndexOutOfRangeException", and the list is unchanged.
  186. /// </remarks>
  187. /// <param name="item">The element to append at the end of the list.</param>
  188. /// <exception cref="IndexOutOfRangeException">Thrown if the append exceeds the capacity.</exception>
  189. public void Add(in T item) => AddNoResize(in item);
  190. /// <summary>
  191. /// Appends elements from a buffer to the end of this list. Increments the length by the number of appended elements.
  192. /// </summary>
  193. /// <remarks>
  194. /// The same as <see cref="AddRangeNoResize"/>. Included only for consistency with the other list types.
  195. /// If the elements exceeds the capacity, throws cref="IndexOutOfRangeException", and the list is unchanged.
  196. /// </remarks>
  197. /// <param name="ptr">A buffer.</param>
  198. /// <param name="length">The number of elements from the buffer to append.</param>
  199. /// <exception cref="IndexOutOfRangeException">Thrown if the append exceeds the capacity.</exception>
  200. public unsafe void AddRange(void* ptr, int length) => AddRangeNoResize(ptr, length);
  201. /// <summary>
  202. /// Appends an element to the end of this list. Increments the length by 1.
  203. /// </summary>
  204. /// <remarks>
  205. /// If the element exceeds the capacity, throws cref="IndexOutOfRangeException", and the list is unchanged.
  206. /// </remarks>
  207. /// <param name="item">The element to append at the end of the list.</param>
  208. /// <exception cref="IndexOutOfRangeException">Thrown if the append exceeds the capacity.</exception>
  209. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  210. public void AddNoResize(in T item)
  211. {
  212. this[Length++] = item;
  213. }
  214. /// <summary>
  215. /// Appends elements from a buffer to the end of this list. Increments the length by the number of appended elements.
  216. /// </summary>
  217. /// <remarks>
  218. /// If the elements exceeds the capacity, throws cref="IndexOutOfRangeException", and the list is unchanged.
  219. /// </remarks>
  220. /// <param name="ptr">A buffer.</param>
  221. /// <param name="length">The number of elements from the buffer to append.</param>
  222. /// <exception cref="IndexOutOfRangeException">Thrown if the append exceeds the capacity.</exception>
  223. public unsafe void AddRangeNoResize(void* ptr, int length)
  224. {
  225. var idx = Length;
  226. Length += length;
  227. UnsafeUtility.MemCpy((T*)Buffer + idx, ptr, UnsafeUtility.SizeOf<T>() * length);
  228. }
  229. /// <summary>
  230. /// Appends value count times to the end of this list.
  231. /// </summary>
  232. /// <remarks>
  233. /// If the elements exceeds the capacity, throws cref="IndexOutOfRangeException", and the list is unchanged.
  234. /// </remarks>
  235. /// <param name="value">The value to add to the end of this list.</param>
  236. /// <param name="count">The number of times to replicate the value.</param>
  237. /// <exception cref="IndexOutOfRangeException">Thrown if the append exceeds the capacity.</exception>
  238. public unsafe void AddReplicate(in T value, int count)
  239. {
  240. var idx = Length;
  241. Length += count;
  242. fixed (T* ptr = &value)
  243. UnsafeUtility.MemCpyReplicate((T*)Buffer + idx, ptr, UnsafeUtility.SizeOf<T>(), count);
  244. }
  245. /// <summary>
  246. /// Sets the length to 0.
  247. /// </summary>
  248. /// <remarks> Does *not* zero out the bytes.</remarks>
  249. public void Clear()
  250. {
  251. Length = 0;
  252. }
  253. /// <summary>
  254. /// Shifts elements toward the end of this list, increasing its length.
  255. /// </summary>
  256. /// <remarks>
  257. /// Right-shifts elements in the list so as to create 'free' slots at the beginning or in the middle.
  258. ///
  259. /// The length is increased by `end - begin`.
  260. ///
  261. /// If `end` equals `begin`, the method does nothing.
  262. ///
  263. /// 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.
  264. ///
  265. /// The indexes `begin` up to `end` are not cleared: they will contain whatever values they held prior.
  266. /// </remarks>
  267. /// <param name="begin">The index of the first element that will be shifted up.</param>
  268. /// <param name="end">The index where the first shifted element will end up.</param>
  269. /// <exception cref="IndexOutOfRangeException">Thrown if the new length exceeds the capacity.</exception>
  270. public void InsertRangeWithBeginEnd(int begin, int end)
  271. {
  272. int items = end - begin;
  273. if(items < 1)
  274. return;
  275. int itemsToCopy = length - begin;
  276. Length += items;
  277. if(itemsToCopy < 1)
  278. return;
  279. int bytesToCopy = itemsToCopy * UnsafeUtility.SizeOf<T>();
  280. unsafe
  281. {
  282. byte *b = Buffer;
  283. byte *dest = b + end * UnsafeUtility.SizeOf<T>();
  284. byte *src = b + begin * UnsafeUtility.SizeOf<T>();
  285. UnsafeUtility.MemMove(dest, src, bytesToCopy);
  286. }
  287. }
  288. /// <summary>
  289. /// Shifts elements toward the end of this list, increasing its length.
  290. /// </summary>
  291. /// <remarks>
  292. /// Right-shifts elements in the list so as to create 'free' slots at the beginning or in the middle.
  293. ///
  294. /// The length is increased by `count`. If necessary, the capacity will be increased accordingly.
  295. ///
  296. /// If `count` equals `0`, the method does nothing.
  297. ///
  298. /// 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.
  299. ///
  300. /// The indexes `index` up to `index + count` are not cleared: they will contain whatever values they held prior.
  301. /// </remarks>
  302. /// <param name="index">The index of the first element that will be shifted up.</param>
  303. /// <param name="count">The number of elements to insert.</param>
  304. /// <exception cref="ArgumentException">Thrown if `count` is negative.</exception>
  305. /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds.</exception>
  306. public void InsertRange(int index, int count) => InsertRangeWithBeginEnd(index, index + count);
  307. /// <summary>
  308. /// Inserts a single element at an index. Increments the length by 1.
  309. /// </summary>
  310. /// <param name="index">The index at which to insert the element.</param>
  311. /// <param name="item">The element to insert.</param>
  312. /// <exception cref="ArgumentOutOfRangeException">Thrown if the index is out of bounds.</exception>
  313. public void Insert(int index, in T item)
  314. {
  315. InsertRangeWithBeginEnd(index, index+1);
  316. this[index] = item;
  317. }
  318. /// <summary>
  319. /// Copies the last element of this list to an index. Decrements the length by 1.
  320. /// </summary>
  321. /// <remarks>Useful as a cheap way to remove elements from a list when you don't care about preserving order.</remarks>
  322. /// <param name="index">The index to overwrite with the last element.</param>
  323. /// <exception cref="ArgumentOutOfRangeException">Thrown if the index is out of bounds.</exception>
  324. public void RemoveAtSwapBack(int index)
  325. {
  326. RemoveRangeSwapBack(index, 1);
  327. }
  328. /// <summary>
  329. /// Copies the last *N* elements of this list to a range in this list. Decrements the length by *N*.
  330. /// </summary>
  331. /// <remarks>
  332. /// Copies the last `count`-numbered elements to the range starting at `index`.
  333. ///
  334. /// Useful as a cheap way to remove elements from a list when you don't care about preserving order.
  335. ///
  336. /// Does nothing if the count is less than 1.
  337. /// </remarks>
  338. /// <param name="index">The first index of the destination range.</param>
  339. /// <param name="count">The number of elements to copy and the amount by which to decrement the length.</param>
  340. /// <exception cref="ArgumentOutOfRangeException">Thrown if the index is out of bounds.</exception>
  341. public void RemoveRangeSwapBack(int index, int count)
  342. {
  343. if (count > 0)
  344. {
  345. int copyFrom = math.max(Length - count, index + count);
  346. unsafe
  347. {
  348. var sizeOf = UnsafeUtility.SizeOf<T>();
  349. void* dst = Buffer + index * sizeOf;
  350. void* src = Buffer + copyFrom * sizeOf;
  351. UnsafeUtility.MemCpy(dst, src, (Length - copyFrom) * sizeOf);
  352. }
  353. Length -= count;
  354. }
  355. }
  356. /// <summary>
  357. /// Removes the element at an index. Shifts everything above the index down by one and decrements the length by 1.
  358. /// </summary>
  359. /// <param name="index">The index of the element to remove.</param>
  360. /// <remarks>
  361. /// If you don't care about preserving the order of the elements, `RemoveAtSwapBack` is a more efficient way to remove an element.
  362. /// </remarks>
  363. /// <exception cref="ArgumentOutOfRangeException">Thrown if the index is out of bounds.</exception>
  364. public void RemoveAt(int index)
  365. {
  366. RemoveRange(index, 1);
  367. }
  368. /// <summary>
  369. /// Removes *N* elements of a range. Shifts everything above the range down by *N* and decrements the length by *N*.
  370. /// </summary>
  371. /// <remarks>
  372. /// If you don't care about preserving the order of the elements, `RemoveAtSwapBack` is a more efficient way to remove elements.
  373. /// </remarks>
  374. /// <param name="index">The first index of the range to remove.</param>
  375. /// <param name="count">The number of elements to remove.</param>
  376. /// <exception cref="ArgumentOutOfRangeException">Thrown if the index is out of bounds.</exception>
  377. public void RemoveRange(int index, int count)
  378. {
  379. if (count > 0)
  380. {
  381. int copyFrom = math.min(index + count, Length);
  382. unsafe
  383. {
  384. var sizeOf = UnsafeUtility.SizeOf<T>();
  385. void* dst = Buffer + index * sizeOf;
  386. void* src = Buffer + copyFrom * sizeOf;
  387. UnsafeUtility.MemCpy(dst, src, (Length - copyFrom) * sizeOf);
  388. }
  389. Length -= count;
  390. }
  391. }
  392. /// <summary>
  393. /// Returns a managed array that is a copy of this list.
  394. /// </summary>
  395. /// <returns>A managed array that is a copy of this list.</returns>
  396. [ExcludeFromBurstCompatTesting("Returns managed array")]
  397. public T[] ToArray()
  398. {
  399. var result = new T[Length];
  400. unsafe
  401. {
  402. byte* s = Buffer;
  403. fixed(T* d = result)
  404. UnsafeUtility.MemCpy(d, s, LengthInBytes);
  405. }
  406. return result;
  407. }
  408. /// <summary>
  409. /// Returns an array that is a copy of this list.
  410. /// </summary>
  411. /// <param name="allocator">The allocator to use.</param>
  412. /// <returns>An array that is a copy of this list.</returns>
  413. public NativeArray<T> ToNativeArray(AllocatorManager.AllocatorHandle allocator)
  414. {
  415. unsafe
  416. {
  417. var copy = CollectionHelper.CreateNativeArray<T>(Length, allocator, NativeArrayOptions.UninitializedMemory);
  418. UnsafeUtility.MemCpy(copy.GetUnsafePtr(), Buffer, LengthInBytes);
  419. return copy;
  420. }
  421. }
  422. }
  423. [GenerateTestsForBurstCompatibility]
  424. struct FixedList
  425. {
  426. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
  427. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  428. internal static int PaddingBytes<T>() where T : unmanaged
  429. {
  430. return math.max(0, math.min(6, (1 << math.tzcnt(UnsafeUtility.SizeOf<T>())) - 2));
  431. }
  432. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  433. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  434. internal static int StorageBytes<BUFFER,T>() where BUFFER : unmanaged where T : unmanaged
  435. {
  436. return UnsafeUtility.SizeOf<BUFFER>() - UnsafeUtility.SizeOf<ushort>() - PaddingBytes<T>();
  437. }
  438. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  439. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  440. internal static int Capacity<BUFFER,T>() where BUFFER : unmanaged where T : unmanaged
  441. {
  442. return StorageBytes<BUFFER,T>() / UnsafeUtility.SizeOf<T>();
  443. }
  444. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  445. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
  446. internal static void CheckResize<BUFFER,T>(int newLength) where BUFFER : unmanaged where T : unmanaged
  447. {
  448. var Capacity = Capacity<BUFFER,T>();
  449. if (newLength < 0 || newLength > Capacity)
  450. throw new IndexOutOfRangeException($"NewLength {newLength} is out of range of '{Capacity}' Capacity.");
  451. }
  452. }
  453. <#
  454. var SIZES = new int[]{32,64,128,512,4096};
  455. for(var size = 0; size < 5; ++size)
  456. {
  457. var BYTES = SIZES[size];
  458. var BUFFER_BYTES = BYTES;
  459. var TYPENAME = String.Format("FixedList{0}Bytes", BYTES);
  460. var OLD_TYPENAME = String.Format("FixedList{0}", BYTES);
  461. #>
  462. /// <summary>
  463. /// An unmanaged, resizable list whose content is all stored directly in the <#=BYTES#>-byte struct. Useful for small lists.
  464. /// </summary>
  465. /// <typeparam name="T">The type of the elements.</typeparam>
  466. [Serializable]
  467. [DebuggerTypeProxy(typeof(<#=TYPENAME#>DebugView<>))]
  468. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
  469. public struct <#=TYPENAME#><T>
  470. : INativeList<T>
  471. , IEnumerable<T> // Used by collection initializers.
  472. <#
  473. foreach(var OTHERBYTES in SIZES)
  474. {
  475. var OTHERTYPENAME = String.Format("FixedList{0}Bytes", OTHERBYTES);
  476. WriteLine(" , IEquatable<{0}<T>>", OTHERTYPENAME);
  477. WriteLine(" , IComparable<{0}<T>>", OTHERTYPENAME);
  478. }
  479. #> where T : unmanaged
  480. {
  481. [SerializeField] internal FixedBytes<#=BUFFER_BYTES#>Align8 data;
  482. internal ushort length
  483. {
  484. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  485. readonly get
  486. {
  487. unsafe
  488. {
  489. fixed(void* ptr = &data)
  490. return *((ushort*)ptr);
  491. }
  492. }
  493. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  494. set
  495. {
  496. unsafe
  497. {
  498. fixed (void* ptr = &data)
  499. *((ushort*)ptr) = value;
  500. }
  501. }
  502. }
  503. internal readonly unsafe byte* buffer
  504. {
  505. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  506. get
  507. {
  508. unsafe
  509. {
  510. fixed (void* ptr = &data)
  511. return ((byte*)ptr) + UnsafeUtility.SizeOf<ushort>();
  512. }
  513. }
  514. }
  515. /// <summary>
  516. /// The current number of items in this list.
  517. /// </summary>
  518. /// <value>The current number of items in this list.</value>
  519. [CreateProperty]
  520. public int Length
  521. {
  522. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  523. readonly get => length;
  524. set
  525. {
  526. FixedList.CheckResize<FixedBytes<#=BUFFER_BYTES#>Align8,T>(value);
  527. length = (ushort)value;
  528. }
  529. }
  530. /// <summary>
  531. /// A property in order to display items in the Entity Inspector.
  532. /// </summary>
  533. [CreateProperty] IEnumerable<T> Elements => this.ToArray();
  534. /// <summary>
  535. /// Whether this list is empty.
  536. /// </summary>
  537. /// <value>True if this string has no characters or if the container has not been constructed.</value>
  538. public readonly bool IsEmpty
  539. {
  540. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  541. get => Length == 0;
  542. }
  543. internal int LengthInBytes => Length * UnsafeUtility.SizeOf<T>();
  544. /// <summary>
  545. /// Returns a pointer to the first element of the list buffer.
  546. /// </summary>
  547. /// <remarks>
  548. /// The pointer returned by this method points into the internals of the target list object. It is the
  549. /// caller's responsibility to ensure that the pointer is not used after the list is destroyed or goes
  550. /// out of scope.
  551. /// </remarks>
  552. /// <returns>A pointer to the first element of the list buffer.</returns>
  553. internal readonly unsafe byte* Buffer
  554. {
  555. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  556. get
  557. {
  558. return buffer + FixedList.PaddingBytes<T>();
  559. }
  560. }
  561. /// <summary>
  562. /// The number of elements that can fit in this list.
  563. /// </summary>
  564. /// <value>The number of elements that can fit in this list.</value>
  565. /// <remarks>The capacity of a FixedList cannot be changed. The setter is included only for conformity with <see cref="INativeList{T}"/>.</remarks>
  566. /// <exception cref="ArgumentOutOfRangeException">Thrown if the new value does not match the current capacity.</exception>
  567. public int Capacity
  568. {
  569. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  570. readonly get
  571. {
  572. return FixedList.Capacity<FixedBytes<#=BUFFER_BYTES#>Align8,T>();
  573. }
  574. set
  575. {
  576. CollectionHelper.CheckCapacityInRange(value, Length);
  577. }
  578. }
  579. /// <summary>
  580. /// The element at a given index.
  581. /// </summary>
  582. /// <param name="index">An index.</param>
  583. /// <value>The value to store at the index.</value>
  584. /// <exception cref="IndexOutOfRangeException">Thrown if the index is out of bounds.</exception>
  585. public T this[int index]
  586. {
  587. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  588. readonly get
  589. {
  590. CollectionHelper.CheckIndexInRange(index, length);
  591. unsafe
  592. {
  593. return UnsafeUtility.ReadArrayElement<T>(Buffer, CollectionHelper.AssumePositive(index));
  594. }
  595. }
  596. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  597. set
  598. {
  599. CollectionHelper.CheckIndexInRange(index, length);
  600. unsafe
  601. {
  602. UnsafeUtility.WriteArrayElement<T>(Buffer, CollectionHelper.AssumePositive(index), value);
  603. }
  604. }
  605. }
  606. /// <summary>
  607. /// Returns the element at a given index.
  608. /// </summary>
  609. /// <param name="index">An index.</param>
  610. /// <returns>The list element at the index.</returns>
  611. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  612. public ref T ElementAt(int index)
  613. {
  614. CollectionHelper.CheckIndexInRange(index, length);
  615. unsafe
  616. {
  617. return ref UnsafeUtility.ArrayElementAsRef<T>(Buffer, index);
  618. }
  619. }
  620. /// <summary>
  621. /// Returns the hash code of this list.
  622. /// </summary>
  623. /// <remarks>
  624. /// Only the content of the list (the bytes of the elements) are included in the hash. Any bytes beyond the length are not part of the hash.</remarks>
  625. /// <returns>The hash code of this list.</returns>
  626. public override int GetHashCode()
  627. {
  628. unsafe
  629. {
  630. return (int)CollectionHelper.Hash(Buffer, LengthInBytes);
  631. }
  632. }
  633. /// <summary>
  634. /// Appends an element to the end of this list. Increments the length by 1.
  635. /// </summary>
  636. /// <remarks>
  637. /// The same as <see cref="AddNoResize"/>. Included only for consistency with the other list types.
  638. /// If the element exceeds the capacity, throws cref="IndexOutOfRangeException", and the list is unchanged.
  639. /// </remarks>
  640. /// <param name="item">The element to append at the end of the list.</param>
  641. /// <exception cref="IndexOutOfRangeException">Thrown if the append exceeds the capacity.</exception>
  642. public void Add(in T item) => AddNoResize(in item);
  643. /// <summary>
  644. /// Appends elements from a buffer to the end of this list. Increments the length by the number of appended elements.
  645. /// </summary>
  646. /// <remarks>
  647. /// The same as <see cref="AddRangeNoResize"/>. Included only for consistency with the other list types.
  648. /// If the elements exceeds the capacity, throws cref="IndexOutOfRangeException", and the list is unchanged.
  649. /// </remarks>
  650. /// <param name="ptr">A buffer.</param>
  651. /// <param name="length">The number of elements from the buffer to append.</param>
  652. /// <exception cref="IndexOutOfRangeException">Thrown if the append exceeds the capacity.</exception>
  653. public unsafe void AddRange(void* ptr, int length) => AddRangeNoResize(ptr, length);
  654. /// <summary>
  655. /// Appends an element to the end of this list. Increments the length by 1.
  656. /// </summary>
  657. /// <remarks>
  658. /// If the element exceeds the capacity, throws cref="IndexOutOfRangeException", and the list is unchanged.
  659. /// </remarks>
  660. /// <param name="item">The element to append at the end of the list.</param>
  661. /// <exception cref="IndexOutOfRangeException">Thrown if the append exceeds the capacity.</exception>
  662. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  663. public void AddNoResize(in T item)
  664. {
  665. this[Length++] = item;
  666. }
  667. /// <summary>
  668. /// Appends elements from a buffer to the end of this list. Increments the length by the number of appended elements.
  669. /// </summary>
  670. /// <remarks>
  671. /// If the elements exceeds the capacity, throws cref="IndexOutOfRangeException", and the list is unchanged.
  672. /// </remarks>
  673. /// <param name="ptr">A buffer.</param>
  674. /// <param name="length">The number of elements from the buffer to append.</param>
  675. /// <exception cref="IndexOutOfRangeException">Thrown if the append exceeds the capacity.</exception>
  676. public unsafe void AddRangeNoResize(void* ptr, int length)
  677. {
  678. var idx = Length;
  679. Length += length;
  680. UnsafeUtility.MemCpy((T*)Buffer + idx, ptr, UnsafeUtility.SizeOf<T>() * length);
  681. }
  682. /// <summary>
  683. /// Appends value count times to the end of this list.
  684. /// </summary>
  685. /// <param name="value">The value to add to the end of this list.</param>
  686. /// <param name="count">The number of times to replicate the value.</param>
  687. /// <exception cref="IndexOutOfRangeException">Thrown if the append exceeds the capacity.</exception>
  688. public unsafe void AddReplicate(in T value, int count)
  689. {
  690. var idx = Length;
  691. Length += count;
  692. fixed (T* ptr = &value)
  693. UnsafeUtility.MemCpyReplicate((T*)Buffer + idx, ptr, UnsafeUtility.SizeOf<T>(), count);
  694. }
  695. /// <summary>
  696. /// Sets the length to 0.
  697. /// </summary>
  698. /// <remarks> Does *not* zero out the bytes.</remarks>
  699. public void Clear()
  700. {
  701. Length = 0;
  702. }
  703. /// <summary>
  704. /// Shifts elements toward the end of this list, increasing its length.
  705. /// </summary>
  706. /// <remarks>
  707. /// Right-shifts elements in the list so as to create 'free' slots at the beginning or in the middle.
  708. ///
  709. /// The length is increased by `end - begin`.
  710. ///
  711. /// If `end` equals `begin`, the method does nothing.
  712. ///
  713. /// 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.
  714. ///
  715. /// The indexes `begin` up to `end` are not cleared: they will contain whatever values they held prior.
  716. /// </remarks>
  717. /// <param name="begin">The index of the first element that will be shifted up.</param>
  718. /// <param name="end">The index where the first shifted element will end up.</param>
  719. /// <exception cref="IndexOutOfRangeException">Thrown if the new length exceeds the capacity.</exception>
  720. public void InsertRangeWithBeginEnd(int begin, int end)
  721. {
  722. int items = end - begin;
  723. if(items < 1)
  724. return;
  725. int itemsToCopy = length - begin;
  726. Length += items;
  727. if(itemsToCopy < 1)
  728. return;
  729. int bytesToCopy = itemsToCopy * UnsafeUtility.SizeOf<T>();
  730. unsafe
  731. {
  732. byte *b = Buffer;
  733. byte *dest = b + end * UnsafeUtility.SizeOf<T>();
  734. byte *src = b + begin * UnsafeUtility.SizeOf<T>();
  735. UnsafeUtility.MemMove(dest, src, bytesToCopy);
  736. }
  737. }
  738. /// <summary>
  739. /// Shifts elements toward the end of this list, increasing its length.
  740. /// </summary>
  741. /// <remarks>
  742. /// Right-shifts elements in the list so as to create 'free' slots at the beginning or in the middle.
  743. ///
  744. /// The length is increased by `count`. If necessary, the capacity will be increased accordingly.
  745. ///
  746. /// If `count` equals `0`, the method does nothing.
  747. ///
  748. /// 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.
  749. ///
  750. /// The indexes `index` up to `index + count` are not cleared: they will contain whatever values they held prior.
  751. /// </remarks>
  752. /// <param name="index">The index of the first element that will be shifted up.</param>
  753. /// <param name="count">The number of elements to insert.</param>
  754. /// <exception cref="ArgumentException">Thrown if `count` is negative.</exception>
  755. /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds.</exception>
  756. public void InsertRange(int index, int count) => InsertRangeWithBeginEnd(index, index + count);
  757. /// <summary>
  758. /// Inserts a single element at an index. Increments the length by 1.
  759. /// </summary>
  760. /// <param name="index">The index at which to insert the element.</param>
  761. /// <param name="item">The element to insert.</param>
  762. /// <exception cref="ArgumentOutOfRangeException">Thrown if the index is out of bounds.</exception>
  763. public void Insert(int index, in T item)
  764. {
  765. InsertRangeWithBeginEnd(index, index+1);
  766. this[index] = item;
  767. }
  768. /// <summary>
  769. /// Copies the last element of this list to an index. Decrements the length by 1.
  770. /// </summary>
  771. /// <remarks>Useful as a cheap way to remove elements from a list when you don't care about preserving order.</remarks>
  772. /// <param name="index">The index to overwrite with the last element.</param>
  773. /// <exception cref="ArgumentOutOfRangeException">Thrown if the index is out of bounds.</exception>
  774. public void RemoveAtSwapBack(int index)
  775. {
  776. RemoveRangeSwapBack(index, 1);
  777. }
  778. /// <summary>
  779. /// Copies the last *N* elements of this list to a range in this list. Decrements the length by *N*.
  780. /// </summary>
  781. /// <remarks>
  782. /// Copies the last `count`-numbered elements to the range starting at `index`.
  783. ///
  784. /// Useful as a cheap way to remove elements from a list when you don't care about preserving order.
  785. ///
  786. /// Does nothing if the count is less than 1.
  787. /// </remarks>
  788. /// <param name="index">The first index of the destination range.</param>
  789. /// <param name="count">The number of elements to copy and the amount by which to decrement the length.</param>
  790. /// <exception cref="ArgumentOutOfRangeException">Thrown if the index is out of bounds.</exception>
  791. public void RemoveRangeSwapBack(int index, int count)
  792. {
  793. if (count > 0)
  794. {
  795. int copyFrom = math.max(Length - count, index + count);
  796. unsafe
  797. {
  798. var sizeOf = UnsafeUtility.SizeOf<T>();
  799. void* dst = Buffer + index * sizeOf;
  800. void* src = Buffer + copyFrom * sizeOf;
  801. UnsafeUtility.MemCpy(dst, src, (Length - copyFrom) * sizeOf);
  802. }
  803. Length -= count;
  804. }
  805. }
  806. /// <summary>
  807. /// Removes the element at an index. Shifts everything above the index down by one and decrements the length by 1.
  808. /// </summary>
  809. /// <param name="index">The index of the element to remove.</param>
  810. /// <remarks>
  811. /// If you don't care about preserving the order of the elements, `RemoveAtSwapBack` is a more efficient way to remove an element.
  812. /// </remarks>
  813. /// <exception cref="ArgumentOutOfRangeException">Thrown if the index is out of bounds.</exception>
  814. public void RemoveAt(int index)
  815. {
  816. RemoveRange(index, 1);
  817. }
  818. /// <summary>
  819. /// Removes *N* elements of a range. Shifts everything above the range down by *N* and decrements the length by *N*.
  820. /// </summary>
  821. /// <remarks>
  822. /// If you don't care about preserving the order of the elements, `RemoveAtSwapBack` is a more efficient way to remove elements.
  823. /// </remarks>
  824. /// <param name="index">The first index of the range to remove.</param>
  825. /// <param name="count">The number of elements to remove.</param>
  826. /// <exception cref="ArgumentOutOfRangeException">Thrown if the index is out of bounds.</exception>
  827. public void RemoveRange(int index, int count)
  828. {
  829. if (count > 0)
  830. {
  831. int copyFrom = math.min(index + count, Length);
  832. unsafe
  833. {
  834. var sizeOf = UnsafeUtility.SizeOf<T>();
  835. void* dst = Buffer + index * sizeOf;
  836. void* src = Buffer + copyFrom * sizeOf;
  837. UnsafeUtility.MemCpy(dst, src, (Length - copyFrom) * sizeOf);
  838. }
  839. Length -= count;
  840. }
  841. }
  842. /// <summary>
  843. /// Returns a managed array that is a copy of this list.
  844. /// </summary>
  845. /// <returns>A managed array that is a copy of this list.</returns>
  846. [ExcludeFromBurstCompatTesting("Returns managed array")]
  847. public T[] ToArray()
  848. {
  849. var result = new T[Length];
  850. unsafe
  851. {
  852. byte* s = Buffer;
  853. fixed(T* d = result)
  854. UnsafeUtility.MemCpy(d, s, LengthInBytes);
  855. }
  856. return result;
  857. }
  858. /// <summary>
  859. /// Returns an array that is a copy of this list.
  860. /// </summary>
  861. /// <param name="allocator">The allocator to use.</param>
  862. /// <returns>An array that is a copy of this list.</returns>
  863. public NativeArray<T> ToNativeArray(AllocatorManager.AllocatorHandle allocator)
  864. {
  865. unsafe
  866. {
  867. var copy = CollectionHelper.CreateNativeArray<T>(Length, allocator, NativeArrayOptions.UninitializedMemory);
  868. UnsafeUtility.MemCpy(copy.GetUnsafePtr(), Buffer, LengthInBytes);
  869. return copy;
  870. }
  871. }
  872. <#
  873. foreach(var OTHERBYTES in SIZES)
  874. {
  875. var OTHER_BUFFER_BYTES = OTHERBYTES;
  876. var OTHERTYPENAME = String.Format("FixedList{0}Bytes", OTHERBYTES);
  877. #>
  878. /// <summary>
  879. /// Returns true if two lists are equal.
  880. /// </summary>
  881. /// <remarks>Two lists are equal if their length and bytes are equal.</remarks>
  882. /// <param name="a">The first list to compare for equality.</param>
  883. /// <param name="b">The second list to compare for equality.</param>
  884. /// <returns>True if the two lists are equal.</returns>
  885. public static bool operator ==(in <#=TYPENAME#><T> a, in <#=OTHERTYPENAME#><T> b)
  886. {
  887. unsafe
  888. {
  889. if(a.length != b.length)
  890. return false;
  891. return UnsafeUtility.MemCmp(a.Buffer, b.Buffer, a.LengthInBytes) == 0;
  892. }
  893. }
  894. /// <summary>
  895. /// Returns true if two lists are unequal.
  896. /// </summary>
  897. /// <remarks>Two lists are equal if their length and bytes are equal.</remarks>
  898. /// <param name="a">The first list to compare for inequality.</param>
  899. /// <param name="b">The second list to compare for inequality.</param>
  900. /// <returns>True if the two lists are unequal.</returns>
  901. public static bool operator !=(in <#=TYPENAME#><T> a, in <#=OTHERTYPENAME#><T> b)
  902. {
  903. return !(a == b);
  904. }
  905. /// <summary>
  906. /// Returns a number denoting whether this list should be placed before or after another list in a sort.
  907. /// </summary>
  908. /// <param name="other">A list to to compare with.</param>
  909. /// <returns>An integer denoting the respective sort position of the list relative to the other:
  910. ///
  911. /// 0 denotes that both lists should have the same position in a sort.
  912. /// -1 denotes that this list should precede the other list in a sort.
  913. /// +1 denotes that this list should follow the other list in a sort.
  914. /// </returns>
  915. public int CompareTo(<#=OTHERTYPENAME#><T> other)
  916. {
  917. unsafe
  918. {
  919. byte* a = buffer;
  920. byte* b = other.buffer;
  921. var aa = a + FixedList.PaddingBytes<T>();
  922. var bb = b + FixedList.PaddingBytes<T>();
  923. var mini = math.min(Length, other.Length);
  924. for(var i = 0; i < mini; ++i)
  925. {
  926. var j = UnsafeUtility.MemCmp(aa + sizeof(T) * i, bb + sizeof(T) * i, sizeof(T));
  927. if(j != 0)
  928. return j;
  929. }
  930. return Length.CompareTo(other.Length);
  931. }
  932. }
  933. /// <summary>
  934. /// Returns true if this list and another list are equal.
  935. /// </summary>
  936. /// <remarks>Two lists are equal if their length and bytes are equal.</remarks>
  937. /// <param name="other">The list to compare for equality.</param>
  938. /// <returns>True if the two lists are equal.</returns>
  939. public bool Equals(<#=OTHERTYPENAME#><T> other)
  940. {
  941. return CompareTo(other) == 0;
  942. }
  943. <#
  944. if(BYTES != OTHERBYTES)
  945. {
  946. #>
  947. /// <summary>
  948. /// Initializes and returns an instance of <#=TYPENAME#> with content copied from another list.
  949. /// </summary>
  950. /// <param name="other">The list to copy.</param>
  951. /// <exception cref="IndexOutOfRangeException">Throws if the other list's length exceeds the capacity of <#=TYPENAME#>&lt;T&gt;.</exception>
  952. public <#=TYPENAME#>(in <#=OTHERTYPENAME#><T> other)
  953. {
  954. this = default;
  955. var error = Initialize(other);
  956. if(error != 0)
  957. FixedList.CheckResize<FixedBytes<#=BUFFER_BYTES#>Align8,T>(other.Length);
  958. }
  959. /// <summary>
  960. /// Initializes an instance of <#=TYPENAME#> with content copied from another list.
  961. /// </summary>
  962. /// <param name="other">The list to copy.</param>
  963. /// <returns>zero on success, or non-zero on error.</returns>
  964. internal int Initialize(in <#=OTHERTYPENAME#><T> other)
  965. {
  966. if(other.Length > Capacity)
  967. return (int)CopyError.Truncation;
  968. length = other.length;
  969. unsafe
  970. {
  971. UnsafeUtility.MemCpy(Buffer, other.Buffer, LengthInBytes);
  972. }
  973. return 0;
  974. }
  975. /// <summary>
  976. /// Returns a new list that is a copy of another list.
  977. /// </summary>
  978. /// <param name="other">The list to copy.</param>
  979. /// <returns>A new list that is a copy of the other.</returns>
  980. /// <exception cref="IndexOutOfRangeException">Throws if the other list's length exceeds the capacity of <#=TYPENAME#>&lt;T&gt;.</exception>
  981. public static implicit operator <#=TYPENAME#><T>(in <#=OTHERTYPENAME#><T> other)
  982. {
  983. return new <#=TYPENAME#><T>(other);
  984. }
  985. <#
  986. }
  987. }
  988. #>
  989. /// <summary>
  990. /// Returns true if the list is equal to an object.
  991. /// </summary>
  992. /// <remarks>Two lists are equal if their length and bytes are equal.
  993. ///
  994. /// A FixedList*N*&lt;T&gt; can only be equal to another FixedList*N*&lt;T&gt; with the same *N* and T.
  995. /// </remarks>
  996. /// <param name="obj">An object to compare for equality.</param>
  997. /// <returns>True if the list is equal to the object.</returns>
  998. [ExcludeFromBurstCompatTesting("Takes managed object")]
  999. public override bool Equals(object obj)
  1000. {
  1001. <#
  1002. foreach(var OTHERBYTES in SIZES)
  1003. {
  1004. var OTHERTYPENAME = String.Format("FixedList{0}Bytes", OTHERBYTES);
  1005. WriteLine(" if(obj is {0}<T> a{0}) return Equals(a{0});", OTHERTYPENAME);
  1006. }
  1007. #>
  1008. return false;
  1009. }
  1010. /// <summary>
  1011. /// An enumerator over the elements of a <#=TYPENAME#>&lt;T&gt;.
  1012. /// </summary>
  1013. /// <remarks>
  1014. /// In an enumerator's initial state, `Current` cannot be read. The first <see cref="MoveNext"/> call advances the enumerator to the first element.
  1015. /// </remarks>
  1016. public struct Enumerator : IEnumerator<T>
  1017. {
  1018. <#=TYPENAME#><T> m_List;
  1019. int m_Index;
  1020. /// <summary>
  1021. /// Initializes and returns an instance of <#=TYPENAME#>&lt;T&gt;.
  1022. /// </summary>
  1023. /// <param name="list">The list for which to create an enumerator.</param>
  1024. public Enumerator(ref <#=TYPENAME#><T> list)
  1025. {
  1026. m_List = list;
  1027. m_Index = -1;
  1028. }
  1029. /// <summary>
  1030. /// Does nothing.
  1031. /// </summary>
  1032. public void Dispose()
  1033. {
  1034. }
  1035. /// <summary>
  1036. /// Advances the enumerator to the next element.
  1037. /// </summary>
  1038. /// <returns>True if <see cref="Current"/> is valid to read after the call.</returns>
  1039. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1040. public bool MoveNext()
  1041. {
  1042. m_Index++;
  1043. return m_Index < m_List.Length;
  1044. }
  1045. /// <summary>
  1046. /// Resets the enumerator to its initial state.
  1047. /// </summary>
  1048. public void Reset()
  1049. {
  1050. m_Index = -1;
  1051. }
  1052. /// <summary>
  1053. /// The current element.
  1054. /// </summary>
  1055. /// <value>The current element.</value>
  1056. public T Current
  1057. {
  1058. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1059. get => m_List[m_Index]; // Let <#=TYPENAME#><T> indexer check for out of range.
  1060. }
  1061. object IEnumerator.Current => Current;
  1062. }
  1063. /// <summary>
  1064. /// Returns an enumerator for iterating over the elements of this list.
  1065. /// </summary>
  1066. /// <returns>An enumerator for iterating over the elements of this list.</returns>
  1067. public Enumerator GetEnumerator()
  1068. {
  1069. return new Enumerator(ref this);
  1070. }
  1071. /// <summary>
  1072. /// This method is not implemented. Use <see cref="GetEnumerator"/> instead.
  1073. /// </summary>
  1074. /// <returns>Nothing because it always throws <see cref="NotImplementedException"/>.</returns>
  1075. /// <exception cref="NotImplementedException">Method is not implemented.</exception>
  1076. IEnumerator IEnumerable.GetEnumerator()
  1077. {
  1078. throw new NotImplementedException();
  1079. }
  1080. /// <summary>
  1081. /// This method is not implemented. Use <see cref="GetEnumerator"/> instead.
  1082. /// </summary>
  1083. /// <returns>Nothing because it always throws <see cref="NotImplementedException"/>.</returns>
  1084. /// <exception cref="NotImplementedException">Method is not implemented.</exception>
  1085. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  1086. {
  1087. throw new NotImplementedException();
  1088. }
  1089. }
  1090. /// <summary>
  1091. /// Provides extension methods for <#=TYPENAME#>.
  1092. /// </summary>
  1093. [GenerateTestsForBurstCompatibility]
  1094. public unsafe static class <#=TYPENAME#>Extensions
  1095. {
  1096. /// <summary>
  1097. /// Finds the index of the first occurrence of a particular value in this list.
  1098. /// </summary>
  1099. /// <typeparam name="T">The type of elements in this list.</typeparam>
  1100. /// <typeparam name="U">The value type.</typeparam>
  1101. /// <param name="list">The list to search.</param>
  1102. /// <param name="value">The value to locate.</param>
  1103. /// <returns>The index of the first occurrence of the value. Returns -1 if no occurrence is found.</returns>
  1104. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  1105. public static int IndexOf<T, U>(this ref <#=TYPENAME#><T> list, U value) where T : unmanaged, IEquatable<U>
  1106. {
  1107. return NativeArrayExtensions.IndexOf<T, U>(list.Buffer, list.Length, value);
  1108. }
  1109. /// <summary>
  1110. /// Returns true if a particular value is present in this list.
  1111. /// </summary>
  1112. /// <typeparam name="T">The type of elements in this list.</typeparam>
  1113. /// <typeparam name="U">The value type.</typeparam>
  1114. /// <param name="list">The list to search.</param>
  1115. /// <param name="value">The value to locate.</param>
  1116. /// <returns>True if the value is present in this list.</returns>
  1117. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  1118. public static bool Contains<T, U>(this ref <#=TYPENAME#><T> list, U value) where T : unmanaged, IEquatable<U>
  1119. {
  1120. return list.IndexOf(value) != -1;
  1121. }
  1122. /// <summary>
  1123. /// Removes the first occurrence of a particular value in this list.
  1124. /// </summary>
  1125. /// <remarks>
  1126. /// If a value is removed, all elements after it are shifted down by one, and the list's length is decremented by one.
  1127. ///
  1128. /// If you don't need to preserve the order of the remaining elements, <see cref="Unity.Collections.<#=TYPENAME#>Extensions.RemoveSwapBack{T, U}"/> is a cheaper alternative.
  1129. /// </remarks>
  1130. /// <typeparam name="T">The type of elements in this list.</typeparam>
  1131. /// <typeparam name="U">The value type.</typeparam>
  1132. /// <param name="list">The list to search.</param>
  1133. /// <param name="value">The value to locate and remove.</param>
  1134. /// <returns>True if the value was found and removed.</returns>
  1135. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  1136. public static bool Remove<T, U>(this ref <#=TYPENAME#><T> list, U value) where T : unmanaged, IEquatable<U>
  1137. {
  1138. int index = list.IndexOf(value);
  1139. if (index < 0)
  1140. {
  1141. return false;
  1142. }
  1143. list.RemoveAt(index);
  1144. return true;
  1145. }
  1146. /// <summary>
  1147. /// Removes the first occurrence of a particular value in this list.
  1148. /// </summary>
  1149. /// <remarks>
  1150. /// If a value is removed, the last element of the list is copied to overwrite the removed value, and the list's length is decremented by one.
  1151. ///
  1152. /// This is cheaper than <see cref="Remove"/>, but the order of the remaining elements is not preserved.
  1153. /// </remarks>
  1154. /// <typeparam name="T">The type of elements in this list.</typeparam>
  1155. /// <typeparam name="U">The value type.</typeparam>
  1156. /// <param name="list">The list to search.</param>
  1157. /// <param name="value">The value to locate and remove.</param>
  1158. /// <returns>Returns true if the item is removed.</returns>
  1159. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
  1160. public static bool RemoveSwapBack<T, U>(this ref <#=TYPENAME#><T> list, U value) where T : unmanaged, IEquatable<U>
  1161. {
  1162. var index = list.IndexOf(value);
  1163. if (index == -1)
  1164. {
  1165. return false;
  1166. }
  1167. list.RemoveAtSwapBack(index);
  1168. return true;
  1169. }
  1170. }
  1171. sealed class <#=TYPENAME#>DebugView<T> where T : unmanaged
  1172. {
  1173. <#=TYPENAME#><T> m_List;
  1174. public <#=TYPENAME#>DebugView(<#=TYPENAME#><T> list)
  1175. {
  1176. m_List = list;
  1177. }
  1178. public T[] Items => m_List.ToArray();
  1179. }
  1180. <#
  1181. }
  1182. #>
  1183. <#
  1184. var TYPES = new string[]{"byte","int","float"};
  1185. var TYPESIZES = new int[]{1,4,4};
  1186. for(var type = 0; type < 3; ++type)
  1187. for(var size = 0; size < 5; ++size)
  1188. {
  1189. var BYTES = SIZES[size];
  1190. var TYPE = TYPES[type];
  1191. var TYPESIZE = TYPESIZES[type];
  1192. var BUFFER_BYTES = BYTES;
  1193. var TYPENAME = String.Format("FixedList{0}{1}", new CultureInfo("en-US").TextInfo.ToTitleCase(TYPE), BYTES);
  1194. var NEW_TYPENAME = $"FixedList{BYTES}Bytes<{TYPE}>";
  1195. #>
  1196. <#
  1197. }
  1198. #>
  1199. /// <summary>
  1200. /// Provides extension methods for FixedList*N*.
  1201. /// </summary>
  1202. public static class FixedListExtensions
  1203. {
  1204. <#
  1205. for(var size = 0; size < 5; ++size)
  1206. {
  1207. var BYTES = SIZES[size];
  1208. var BUFFER_BYTES = BYTES;
  1209. var TYPENAME = String.Format("FixedList{0}Bytes", BYTES);
  1210. #>
  1211. /// <summary>
  1212. /// Sorts the elements in this list in ascending order.
  1213. /// </summary>
  1214. /// <typeparam name="T">The type of the elements.</typeparam>
  1215. /// <param name="list">The list to sort.</param>
  1216. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
  1217. public static void Sort<T>(this ref <#=TYPENAME#><T> list)
  1218. where T : unmanaged, IComparable<T>
  1219. {
  1220. unsafe
  1221. {
  1222. var c = list.buffer + FixedList.PaddingBytes<T>();
  1223. NativeSortExtension.Sort((T*)c, list.Length);
  1224. }
  1225. }
  1226. /// <summary>
  1227. /// Sorts the elements in this list using a custom comparison.
  1228. /// </summary>
  1229. /// <typeparam name="T">The type of the elements.</typeparam>
  1230. /// <typeparam name="U">The type of the comparer.</typeparam>
  1231. /// <param name="list">The list to sort.</param>
  1232. /// <param name="comp">The comparison function used to determine the relative order of the elements.</param>
  1233. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(NativeSortExtension.DefaultComparer<int>) })]
  1234. public static void Sort<T, U>(this ref <#=TYPENAME#><T> list, U comp)
  1235. where T : unmanaged, IComparable<T>
  1236. where U : IComparer<T>
  1237. {
  1238. unsafe
  1239. {
  1240. var c = list.buffer + FixedList.PaddingBytes<T>();
  1241. NativeSortExtension.Sort((T*)c, list.Length, comp);
  1242. }
  1243. }
  1244. <#
  1245. }
  1246. #>
  1247. }
  1248. }