12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Runtime.InteropServices;
- using System.Threading;
- using Unity.Burst;
- using Unity.Jobs;
- using Unity.Mathematics;
-
- namespace Unity.Collections.LowLevel.Unsafe
- {
-
- [BurstCompile]
- internal unsafe struct UnsafeDisposeJob : IJob
- {
- [NativeDisableUnsafePtrRestriction]
- public void* Ptr;
- public AllocatorManager.AllocatorHandle Allocator;
-
- public void Execute()
- {
- AllocatorManager.Free(Allocator, Ptr);
- }
- }
-
- internal unsafe struct UntypedUnsafeList
- {
- #pragma warning disable 169
- [NativeDisableUnsafePtrRestriction]
- public void* Ptr;
- public int m_length;
- public int m_capacity;
- public AllocatorManager.AllocatorHandle Allocator;
- internal int obsolete_length;
- internal int obsolete_capacity;
- #pragma warning restore 169
- }
-
- /// <summary>
- /// An unmanaged, resizable list.
- /// </summary>
- /// <typeparam name="T">The type of the elements.</typeparam>
- [DebuggerDisplay("Length = {Length}, Capacity = {Capacity}, IsCreated = {IsCreated}, IsEmpty = {IsEmpty}")]
- [DebuggerTypeProxy(typeof(UnsafeListTDebugView<>))]
- [StructLayout(LayoutKind.Sequential)]
- [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
- public unsafe struct UnsafeList<T>
- : INativeDisposable
- , INativeList<T>
- , IEnumerable<T> // Used by collection initializers.
- where T : unmanaged
- {
- // <WARNING>
- // 'Header' of this struct must binary match 'UntypedUnsafeList' struct
- // Fields must match UntypedUnsafeList structure, please don't reorder and don't insert anything in between first 4 fields
-
- /// <summary>
- /// The internal buffer of this list.
- /// </summary>
- [NativeDisableUnsafePtrRestriction]
- public T* Ptr;
-
- /// <summary>
- /// The number of elements.
- /// </summary>
- public int m_length;
-
- /// <summary>
- /// The number of elements that can fit in the internal buffer.
- /// </summary>
- public int m_capacity;
-
- /// <summary>
- /// The allocator used to create the internal buffer.
- /// </summary>
- public AllocatorManager.AllocatorHandle Allocator;
-
- [Obsolete("Use Length property (UnityUpgradable) -> Length", true)]
- public int length;
-
- [Obsolete("Use Capacity property (UnityUpgradable) -> Capacity", true)]
- public int capacity;
-
- /// <summary>
- /// The number of elements.
- /// </summary>
- /// <value>The number of elements.</value>
- public int Length
- {
- get
- {
- return CollectionHelper.AssumePositive(m_length);
- }
-
- set
- {
- if (value > Capacity)
- {
- Resize(value);
- }
- else
- {
- m_length = value;
- }
- }
- }
-
- /// <summary>
- /// The number of elements that can fit in the internal buffer.
- /// </summary>
- /// <value>The number of elements that can fit in the internal buffer.</value>
- public int Capacity
- {
- get
- {
- return CollectionHelper.AssumePositive(m_capacity);
- }
-
- set
- {
- SetCapacity(value);
- }
- }
-
- /// <summary>
- /// The element at an index.
- /// </summary>
- /// <param name="index">An index.</param>
- /// <value>The element at the index.</value>
- public T this[int index]
- {
- get
- {
- CollectionHelper.CheckIndexInRange(index, Length);
- return Ptr[CollectionHelper.AssumePositive(index)];
- }
-
- set
- {
- CollectionHelper.CheckIndexInRange(index, Length);
- Ptr[CollectionHelper.AssumePositive(index)] = value;
- }
- }
-
- /// <summary>
- /// Returns a reference to the element at a given index.
- /// </summary>
- /// <param name="index">The index to access. Must be in the range of [0..Length).</param>
- /// <returns>A reference to the element at the index.</returns>
- public ref T ElementAt(int index)
- {
- CollectionHelper.CheckIndexInRange(index, Length);
- return ref Ptr[CollectionHelper.AssumePositive(index)];
- }
-
- /// <summary>
- /// Initializes and returns an instance of UnsafeList.
- /// </summary>
- /// <param name="ptr">An existing byte array to set as the internal buffer.</param>
- /// <param name="length">The length.</param>
- public UnsafeList(T* ptr, int length) : this()
- {
- Ptr = ptr;
- this.m_length = length;
- m_capacity = 0;
- Allocator = AllocatorManager.None;
- }
-
- /// <summary>
- /// Initializes and returns an instance of UnsafeList.
- /// </summary>
- /// <param name="initialCapacity">The initial capacity of the list.</param>
- /// <param name="allocator">The allocator to use.</param>
- /// <param name="options">Whether newly allocated bytes should be zeroed out.</param>
- public UnsafeList(int initialCapacity, AllocatorManager.AllocatorHandle allocator, NativeArrayOptions options = NativeArrayOptions.UninitializedMemory) : this()
- {
- Ptr = null;
- m_length = 0;
- m_capacity = 0;
- Allocator = allocator;
-
- if (initialCapacity != 0)
- {
- SetCapacity(initialCapacity);
- }
-
- if (options == NativeArrayOptions.ClearMemory && Ptr != null)
- {
- var sizeOf = sizeof(T);
- UnsafeUtility.MemClear(Ptr, Capacity * sizeOf);
- }
- }
-
- [BurstCompatible(GenericTypeArguments = new [] { typeof(AllocatorManager.AllocatorHandle) })]
- internal void Initialize<U>(int initialCapacity, ref U allocator, NativeArrayOptions options = NativeArrayOptions.UninitializedMemory) where U : unmanaged, AllocatorManager.IAllocator
- {
- Ptr = null;
- m_length = 0;
- m_capacity = 0;
- Allocator = AllocatorManager.None;
- Initialize(initialCapacity, ref allocator, options);
- }
-
- [BurstCompatible(GenericTypeArguments = new [] { typeof(AllocatorManager.AllocatorHandle) })]
- internal static UnsafeList<T> New<U>(int initialCapacity, ref U allocator, NativeArrayOptions options = NativeArrayOptions.UninitializedMemory) where U : unmanaged, AllocatorManager.IAllocator
- {
- UnsafeList<T> instance = default;
- instance.Initialize(initialCapacity, ref allocator, options);
- return instance;
- }
-
- [BurstCompatible(GenericTypeArguments = new[] { typeof(AllocatorManager.AllocatorHandle) })]
- internal static UnsafeList<T>* Create<U>(int initialCapacity, ref U allocator, NativeArrayOptions options = NativeArrayOptions.UninitializedMemory) where U : unmanaged, AllocatorManager.IAllocator
- {
- UnsafeList<T>* listData = allocator.Allocate(default(UnsafeList<T>), 1);
- UnsafeUtility.MemClear(listData, sizeof(UnsafeList<T>));
-
- listData->Allocator = allocator.Handle;
-
- if (initialCapacity != 0)
- {
- listData->SetCapacity(ref allocator, initialCapacity);
- }
-
- if (options == NativeArrayOptions.ClearMemory
- && listData->Ptr != null)
- {
- var sizeOf = sizeof(T);
- UnsafeUtility.MemClear(listData->Ptr, listData->Capacity * sizeOf);
- }
-
- return listData;
- }
-
- [BurstCompatible(GenericTypeArguments = new[] { typeof(AllocatorManager.AllocatorHandle) })]
- internal static void Destroy<U>(UnsafeList<T>* listData, ref U allocator) where U : unmanaged, AllocatorManager.IAllocator
- {
- CheckNull(listData);
- listData->Dispose(ref allocator);
- allocator.Free(listData, sizeof(UnsafeList<T>), UnsafeUtility.AlignOf<UnsafeList<T>>(), 1);
- }
-
- /// <summary>
- /// Returns a new list.
- /// </summary>
- /// <param name="initialCapacity">The initial capacity of the list.</param>
- /// <param name="allocator">The allocator to use.</param>
- /// <param name="options">Whether newly allocated bytes should be zeroed out.</param>
- /// <returns>A pointer to the new list.</returns>
- public static UnsafeList<T>* Create(int initialCapacity, AllocatorManager.AllocatorHandle allocator, NativeArrayOptions options = NativeArrayOptions.UninitializedMemory)
- {
- UnsafeList<T>* listData = AllocatorManager.Allocate<UnsafeList<T>>(allocator);
- *listData = new UnsafeList<T>(initialCapacity, allocator, options);
-
- return listData;
- }
-
- /// <summary>
- /// Destroys the list.
- /// </summary>
- /// <param name="listData">The list to destroy.</param>
- public static void Destroy(UnsafeList<T>* listData)
- {
- CheckNull(listData);
- var allocator = listData->Allocator;
- listData->Dispose();
- AllocatorManager.Free(allocator, listData);
- }
-
- /// <summary>
- /// Whether the list is empty.
- /// </summary>
- /// <value>True if the list is empty or the list has not been constructed.</value>
- public bool IsEmpty => !IsCreated || m_length == 0;
-
- /// <summary>
- /// Whether this list has been allocated (and not yet deallocated).
- /// </summary>
- /// <value>True if this list has been allocated (and not yet deallocated).</value>
- public bool IsCreated => Ptr != null;
-
- [BurstCompatible(GenericTypeArguments = new[] { typeof(AllocatorManager.AllocatorHandle) })]
- internal void Dispose<U>(ref U allocator) where U : unmanaged, AllocatorManager.IAllocator
- {
- allocator.Free(Ptr, m_length);
- Ptr = null;
- m_length = 0;
- m_capacity = 0;
- }
-
- /// <summary>
- /// Releases all resources (memory).
- /// </summary>
- public void Dispose()
- {
- if (CollectionHelper.ShouldDeallocate(Allocator))
- {
- AllocatorManager.Free(Allocator, Ptr);
- Allocator = AllocatorManager.Invalid;
- }
-
- Ptr = null;
- m_length = 0;
- m_capacity = 0;
- }
-
- /// <summary>
- /// Creates and schedules a job that frees the memory of this list.
- /// </summary>
- /// <param name="inputDeps">The dependency for the new job.</param>
- /// <returns>The handle of the new job. The job depends upon `inputDeps` and frees the memory of this list.</returns>
- [NotBurstCompatible /* This is not burst compatible because of IJob's use of a static IntPtr. Should switch to IJobBurstSchedulable in the future */]
- public JobHandle Dispose(JobHandle inputDeps)
- {
- if (CollectionHelper.ShouldDeallocate(Allocator))
- {
- var jobHandle = new UnsafeDisposeJob { Ptr = Ptr, Allocator = Allocator }.Schedule(inputDeps);
-
- Ptr = null;
- Allocator = AllocatorManager.Invalid;
-
- return jobHandle;
- }
-
- Ptr = null;
-
- return inputDeps;
- }
-
- /// <summary>
- /// Sets the length to 0.
- /// </summary>
- /// <remarks>Does not change the capacity.</remarks>
- public void Clear()
- {
- m_length = 0;
- }
-
- /// <summary>
- /// Sets the length, expanding the capacity if necessary.
- /// </summary>
- /// <param name="length">The new length.</param>
- /// <param name="options">Whether newly allocated bytes should be zeroed out.</param>
- public void Resize(int length, NativeArrayOptions options = NativeArrayOptions.UninitializedMemory)
- {
- var oldLength = m_length;
-
- if (length > Capacity)
- {
- SetCapacity(length);
- }
-
- m_length = length;
-
- if (options == NativeArrayOptions.ClearMemory && oldLength < length)
- {
- var num = length - oldLength;
- byte* ptr = (byte*)Ptr;
- var sizeOf = sizeof(T);
- UnsafeUtility.MemClear(ptr + oldLength * sizeOf, num * sizeOf);
- }
- }
-
- void Realloc<U>(ref U allocator, int newCapacity) where U : unmanaged, AllocatorManager.IAllocator
- {
- CollectionHelper.CheckAllocator(Allocator);
- T* newPointer = null;
-
- var alignOf = UnsafeUtility.AlignOf<T>();
- var sizeOf = sizeof(T);
-
- if (newCapacity > 0)
- {
- newPointer = (T*)allocator.Allocate(sizeOf, alignOf, newCapacity);
-
- if (m_capacity > 0)
- {
- var itemsToCopy = math.min(newCapacity, Capacity);
- var bytesToCopy = itemsToCopy * sizeOf;
- UnsafeUtility.MemCpy(newPointer, Ptr, bytesToCopy);
- }
- }
-
- allocator.Free(Ptr, Capacity);
-
- Ptr = newPointer;
- m_capacity = newCapacity;
- m_length = math.min(m_length, newCapacity);
- }
-
- void Realloc(int capacity)
- {
- Realloc(ref Allocator, capacity);
- }
-
- void SetCapacity<U>(ref U allocator, int capacity) where U : unmanaged, AllocatorManager.IAllocator
- {
- CollectionHelper.CheckCapacityInRange(capacity, Length);
-
- var sizeOf = sizeof(T);
- var newCapacity = math.max(capacity, 64 / sizeOf);
- newCapacity = math.ceilpow2(newCapacity);
-
- if (newCapacity == Capacity)
- {
- return;
- }
-
- Realloc(ref allocator, newCapacity);
- }
-
- /// <summary>
- /// Sets the capacity.
- /// </summary>
- /// <param name="capacity">The new capacity.</param>
- public void SetCapacity(int capacity)
- {
- SetCapacity(ref Allocator, capacity);
- }
-
- /// <summary>
- /// Sets the capacity to match the length.
- /// </summary>
- public void TrimExcess()
- {
- if (Capacity != m_length)
- {
- Realloc(m_length);
- }
- }
-
- /// <summary>
- /// Adds an element to the end of this list.
- /// </summary>
- /// <remarks>
- /// Increments the length by 1. Never increases the capacity.
- /// </remarks>
- /// <param name="value">The value to add to the end of the list.</param>
- /// <exception cref="Exception">Thrown if incrementing the length would exceed the capacity.</exception>
- public void AddNoResize(T value)
- {
- CheckNoResizeHasEnoughCapacity(1);
- UnsafeUtility.WriteArrayElement(Ptr, m_length, value);
- m_length += 1;
- }
-
- /// <summary>
- /// Copies elements from a buffer to the end of this list.
- /// </summary>
- /// <remarks>
- /// Increments the length by `count`. Never increases the capacity.
- /// </remarks>
- /// <param name="ptr">The buffer to copy from.</param>
- /// <param name="count">The number of elements to copy from the buffer.</param>
- /// <exception cref="Exception">Thrown if the increased length would exceed the capacity.</exception>
- public void AddRangeNoResize(void* ptr, int count)
- {
- CheckNoResizeHasEnoughCapacity(count);
- var sizeOf = sizeof(T);
- void* dst = (byte*)Ptr + m_length * sizeOf;
- UnsafeUtility.MemCpy(dst, ptr, count * sizeOf);
- m_length += count;
- }
-
- /// <summary>
- /// Copies the elements of another list to the end of this list.
- /// </summary>
- /// <param name="list">The other list to copy from.</param>
- /// <remarks>
- /// Increments the length by the length of the other list. Never increases the capacity.
- /// </remarks>
- /// <exception cref="Exception">Thrown if the increased length would exceed the capacity.</exception>
- [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
- public void AddRangeNoResize(UnsafeList<T> list)
- {
- AddRangeNoResize(list.Ptr, CollectionHelper.AssumePositive(list.m_length));
- }
-
- /// <summary>
- /// Adds an element to the end of the list.
- /// </summary>
- /// <param name="value">The value to add to the end of this list.</param>
- /// <remarks>
- /// Increments the length by 1. Increases the capacity if necessary.
- /// </remarks>
- public void Add(in T value)
- {
- var idx = m_length;
-
- if (m_length + 1 > Capacity)
- {
- Resize(idx + 1);
- }
- else
- {
- m_length += 1;
- }
-
- UnsafeUtility.WriteArrayElement(Ptr, idx, value);
- }
-
- /// <summary>
- /// Copies the elements of a buffer to the end of this list.
- /// </summary>
- /// <param name="ptr">The buffer to copy from.</param>
- /// <param name="count">The number of elements to copy from the buffer.</param>
- /// <remarks>
- /// Increments the length by `count`. Increases the capacity if necessary.
- /// </remarks>
- public void AddRange(void* ptr, int count)
- {
- var idx = m_length;
-
- if (m_length + count > Capacity)
- {
- Resize(m_length + count);
- }
- else
- {
- m_length += count;
- }
-
- var sizeOf = sizeof(T);
- void* dst = (byte*)Ptr + idx * sizeOf;
- UnsafeUtility.MemCpy(dst, ptr, count * sizeOf);
- }
-
- /// <summary>
- /// Copies the elements of another list to the end of the list.
- /// </summary>
- /// <param name="list">The list to copy from.</param>
- /// <remarks>
- /// The length is increased by the length of the other list. Increases the capacity if necessary.
- /// </remarks>
- [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
- public void AddRange(UnsafeList<T> list)
- {
- AddRange(list.Ptr, list.Length);
- }
-
- /// <summary>
- /// Shifts elements toward the end of this list, increasing its length.
- /// </summary>
- /// <remarks>
- /// Right-shifts elements in the list so as to create 'free' slots at the beginning or in the middle.
- ///
- /// The length is increased by `end - begin`. If necessary, the capacity will be increased accordingly.
- ///
- /// If `end` equals `begin`, the method does nothing.
- ///
- /// 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.
- ///
- /// The indexes `begin` up to `end` are not cleared: they will contain whatever values they held prior.
- /// </remarks>
- /// <param name="begin">The index of the first element that will be shifted up.</param>
- /// <param name="end">The index where the first shifted element will end up.</param>
- /// <exception cref="ArgumentException">Thrown if `end < begin`.</exception>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `begin` or `end` are out of bounds.</exception>
- public void InsertRangeWithBeginEnd(int begin, int end)
- {
- CheckBeginEnd(begin, end);
-
- int items = end - begin;
- if (items < 1)
- {
- return;
- }
-
- var oldLength = m_length;
-
- if (m_length + items > Capacity)
- {
- Resize(m_length + items);
- }
- else
- {
- m_length += items;
- }
-
- var itemsToCopy = oldLength - begin;
-
- if (itemsToCopy < 1)
- {
- return;
- }
-
- var sizeOf = sizeof(T);
- var bytesToCopy = itemsToCopy * sizeOf;
- unsafe
- {
- byte* ptr = (byte*)Ptr;
- byte* dest = ptr + end * sizeOf;
- byte* src = ptr + begin * sizeOf;
- UnsafeUtility.MemMove(dest, src, bytesToCopy);
- }
- }
-
- /// <summary>
- /// Copies the last element of this list to the specified index. Decrements the length by 1.
- /// </summary>
- /// <remarks>Useful as a cheap way to remove an element from this list when you don't care about preserving order.</remarks>
- /// <param name="index">The index to overwrite with the last element.</param>
- /// <exception cref="IndexOutOfRangeException">Thrown if `index` is out of bounds.</exception>
- public void RemoveAtSwapBack(int index)
- {
- RemoveRangeSwapBack(index, 1);
- }
-
- /// <summary>
- /// Copies the last *N* elements of this list to a range in this list. Decrements the length by *N*.
- /// </summary>
- /// <remarks>
- /// Copies the last `count` elements to the indexes `index` up to `index + count`.
- ///
- /// Useful as a cheap way to remove elements from a list when you don't care about preserving order.
- /// </remarks>
- /// <param name="index">The index of the first element to overwrite.</param>
- /// <param name="count">The number of elements to copy and remove.</param>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds, `count` is negative,
- /// or `index + count` exceeds the length.</exception>
- public void RemoveRangeSwapBack(int index, int count)
- {
- CheckIndexCount(index, count);
-
- if (count > 0)
- {
- int copyFrom = math.max(m_length - count, index + count);
- var sizeOf = sizeof(T);
- void* dst = (byte*)Ptr + index * sizeOf;
- void* src = (byte*)Ptr + copyFrom * sizeOf;
- UnsafeUtility.MemCpy(dst, src, (m_length - copyFrom) * sizeOf);
- m_length -= count;
- }
- }
-
- /// <summary>
- /// Copies the last *N* elements of this list to a range in this list. Decrements the length by *N*.
- /// </summary>
- /// <remarks>
- /// Copies the last `end - begin` elements to the indexes `begin` up to `end`.
- ///
- /// Useful as a cheap way to remove elements from a list when you don't care about preserving order.
- ///
- /// Does nothing if `end - begin` is less than 1.
- /// </remarks>
- /// <param name="begin">The index of the first element to overwrite.</param>
- /// <param name="end">The index one greater than the last element to overwrite.</param>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `begin` or `end` are out of bounds.</exception>
- [Obsolete("RemoveRangeSwapBackWithBeginEnd(begin, end) is deprecated, use RemoveRangeSwapBack(index, count) instead. (RemovedAfter 2021-06-02)", false)]
- public void RemoveRangeSwapBackWithBeginEnd(int begin, int end)
- {
- CheckBeginEnd(begin, end);
-
- int itemsToRemove = end - begin;
- if (itemsToRemove > 0)
- {
- int copyFrom = math.max(m_length - itemsToRemove, end);
- var sizeOf = sizeof(T);
- void* dst = (byte*)Ptr + begin * sizeOf;
- void* src = (byte*)Ptr + copyFrom * sizeOf;
- UnsafeUtility.MemCpy(dst, src, (m_length - copyFrom) * sizeOf);
- m_length -= itemsToRemove;
- }
- }
-
- /// <summary>
- /// Removes the element at an index, shifting everything above it down by one. Decrements the length by 1.
- /// </summary>
- /// <param name="index">The index of the element to remove.</param>
- /// <remarks>
- /// If you don't care about preserving the order of the elements, <see cref="RemoveAtSwapBack(int)"/> is a more efficient way to remove elements.
- /// </remarks>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds.</exception>
- public void RemoveAt(int index)
- {
- RemoveRange(index, 1);
- }
-
- /// <summary>
- /// Removes *N* elements in a range, shifting everything above the range down by *N*. Decrements the length by *N*.
- /// </summary>
- /// <param name="index">The index of the first element to remove.</param>
- /// <param name="count">The number of elements to remove.</param>
- /// <remarks>
- /// If you don't care about preserving the order of the elements, <see cref="RemoveRangeSwapBackWithBeginEnd"/>
- /// is a more efficient way to remove elements.
- /// </remarks>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds, `count` is negative,
- /// or `index + count` exceeds the length.</exception>
- public void RemoveRange(int index, int count)
- {
- CheckIndexCount(index, count);
-
- if (count > 0)
- {
- int copyFrom = math.min(index + count, m_length);
- var sizeOf = sizeof(T);
- void* dst = (byte*)Ptr + index * sizeOf;
- void* src = (byte*)Ptr + copyFrom * sizeOf;
- UnsafeUtility.MemCpy(dst, src, (m_length - copyFrom) * sizeOf);
- m_length -= count;
- }
- }
-
- /// <summary>
- /// Removes *N* elements in a range, shifting everything above it down by *N*. Decrements the length by *N*.
- /// </summary>
- /// <param name="begin">The index of the first element to remove.</param>
- /// <param name="end">The index one greater than the last element to remove.</param>
- /// <remarks>
- /// If you don't care about preserving the order of the elements, <see cref="RemoveRangeSwapBackWithBeginEnd"/> is a more efficient way to remove elements.
- /// </remarks>
- /// <exception cref="ArgumentException">Thrown if `end < begin`.</exception>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `begin` or `end` are out of bounds.</exception>
- [Obsolete("RemoveRangeWithBeginEnd(begin, end) is deprecated, use RemoveRange(index, count) instead. (RemovedAfter 2021-06-02)", false)]
- public void RemoveRangeWithBeginEnd(int begin, int end)
- {
- CheckBeginEnd(begin, end);
-
- int itemsToRemove = end - begin;
- if (itemsToRemove > 0)
- {
- int copyFrom = math.min(begin + itemsToRemove, m_length);
- var sizeOf = sizeof(T);
- void* dst = (byte*)Ptr + begin * sizeOf;
- void* src = (byte*)Ptr + copyFrom * sizeOf;
- UnsafeUtility.MemCpy(dst, src, (m_length - copyFrom) * sizeOf);
- m_length -= itemsToRemove;
- }
- }
-
- /// <summary>
- /// Returns a parallel reader of this list.
- /// </summary>
- /// <returns>A parallel reader of this list.</returns>
- public ParallelReader AsParallelReader()
- {
- return new ParallelReader(Ptr, Length);
- }
-
- /// <summary>
- /// A parallel reader for an UnsafeList<T>.
- /// </summary>
- /// <remarks>
- /// Use <see cref="AsParallelReader"/> to create a parallel reader for a list.
- /// </remarks>
- [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
- public unsafe struct ParallelReader
- {
- /// <summary>
- /// The internal buffer of the list.
- /// </summary>
- [NativeDisableUnsafePtrRestriction]
- public readonly T* Ptr;
-
- /// <summary>
- /// The number of elements.
- /// </summary>
- public readonly int Length;
-
- internal ParallelReader(T* ptr, int length)
- {
- Ptr = ptr;
- Length = length;
- }
- }
-
- /// <summary>
- /// Returns a parallel writer of this list.
- /// </summary>
- /// <returns>A parallel writer of this list.</returns>
- public ParallelWriter AsParallelWriter()
- {
- return new ParallelWriter((UnsafeList<T>*)UnsafeUtility.AddressOf(ref this));
- }
-
- /// <summary>
- /// A parallel writer for an UnsafeList<T>.
- /// </summary>
- /// <remarks>
- /// Use <see cref="AsParallelWriter"/> to create a parallel writer for a list.
- /// </remarks>
- [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
- public unsafe struct ParallelWriter
- {
- /// <summary>
- /// The data of the list.
- /// </summary>
- public readonly void* Ptr => ListData->Ptr;
-
- /// <summary>
- /// The UnsafeList to write to.
- /// </summary>
- [NativeDisableUnsafePtrRestriction]
- public UnsafeList<T>* ListData;
-
- internal unsafe ParallelWriter(UnsafeList<T>* listData)
- {
- ListData = listData;
- }
-
- /// <summary>
- /// Adds an element to the end of the list.
- /// </summary>
- /// <param name="value">The value to add to the end of the list.</param>
- /// <remarks>
- /// Increments the length by 1. Never increases the capacity.
- /// </remarks>
- /// <exception cref="Exception">Thrown if incrementing the length would exceed the capacity.</exception>
- [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
- public void AddNoResize(T value)
- {
- var idx = Interlocked.Increment(ref ListData->m_length) - 1;
- ListData->CheckNoResizeHasEnoughCapacity(idx, 1);
- UnsafeUtility.WriteArrayElement(ListData->Ptr, idx, value);
- }
-
- /// <summary>
- /// Copies elements from a buffer to the end of the list.
- /// </summary>
- /// <param name="ptr">The buffer to copy from.</param>
- /// <param name="count">The number of elements to copy from the buffer.</param>
- /// <remarks>
- /// Increments the length by `count`. Never increases the capacity.
- /// </remarks>
- /// <exception cref="Exception">Thrown if the increased length would exceed the capacity.</exception>
- [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
- public void AddRangeNoResize(void* ptr, int count)
- {
- var idx = Interlocked.Add(ref ListData->m_length, count) - count;
- ListData->CheckNoResizeHasEnoughCapacity(idx, count);
- void* dst = (byte*)ListData->Ptr + idx * sizeof(T);
- UnsafeUtility.MemCpy(dst, ptr, count * sizeof(T));
- }
-
- /// <summary>
- /// Copies the elements of another list to the end of this list.
- /// </summary>
- /// <param name="list">The other list to copy from.</param>
- /// <remarks>
- /// Increments the length by the length of the other list. Never increases the capacity.
- /// </remarks>
- /// <exception cref="Exception">Thrown if the increased length would exceed the capacity.</exception>
- [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
- public void AddRangeNoResize(UnsafeList<T> list)
- {
- AddRangeNoResize(list.Ptr, list.Length);
- }
- }
-
- /// <summary>
- /// Overwrites the elements of this list with the elements of an equal-length array.
- /// </summary>
- /// <param name="array">An array to copy into this list.</param>
- public void CopyFrom(UnsafeList<T> array)
- {
- Resize(array.Length);
- UnsafeUtility.MemCpy(Ptr, array.Ptr, UnsafeUtility.SizeOf<T>() * Length);
- }
-
-
- /// <summary>
- /// Returns an enumerator over the elements of the list.
- /// </summary>
- /// <returns>An enumerator over the elements of the list.</returns>
- public Enumerator GetEnumerator()
- {
- return new Enumerator { m_Ptr = Ptr, m_Length = Length, m_Index = -1 };
- }
-
- /// <summary>
- /// This method is not implemented. Use <see cref="GetEnumerator"/> instead.
- /// </summary>
- /// <returns>Throws NotImplementedException.</returns>
- /// <exception cref="NotImplementedException">Method is not implemented.</exception>
- IEnumerator IEnumerable.GetEnumerator()
- {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// This method is not implemented. Use <see cref="GetEnumerator"/> instead.
- /// </summary>
- /// <returns>Throws NotImplementedException.</returns>
- /// <exception cref="NotImplementedException">Method is not implemented.</exception>
- IEnumerator<T> IEnumerable<T>.GetEnumerator()
- {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// An enumerator over the elements of a list.
- /// </summary>
- /// <remarks>
- /// In an enumerator's initial state, <see cref="Current"/> is invalid.
- /// The first <see cref="MoveNext"/> call advances the enumerator to the first element of the list.
- /// </remarks>
- public struct Enumerator : IEnumerator<T>
- {
- internal T* m_Ptr;
- internal int m_Length;
- internal int m_Index;
-
- /// <summary>
- /// Does nothing.
- /// </summary>
- public void Dispose() { }
-
- /// <summary>
- /// Advances the enumerator to the next element of the list.
- /// </summary>
- /// <remarks>
- /// The first `MoveNext` call advances the enumerator to the first element of the list. Before this call, `Current` is not valid to read.
- /// </remarks>
- /// <returns>True if `Current` is valid to read after the call.</returns>
- public bool MoveNext() => ++m_Index < m_Length;
-
- /// <summary>
- /// Resets the enumerator to its initial state.
- /// </summary>
- public void Reset() => m_Index = -1;
-
- /// <summary>
- /// The current element.
- /// </summary>
- /// <value>The current element.</value>
- public T Current => m_Ptr[m_Index];
-
- object IEnumerator.Current => Current;
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- internal static void CheckNull(void* listData)
- {
- if (listData == null)
- {
- throw new Exception("UnsafeList has yet to be created or has been destroyed!");
- }
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- void CheckIndexCount(int index, int count)
- {
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException($"Value for cound {count} must be positive.");
- }
-
- if (index < 0)
- {
- throw new ArgumentOutOfRangeException($"Value for index {index} must be positive.");
- }
-
- if (index > Length)
- {
- throw new ArgumentOutOfRangeException($"Value for index {index} is out of bounds.");
- }
-
- if (index+count > Length)
- {
- throw new ArgumentOutOfRangeException($"Value for count {count} is out of bounds.");
- }
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- void CheckBeginEnd(int begin, int end)
- {
- if (begin > end)
- {
- throw new ArgumentException($"Value for begin {begin} index must less or equal to end {end}.");
- }
-
- if (begin < 0)
- {
- throw new ArgumentOutOfRangeException($"Value for begin {begin} must be positive.");
- }
-
- if (begin > Length)
- {
- throw new ArgumentOutOfRangeException($"Value for begin {begin} is out of bounds.");
- }
-
- if (end > Length)
- {
- throw new ArgumentOutOfRangeException($"Value for end {end} is out of bounds.");
- }
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- void CheckNoResizeHasEnoughCapacity(int length)
- {
- CheckNoResizeHasEnoughCapacity(length, Length);
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- void CheckNoResizeHasEnoughCapacity(int length, int index)
- {
- if (Capacity < index + length)
- {
- throw new Exception($"AddNoResize assumes that list capacity is sufficient (Capacity {Capacity}, Length {Length}), requested length {length}!");
- }
- }
- }
-
- /// <summary>
- /// Provides extension methods for UnsafeList.
- /// </summary>
- [BurstCompatible]
- public unsafe static class UnsafeListExtensions
- {
- /// <summary>
- /// Finds the index of the first occurrence of a particular value in this list.
- /// </summary>
- /// <typeparam name="T">The type of elements in this list.</typeparam>
- /// <typeparam name="U">The type of value to locate.</typeparam>
- /// <param name="list">This list.</param>
- /// <param name="value">A value to locate.</param>
- /// <returns>The zero-based index of the first occurrence of the value if it is found. Returns -1 if no occurrence is found.</returns>
- [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
- public static int IndexOf<T, U>(this UnsafeList<T> list, U value) where T : unmanaged, IEquatable<U>
- {
- return NativeArrayExtensions.IndexOf<T, U>(list.Ptr, list.Length, value);
- }
-
- /// <summary>
- /// Returns true if a particular value is present in this list.
- /// </summary>
- /// <typeparam name="T">The type of elements in the list.</typeparam>
- /// <typeparam name="U">The type of value to locate.</typeparam>
- /// <param name="list">This list.</param>
- /// <param name="value">The value to locate.</param>
- /// <returns>True if the value is present in this list.</returns>
- [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
- public static bool Contains<T, U>(this UnsafeList<T> list, U value) where T : unmanaged, IEquatable<U>
- {
- return list.IndexOf(value) != -1;
- }
-
- /// <summary>
- /// Finds the index of the first occurrence of a particular value in the list.
- /// </summary>
- /// <typeparam name="T">The type of elements in the list.</typeparam>
- /// <typeparam name="U">The type of value to locate.</typeparam>
- /// <param name="list">This reader of the list.</param>
- /// <param name="value">A value to locate.</param>
- /// <returns>The zero-based index of the first occurrence of the value if it is found. Returns -1 if no occurrence is found.</returns>
- [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
- public static int IndexOf<T, U>(this UnsafeList<T>.ParallelReader list, U value) where T : unmanaged, IEquatable<U>
- {
- return NativeArrayExtensions.IndexOf<T, U>(list.Ptr, list.Length, value);
- }
-
- /// <summary>
- /// Returns true if a particular value is present in the list.
- /// </summary>
- /// <typeparam name="T">The type of elements in the list.</typeparam>
- /// <typeparam name="U">The type of value to locate.</typeparam>
- /// <param name="list">This reader of the list.</param>
- /// <param name="value">The value to locate.</param>
- /// <returns>True if the value is present in the list.</returns>
- [BurstCompatible(GenericTypeArguments = new [] { typeof(int), typeof(int) })]
- public static bool Contains<T, U>(this UnsafeList<T>.ParallelReader list, U value) where T : unmanaged, IEquatable<U>
- {
- return list.IndexOf(value) != -1;
- }
-
-
- /// <summary>
- /// Returns true if this array and another have equal length and content.
- /// </summary>
- /// <typeparam name="T">The type of the source array's elements.</typeparam>
- /// <param name="array">The array to compare for equality.</param>
- /// <param name="other">The other array to compare for equality.</param>
- /// <returns>True if the arrays have equal length and content.</returns>
- [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
- public static bool ArraysEqual<T>(this UnsafeList<T> array, UnsafeList<T> other) where T : unmanaged, IEquatable<T>
- {
- if (array.Length != other.Length)
- return false;
-
- for (int i = 0; i != array.Length; i++)
- {
- if (!array[i].Equals(other[i]))
- return false;
- }
-
- return true;
- }
-
- }
-
- internal sealed class UnsafeListTDebugView<T>
- where T : unmanaged
- {
- UnsafeList<T> Data;
-
- public UnsafeListTDebugView(UnsafeList<T> data)
- {
- Data = data;
- }
-
- public unsafe T[] Items
- {
- get
- {
- T[] result = new T[Data.Length];
-
- for (var i = 0; i < result.Length; ++i)
- {
- result[i] = Data.Ptr[i];
- }
-
- return result;
- }
- }
- }
-
- /// <summary>
- /// An unmanaged, resizable list of pointers.
- /// </summary>
- /// <typeparam name="T">The type of pointer element.</typeparam>
- [DebuggerDisplay("Length = {Length}, Capacity = {Capacity}, IsCreated = {IsCreated}, IsEmpty = {IsEmpty}")]
- [DebuggerTypeProxy(typeof(UnsafePtrListTDebugView<>))]
- [StructLayout(LayoutKind.Sequential)]
- [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
- public unsafe struct UnsafePtrList<T>
- : INativeDisposable
- // IIndexable<T> and INativeList<T> can't be implemented because this[index] and ElementAt return T* instead of T.
- , IEnumerable<IntPtr> // Used by collection initializers.
- where T : unmanaged
- {
- /// <summary>
- /// The internal buffer of this list.
- /// </summary>
- [NativeDisableUnsafePtrRestriction]
- public readonly T** Ptr;
-
- /// <summary>
- /// The number of elements.
- /// </summary>
- public readonly int m_length;
-
- /// <summary>
- /// The number of elements that can fit in the internal buffer.
- /// </summary>
- public readonly int m_capacity;
-
- /// <summary>
- /// The allocator used to create the internal buffer.
- /// </summary>
- public readonly AllocatorManager.AllocatorHandle Allocator;
-
- [Obsolete("Use Length property (UnityUpgradable) -> Length", true)]
- public int length;
-
- [Obsolete("Use Capacity property (UnityUpgradable) -> Capacity", true)]
- public int capacity;
-
- /// <summary>
- /// The number of elements.
- /// </summary>
- /// <value>The number of elements.</value>
- public int Length
- {
- get
- {
- return this.ListData().Length;
- }
-
- set
- {
- this.ListData().Length = value;
- }
- }
-
- /// <summary>
- /// The number of elements that can fit in the internal buffer.
- /// </summary>
- /// <value>The number of elements that can fit in the internal buffer.</value>
- public int Capacity
- {
- get
- {
- return this.ListData().Capacity;
- }
-
- set
- {
- this.ListData().Capacity = value;
- }
- }
-
- /// <summary>
- /// The element at an index.
- /// </summary>
- /// <param name="index">An index.</param>
- /// <value>The element at the index.</value>
- public T* this[int index]
- {
- get
- {
- CollectionHelper.CheckIndexInRange(index, Length);
- return Ptr[CollectionHelper.AssumePositive(index)];
- }
-
- set
- {
- CollectionHelper.CheckIndexInRange(index, Length);
- Ptr[CollectionHelper.AssumePositive(index)] = value;
- }
- }
-
- /// <summary>
- /// Returns a reference to the element at a given index.
- /// </summary>
- /// <param name="index">The index to access. Must be in the range of [0..Length).</param>
- /// <returns>A reference to the element at the index.</returns>
- public ref T* ElementAt(int index)
- {
- CollectionHelper.CheckIndexInRange(index, Length);
- return ref Ptr[CollectionHelper.AssumePositive(index)];
- }
-
- /// <summary>
- /// Initializes and returns an instance of UnsafePtrList.
- /// </summary>
- /// <param name="ptr">An existing pointer array to set as the internal buffer.</param>
- /// <param name="length">The length.</param>
- public unsafe UnsafePtrList(T** ptr, int length) : this()
- {
- Ptr = ptr;
- this.m_length = length;
- this.m_capacity = length;
- Allocator = AllocatorManager.None;
- }
-
- /// <summary>
- /// Initializes and returns an instance of UnsafePtrList.
- /// </summary>
- /// <param name="initialCapacity">The initial capacity of the list.</param>
- /// <param name="allocator">The allocator to use.</param>
- /// <param name="options">Whether newly allocated bytes should be zeroed out.</param>
- public unsafe UnsafePtrList(int initialCapacity, AllocatorManager.AllocatorHandle allocator, NativeArrayOptions options = NativeArrayOptions.UninitializedMemory) : this()
- {
- Ptr = null;
- m_length = 0;
- m_capacity = 0;
- Allocator = AllocatorManager.None;
-
- this.ListData() = new UnsafeList<IntPtr>(initialCapacity, allocator, options);
- }
-
- /// <summary>
- /// Returns a new list of pointers.
- /// </summary>
- /// <param name="ptr">An existing pointer array to set as the internal buffer.</param>
- /// <param name="length">The length.</param>
- /// <returns>A pointer to the new list.</returns>
- public static UnsafePtrList<T>* Create(T** ptr, int length)
- {
- UnsafePtrList<T>* listData = AllocatorManager.Allocate<UnsafePtrList<T>>(AllocatorManager.Persistent);
- *listData = new UnsafePtrList<T>(ptr, length);
- return listData;
- }
-
- /// <summary>
- /// Returns a new list of pointers.
- /// </summary>
- /// <param name="initialCapacity">The initial capacity of the list.</param>
- /// <param name="allocator">The allocator to use.</param>
- /// <param name="options">Whether newly allocated bytes should be zeroed out.</param>
- /// <returns>A pointer to the new list.</returns>
- public static UnsafePtrList<T>* Create(int initialCapacity, AllocatorManager.AllocatorHandle allocator, NativeArrayOptions options = NativeArrayOptions.UninitializedMemory)
- {
- UnsafePtrList<T>* listData = AllocatorManager.Allocate<UnsafePtrList<T>>(allocator);
- *listData = new UnsafePtrList<T>(initialCapacity, allocator, options);
- return listData;
- }
-
- /// <summary>
- /// Destroys the list.
- /// </summary>
- /// <param name="listData">The list to destroy.</param>
- public static void Destroy(UnsafePtrList<T>* listData)
- {
- UnsafeList<IntPtr>.CheckNull(listData);
- var allocator = listData->ListData().Allocator.Value == AllocatorManager.Invalid.Value
- ? AllocatorManager.Persistent
- : listData->ListData().Allocator
- ;
- listData->Dispose();
- AllocatorManager.Free(allocator, listData);
- }
-
- /// <summary>
- /// Whether the list is empty.
- /// </summary>
- /// <value>True if the list is empty or the list has not been constructed.</value>
- public bool IsEmpty => !IsCreated || Length == 0;
-
- /// <summary>
- /// Whether this list has been allocated (and not yet deallocated).
- /// </summary>
- /// <value>True if this list has been allocated (and not yet deallocated).</value>
- public bool IsCreated => Ptr != null;
-
- /// <summary>
- /// Releases all resources (memory).
- /// </summary>
- public void Dispose()
- {
- this.ListData().Dispose();
- }
-
- /// <summary>
- /// Creates and schedules a job that frees the memory of this list.
- /// </summary>
- /// <param name="inputDeps">The dependency for the new job.</param>
- /// <returns>The handle of the new job. The job depends upon `inputDeps` and frees the memory of this list.</returns>
- [NotBurstCompatible /* This is not burst compatible because of IJob's use of a static IntPtr. Should switch to IJobBurstSchedulable in the future */]
- public JobHandle Dispose(JobHandle inputDeps) => this.ListData().Dispose(inputDeps);
-
- /// <summary>
- /// Sets the length to 0.
- /// </summary>
- /// <remarks>Does not change the capacity.</remarks>
- public void Clear() => this.ListData().Clear();
-
- /// <summary>
- /// Sets the length, expanding the capacity if necessary.
- /// </summary>
- /// <param name="length">The new length.</param>
- /// <param name="options">Whether newly allocated bytes should be zeroed out.</param>
- public void Resize(int length, NativeArrayOptions options = NativeArrayOptions.UninitializedMemory) => this.ListData().Resize(length, options);
-
- /// <summary>
- /// Sets the capacity.
- /// </summary>
- /// <param name="capacity">The new capacity.</param>
- public void SetCapacity(int capacity) => this.ListData().SetCapacity(capacity);
-
- /// <summary>
- /// Sets the capacity to match the length.
- /// </summary>
- public void TrimExcess() => this.ListData().TrimExcess();
-
- /// <summary>
- /// Returns the index of the first occurrence of a specific pointer in the list.
- /// </summary>
- /// <param name="ptr">The pointer to search for in the list.</param>
- /// <returns>The index of the first occurrence of the pointer. Returns -1 if it is not found in the list.</returns>
- public int IndexOf(void* ptr)
- {
- for (int i = 0; i < Length; ++i)
- {
- if (Ptr[i] == ptr) return i;
- }
-
- return -1;
- }
-
- /// <summary>
- /// Returns true if the list contains at least one occurrence of a specific pointer.
- /// </summary>
- /// <param name="ptr">The pointer to search for in the list.</param>
- /// <returns>True if the list contains at least one occurrence of the pointer.</returns>
- public bool Contains(void* ptr)
- {
- return IndexOf(ptr) != -1;
- }
-
- /// <summary>
- /// Adds a pointer to the end of this list.
- /// </summary>
- /// <remarks>
- /// Increments the length by 1. Never increases the capacity.
- /// </remarks>
- /// <param name="value">The pointer to add to the end of the list.</param>
- /// <exception cref="Exception">Thrown if incrementing the length would exceed the capacity.</exception>
- public void AddNoResize(void* value)
- {
- this.ListData().AddNoResize((IntPtr)value);
- }
-
- /// <summary>
- /// Copies pointers from a buffer to the end of this list.
- /// </summary>
- /// <remarks>
- /// Increments the length by `count`. Never increases the capacity.
- /// </remarks>
- /// <param name="ptr">The buffer to copy from.</param>
- /// <param name="count">The number of pointers to copy from the buffer.</param>
- /// <exception cref="Exception">Thrown if the increased length would exceed the capacity.</exception>
- public void AddRangeNoResize(void** ptr, int count) => this.ListData().AddRangeNoResize(ptr, count);
-
- /// <summary>
- /// Copies the pointers of another list to the end of this list.
- /// </summary>
- /// <param name="list">The other list to copy from.</param>
- /// <remarks>
- /// Increments the length by the length of the other list. Never increases the capacity.
- /// </remarks>
- /// <exception cref="Exception">Thrown if the increased length would exceed the capacity.</exception>
- public void AddRangeNoResize(UnsafePtrList<T> list) => this.ListData().AddRangeNoResize(list.Ptr, list.Length);
-
- /// <summary>
- /// Adds a pointer to the end of the list.
- /// </summary>
- /// <param name="value">The pointer to add to the end of this list.</param>
- /// <remarks>
- /// Increments the length by 1. Increases the capacity if necessary.
- /// </remarks>
- public void Add(in IntPtr value)
- {
- this.ListData().Add(value);
- }
-
- /// <summary>
- /// Adds a pointer to the end of the list.
- /// </summary>
- /// <param name="value">The pointer to add to the end of this list.</param>
- /// <remarks>
- /// Increments the length by 1. Increases the capacity if necessary.
- /// </remarks>
- public void Add(void* value)
- {
- this.ListData().Add((IntPtr)value);
- }
-
- /// <summary>
- /// Adds elements from a buffer to this list.
- /// </summary>
- /// <param name="ptr">A pointer to the buffer.</param>
- /// <param name="length">The number of elements to add to the list.</param>
- public void AddRange(void* ptr, int length) => this.ListData().AddRange(ptr, length);
-
- /// <summary>
- /// Copies the elements of another list to the end of this list.
- /// </summary>
- /// <param name="list">The other list to copy from.</param>
- /// <remarks>
- /// Increments the length by the length of the other list. Increases the capacity if necessary.
- /// </remarks>
- public void AddRange(UnsafePtrList<T> list) => this.ListData().AddRange(list.ListData());
-
- /// <summary>
- /// Shifts pointers toward the end of this list, increasing its length.
- /// </summary>
- /// <remarks>
- /// Right-shifts pointers in the list so as to create 'free' slots at the beginning or in the middle.
- ///
- /// The length is increased by `end - begin`. If necessary, the capacity will be increased accordingly.
- ///
- /// If `end` equals `begin`, the method does nothing.
- ///
- /// The pointer at index `begin` will be copied to index `end`, the pointer at index `begin + 1` will be copied to `end + 1`, and so forth.
- ///
- /// The indexes `begin` up to `end` are not cleared: they will contain whatever pointers they held prior.
- /// </remarks>
- /// <param name="begin">The index of the first pointer that will be shifted up.</param>
- /// <param name="end">The index where the first shifted pointer will end up.</param>
- /// <exception cref="ArgumentException">Thrown if `end < begin`.</exception>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `begin` or `end` are out of bounds.</exception>
- public void InsertRangeWithBeginEnd(int begin, int end) => this.ListData().InsertRangeWithBeginEnd(begin, end);
-
- /// <summary>
- /// Copies the last pointer of this list to the specified index. Decrements the length by 1.
- /// </summary>
- /// <remarks>Useful as a cheap way to remove a pointer from this list when you don't care about preserving order.</remarks>
- /// <param name="index">The index to overwrite with the last pointer.</param>
- /// <exception cref="IndexOutOfRangeException">Thrown if `index` is out of bounds.</exception>
- public void RemoveAtSwapBack(int index) => this.ListData().RemoveAtSwapBack(index);
-
- /// <summary>
- /// Copies the last *N* pointer of this list to a range in this list. Decrements the length by *N*.
- /// </summary>
- /// <remarks>
- /// Copies the last `count` pointers to the indexes `index` up to `index + count`.
- ///
- /// Useful as a cheap way to remove pointers from a list when you don't care about preserving order.
- /// </remarks>
- /// <param name="index">The index of the first pointer to overwrite.</param>
- /// <param name="count">The number of pointers to copy and remove.</param>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds, `count` is negative,
- /// or `index + count` exceeds the length.</exception>
- public void RemoveRangeSwapBack(int index, int count) => this.ListData().RemoveRangeSwapBack(index, count);
-
- /// <summary>
- /// Copies the last *N* pointers of this list to a range in this list. Decrements the length by *N*.
- /// </summary>
- /// <remarks>
- /// Copies the last `end - begin` pointers to the indexes `begin` up to `end`.
- ///
- /// Useful as a cheap way to remove pointers from a list when you don't care about preserving order.
- ///
- /// Does nothing if `end - begin` is less than 1.
- /// </remarks>
- /// <param name="begin">The index of the first pointers to overwrite.</param>
- /// <param name="end">The index one greater than the last pointers to overwrite.</param>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `begin` or `end` are out of bounds.</exception>
- [Obsolete("RemoveRangeSwapBackWithBeginEnd(begin, end) is deprecated, use RemoveRangeSwapBack(index, count) instead. (RemovedAfter 2021-06-02)", false)]
- public void RemoveRangeSwapBackWithBeginEnd(int begin, int end) => this.ListData().RemoveRangeSwapBackWithBeginEnd(begin, end);
-
- /// <summary>
- /// Removes the pointer at an index, shifting everything above it down by one. Decrements the length by 1.
- /// </summary>
- /// <param name="index">The index of the pointer to remove.</param>
- /// <remarks>
- /// If you don't care about preserving the order of the pointers, <see cref="RemoveAtSwapBack(int)"/> is a more efficient way to remove pointers.
- /// </remarks>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds.</exception>
- public void RemoveAt(int index) => this.ListData().RemoveAt(index);
-
- /// <summary>
- /// Removes *N* pointers in a range, shifting everything above the range down by *N*. Decrements the length by *N*.
- /// </summary>
- /// <param name="index">The index of the first pointer to remove.</param>
- /// <param name="count">The number of pointers to remove.</param>
- /// <remarks>
- /// If you don't care about preserving the order of the pointers, <see cref="RemoveRangeSwapBackWithBeginEnd"/>
- /// is a more efficient way to remove pointers.
- /// </remarks>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds, `count` is negative,
- /// or `index + count` exceeds the length.</exception>
- public void RemoveRange(int index, int count) => this.ListData().RemoveRange(index, count);
-
- /// <summary>
- /// Removes *N* pointers in a range, shifting everything above it down by *N*. Decrements the length by *N*.
- /// </summary>
- /// <param name="begin">The index of the first pointer to remove.</param>
- /// <param name="end">The index one greater than the last pointer to remove.</param>
- /// <remarks>
- /// If you don't care about preserving the order of the pointers, <see cref="RemoveRangeSwapBackWithBeginEnd"/> is a more efficient way to remove pointers.
- /// </remarks>
- /// <exception cref="ArgumentException">Thrown if `end < begin`.</exception>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if `begin` or `end` are out of bounds.</exception>
- [Obsolete("RemoveRangeWithBeginEnd(begin, end) is deprecated, use RemoveRange(index, count) instead. (RemovedAfter 2021-06-02)", false)]
- public void RemoveRangeWithBeginEnd(int begin, int end) => this.ListData().RemoveRangeWithBeginEnd(begin, end);
-
- /// <summary>
- /// This method is not implemented. It will throw NotImplementedException if it is used.
- /// </summary>
- /// <remarks>Use Enumerator GetEnumerator() instead.</remarks>
- /// <returns>Throws NotImplementedException.</returns>
- /// <exception cref="NotImplementedException">Method is not implemented.</exception>
- IEnumerator IEnumerable.GetEnumerator()
- {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// This method is not implemented. It will throw NotImplementedException if it is used.
- /// </summary>
- /// <remarks>Use Enumerator GetEnumerator() instead.</remarks>
- /// <returns>Throws NotImplementedException.</returns>
- /// <exception cref="NotImplementedException">Method is not implemented.</exception>
- IEnumerator<IntPtr> IEnumerable<IntPtr>.GetEnumerator()
- {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Returns a parallel reader of this list.
- /// </summary>
- /// <returns>A parallel reader of this list.</returns>
- public ParallelReader AsParallelReader()
- {
- return new ParallelReader(Ptr, Length);
- }
-
- /// <summary>
- /// A parallel reader for an UnsafePtrList<T>.
- /// </summary>
- /// <remarks>
- /// Use <see cref="AsParallelReader"/> to create a parallel reader for a list.
- /// </remarks>
- [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
- public unsafe struct ParallelReader
- {
- /// <summary>
- /// The internal buffer of the list.
- /// </summary>
- [NativeDisableUnsafePtrRestriction]
- public readonly T** Ptr;
-
- /// <summary>
- /// The number of elements.
- /// </summary>
- public readonly int Length;
-
- internal ParallelReader(T** ptr, int length)
- {
- Ptr = ptr;
- Length = length;
- }
-
- /// <summary>
- /// Returns the index of the first occurrence of a specific pointer in the list.
- /// </summary>
- /// <param name="ptr">The pointer to search for in the list.</param>
- /// <returns>The index of the first occurrence of the pointer. Returns -1 if it is not found in the list.</returns>
- public int IndexOf(void* ptr)
- {
- for (int i = 0; i < Length; ++i)
- {
- if (Ptr[i] == ptr) return i;
- }
- return -1;
- }
-
- /// <summary>
- /// Returns true if the list contains at least one occurrence of a specific pointer.
- /// </summary>
- /// <param name="ptr">The pointer to search for in the list.</param>
- /// <returns>True if the list contains at least one occurrence of the pointer.</returns>
- public bool Contains(void* ptr)
- {
- return IndexOf(ptr) != -1;
- }
- }
-
- /// <summary>
- /// Returns a parallel writer of this list.
- /// </summary>
- /// <returns>A parallel writer of this list.</returns>
- public ParallelWriter AsParallelWriter()
- {
- return new ParallelWriter(Ptr, (UnsafeList<IntPtr>*)UnsafeUtility.AddressOf(ref this));
- }
-
- /// <summary>
- /// A parallel writer for an UnsafePtrList<T>.
- /// </summary>
- /// <remarks>
- /// Use <see cref="AsParallelWriter"/> to create a parallel writer for a list.
- /// </remarks>
- [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
- public unsafe struct ParallelWriter
- {
- /// <summary>
- /// The data of the list.
- /// </summary>
- [NativeDisableUnsafePtrRestriction]
- public readonly T** Ptr;
-
- /// <summary>
- /// The UnsafeList to write to.
- /// </summary>
- [NativeDisableUnsafePtrRestriction]
- public UnsafeList<IntPtr>* ListData;
-
- internal unsafe ParallelWriter(T** ptr, UnsafeList<IntPtr>* listData)
- {
- Ptr = ptr;
- ListData = listData;
- }
-
- /// <summary>
- /// Adds a pointer to the end of the list.
- /// </summary>
- /// <param name="value">The pointer to add to the end of the list.</param>
- /// <remarks>
- /// Increments the length by 1. Never increases the capacity.
- /// </remarks>
- /// <exception cref="Exception">Thrown if incrementing the length would exceed the capacity.</exception>
- public void AddNoResize(T* value) => ListData->AddNoResize((IntPtr)value);
-
- /// <summary>
- /// Copies pointers from a buffer to the end of the list.
- /// </summary>
- /// <param name="ptr">The buffer to copy from.</param>
- /// <param name="count">The number of pointers to copy from the buffer.</param>
- /// <remarks>
- /// Increments the length by `count`. Never increases the capacity.
- /// </remarks>
- /// <exception cref="Exception">Thrown if the increased length would exceed the capacity.</exception>
- public void AddRangeNoResize(T** ptr, int count) => ListData->AddRangeNoResize(ptr, count);
-
- /// <summary>
- /// Copies the pointers of another list to the end of this list.
- /// </summary>
- /// <param name="list">The other list to copy from.</param>
- /// <remarks>
- /// Increments the length by the length of the other list. Never increases the capacity.
- /// </remarks>
- /// <exception cref="Exception">Thrown if the increased length would exceed the capacity.</exception>
- public void AddRangeNoResize(UnsafePtrList<T> list) => ListData->AddRangeNoResize(list.Ptr, list.Length);
- }
- }
-
- [BurstCompatible]
- internal static class UnsafePtrListTExtensions
- {
- [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
- public static ref UnsafeList<IntPtr> ListData<T>(ref this UnsafePtrList<T> from) where T : unmanaged => ref UnsafeUtility.As<UnsafePtrList<T>, UnsafeList<IntPtr>>(ref from);
- }
-
- internal sealed class UnsafePtrListTDebugView<T>
- where T : unmanaged
- {
- UnsafePtrList<T> Data;
-
- public UnsafePtrListTDebugView(UnsafePtrList<T> data)
- {
- Data = data;
- }
-
- public unsafe T*[] Items
- {
- get
- {
- T*[] result = new T*[Data.Length];
-
- for (var i = 0; i < result.Length; ++i)
- {
- result[i] = Data.Ptr[i];
- }
-
- return result;
- }
- }
- }
- }
|