using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Unity.Burst;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
namespace Unity.Collections
{
    /// 
    /// An indexable collection.
    /// 
    /// The type of the elements in the collection.
    public interface IIndexable where T : unmanaged
    {
        /// 
        /// The current number of elements in the collection.
        /// 
        /// The current number of elements in the collection.
        int Length { get; set; }
        /// 
        /// Returns a reference to the element at a given index.
        /// 
        /// The index to access. Must be in the range of [0..Length).
        /// A reference to the element at the index.
        ref T ElementAt(int index);
    }
    /// 
    /// A resizable list.
    /// 
    /// The type of the elements.
    public interface INativeList : IIndexable where T : unmanaged
    {
        /// 
        /// The number of elements that fit in the current allocation.
        /// 
        /// The number of elements that fit in the current allocation.
        /// A new capacity.
        int Capacity { get; set; }
        /// 
        /// Whether this list is empty.
        /// 
        /// True if this list is empty.
        bool IsEmpty { get; }
        /// 
        /// The element at an index.
        /// 
        /// An index.
        /// The element at the index.
        /// Thrown if index is out of bounds.
        T this[int index] { get; set; }
        /// 
        /// Sets the length to 0.
        /// 
        /// Does not change the capacity.
        void Clear();
    }
    /// 
    /// An unmanaged, resizable list.
    /// 
    /// The elements are stored contiguously in a buffer rather than as linked nodes.
    /// The type of the elements.
    [StructLayout(LayoutKind.Sequential)]
    [NativeContainer]
    [DebuggerDisplay("Length = {m_ListData == null ? default : m_ListData->Length}, Capacity = {m_ListData == null ? default : m_ListData->Capacity}")]
    [DebuggerTypeProxy(typeof(NativeListDebugView<>))]
    [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
    public unsafe struct NativeList
        : INativeDisposable
        , INativeList
        , IEnumerable // Used by collection initializers.
        where T : unmanaged
    {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        internal AtomicSafetyHandle m_Safety;
        internal int m_SafetyIndexHint;
        internal static readonly SharedStatic s_staticSafetyId = SharedStatic.GetOrCreate>();
#endif
        [NativeDisableUnsafePtrRestriction]
        internal UnsafeList* m_ListData;
        /// 
        /// Initializes and returns a NativeList with a capacity of one.
        /// 
        /// The allocator to use.
        public NativeList(AllocatorManager.AllocatorHandle allocator)
            : this(1, allocator)
        {
        }
        /// 
        /// Initializes and returns a NativeList.
        /// 
        /// The initial capacity of the list.
        /// The allocator to use.
        public NativeList(int initialCapacity, AllocatorManager.AllocatorHandle allocator)
        {
            this = default;
            AllocatorManager.AllocatorHandle temp = allocator;
            Initialize(initialCapacity, ref temp);
        }
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(AllocatorManager.AllocatorHandle) })]
        internal void Initialize(int initialCapacity, ref U allocator) where U : unmanaged, AllocatorManager.IAllocator
        {
            var totalSize = sizeof(T) * (long)initialCapacity;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            CollectionHelper.CheckAllocator(allocator.Handle);
            CheckInitialCapacity(initialCapacity);
            CheckTotalSize(initialCapacity, totalSize);
            m_Safety = CollectionHelper.CreateSafetyHandle(allocator.Handle);
            CollectionHelper.InitNativeContainer(m_Safety);
            CollectionHelper.SetStaticSafetyId>(ref m_Safety, ref s_staticSafetyId.Data);
            m_SafetyIndexHint = (allocator.Handle).AddSafetyHandle(m_Safety);
            AtomicSafetyHandle.SetBumpSecondaryVersionOnScheduleWrite(m_Safety, true);
#endif
            m_ListData = UnsafeList.Create(initialCapacity, ref allocator, NativeArrayOptions.UninitializedMemory);
        }
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(AllocatorManager.AllocatorHandle) })]
        internal static NativeList New(int initialCapacity, ref U allocator) where U : unmanaged, AllocatorManager.IAllocator
        {
            var nativelist = new NativeList();
            nativelist.Initialize(initialCapacity, ref allocator);
            return nativelist;
        }
        /// 
        /// The element at a given index.
        /// 
        /// An index into this list.
        /// The value to store at the `index`.
        /// Thrown if `index` is out of bounds.
        public T this[int index]
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
#endif
                return (*m_ListData)[index];
            }
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            set
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
#endif
                (*m_ListData)[index] = value;
            }
        }
        /// 
        /// Returns a reference to the element at an index.
        /// 
        /// An index.
        /// A reference to the element at the index.
        /// Thrown if index is out of bounds.
        public ref T ElementAt(int index)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
#endif
            return ref m_ListData->ElementAt(index);
        }
        /// 
        /// The count of elements.
        /// 
        /// The current count of elements. Always less than or equal to the capacity.
        /// To decrease the memory used by a list, set  after reducing the length of the list.
        /// The new length. If the new length is greater than the current capacity, the capacity is increased.
        /// Newly allocated memory is cleared.
        public int Length
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            readonly get
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
#endif
                return CollectionHelper.AssumePositive(m_ListData->Length);
            }
            set
            {
                // Unity 2022.2.16f1 removes the global temp safety handle so only
                // from this version onward is it not a breaking change to perform this check
                // since all previous versions did not have this safety check and will
                // likely break from safe usage that is blurred by sharing the temp safety handle
                // between multiple containers
#if ENABLE_UNITY_COLLECTIONS_CHECKS && UNITY_2022_2_16F1_OR_NEWER
                AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
                m_ListData->Resize(value, NativeArrayOptions.ClearMemory);
            }
        }
        /// 
        /// The number of elements that fit in the current allocation.
        /// 
        /// The number of elements that fit in the current allocation.
        /// The new capacity. Must be greater or equal to the length.
        /// Thrown if the new capacity is smaller than the length.
        public int Capacity
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            readonly get
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
#endif
                return m_ListData->Capacity;
            }
            set
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
                m_ListData->Capacity = value;
            }
        }
        /// 
        /// Returns the internal unsafe list.
        /// 
        /// Internally, the elements of a NativeList are stored in an UnsafeList.
        /// The internal unsafe list.
        public UnsafeList* GetUnsafeList() => m_ListData;
        /// 
        /// Appends an element to the end of this list.
        /// 
        /// The value to add to the end of this list.
        /// 
        /// Length is incremented by 1. Will not increase the capacity.
        /// 
        /// Thrown if incrementing the length would exceed the capacity.
        public void AddNoResize(T value)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
#endif
            m_ListData->AddNoResize(value);
        }
        /// 
        /// Appends elements from a buffer to the end of this list.
        /// 
        /// The buffer to copy from.
        /// The number of elements to copy from the buffer.
        /// 
        /// Length is increased by the count. Will not increase the capacity.
        /// 
        /// Thrown if the increased length would exceed the capacity.
        public void AddRangeNoResize(void* ptr, int count)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
#endif
            CheckArgPositive(count);
            m_ListData->AddRangeNoResize(ptr, count);
        }
        /// 
        /// Appends the elements of another list to the end of this list.
        /// 
        /// The other list to copy from.
        /// 
        /// Length is increased by the length of the other list. Will not increase the capacity.
        /// 
        /// Thrown if the increased length would exceed the capacity.
        public void AddRangeNoResize(NativeList list)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
#endif
            m_ListData->AddRangeNoResize(*list.m_ListData);
        }
        /// 
        /// Appends an element to the end of this list.
        /// 
        /// The value to add to the end of this list.
        /// 
        /// Length is incremented by 1. If necessary, the capacity is increased.
        /// 
        public void Add(in T value)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
            m_ListData->Add(in value);
        }
        /// 
        /// Appends the elements of an array to the end of this list.
        /// 
        /// The array to copy from.
        /// 
        /// Length is increased by the number of new elements. Does not increase the capacity.
        /// 
        /// Thrown if the increased length would exceed the capacity.
        public void AddRange(NativeArray array)
        {
            AddRange(array.GetUnsafeReadOnlyPtr(), array.Length);
        }
        /// 
        /// Appends the elements of a buffer to the end of this list.
        /// 
        /// The buffer to copy from.
        /// The number of elements to copy from the buffer.
        /// Thrown if count is negative.
        public void AddRange(void* ptr, int count)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
            CheckArgPositive(count);
            m_ListData->AddRange(ptr, CollectionHelper.AssumePositive(count));
        }
        /// 
        /// Appends value count times to the end of this list.
        /// 
        /// The value to add to the end of this list.
        /// The number of times to replicate the value.
        /// 
        /// Length is incremented by count. If necessary, the capacity is increased.
        /// 
        /// Thrown if count is negative.
        public void AddReplicate(in T value, int count)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
            CheckArgPositive(count);
            m_ListData->AddReplicate(in value, CollectionHelper.AssumePositive(count));
        }
        /// 
        /// Shifts elements toward the end of this list, increasing its length.
        /// 
        /// 
        /// 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.
        /// 
        /// The index of the first element that will be shifted up.
        /// The index where the first shifted element will end up.
        /// Thrown if `end < begin`.
        /// Thrown if `begin` or `end` are out of bounds.
        public void InsertRangeWithBeginEnd(int begin, int end)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
            m_ListData->InsertRangeWithBeginEnd(begin, end);
        }
        /// 
        /// Shifts elements toward the end of this list, increasing its length.
        /// 
        /// 
        /// Right-shifts elements in the list so as to create 'free' slots at the beginning or in the middle.
        ///
        /// The length is increased by `count`. If necessary, the capacity will be increased accordingly.
        ///
        /// If `count` equals `0`, the method does nothing.
        ///
        /// 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.
        ///
        /// The indexes `index` up to `index + count` are not cleared: they will contain whatever values they held prior.
        /// 
        /// The index of the first element that will be shifted up.
        /// The number of elements to insert.
        /// Thrown if `count` is negative.
        /// Thrown if `index` is out of bounds.
        public void InsertRange(int index, int count) => InsertRangeWithBeginEnd(index, index + count);
        /// 
        /// Copies the last element of this list to the specified index. Decrements the length by 1.
        /// 
        /// Useful as a cheap way to remove an element from this list when you don't care about preserving order.
        /// The index to overwrite with the last element.
        /// Thrown if `index` is out of bounds.
        public void RemoveAtSwapBack(int index)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
            m_ListData->RemoveAtSwapBack(index);
        }
        /// 
        /// Copies the last *N* elements of this list to a range in this list. Decrements the length by *N*.
        /// 
        /// 
        /// 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.
        /// 
        /// The index of the first element to overwrite.
        /// The number of elements to copy and remove.
        /// Thrown if `index` is out of bounds, `count` is negative,
        /// or `index + count` exceeds the length.
        public void RemoveRangeSwapBack(int index, int count)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
            m_ListData->RemoveRangeSwapBack(index, count);
        }
        /// 
        /// Removes the element at an index, shifting everything above it down by one. Decrements the length by 1.
        /// 
        /// The index of the item to remove.
        /// 
        /// If you don't care about preserving the order of the elements,  is a more efficient way to remove elements.
        /// 
        /// Thrown if `index` is out of bounds.
        public void RemoveAt(int index)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
            m_ListData->RemoveAt(index);
        }
        /// 
        /// Removes *N* elements in a range, shifting everything above the range down by *N*. Decrements the length by *N*.
        /// 
        /// The index of the first element to remove.
        /// The number of elements to remove.
        /// 
        /// If you don't care about preserving the order of the elements, `RemoveRangeSwapBackWithBeginEnd`
        /// is a more efficient way to remove elements.
        /// 
        /// Thrown if `index` is out of bounds, `count` is negative,
        /// or `index + count` exceeds the length.
        public void RemoveRange(int index, int count)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
            m_ListData->RemoveRange(index, count);
        }
        /// 
        /// Whether this list is empty.
        /// 
        /// True if the list is empty or if the list has not been constructed.
        public readonly bool IsEmpty
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get => m_ListData == null || m_ListData->Length == 0;
        }
        /// 
        /// Whether this list has been allocated (and not yet deallocated).
        /// 
        /// True if this list has been allocated (and not yet deallocated).
        public readonly bool IsCreated
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get => m_ListData != null;
        }
        /// 
        /// Releases all resources (memory and safety handles).
        /// 
        public void Dispose()
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            if (!AtomicSafetyHandle.IsDefaultValue(m_Safety))
            {
                AtomicSafetyHandle.CheckExistsAndThrow(m_Safety);
            }
#endif
            if (!IsCreated)
            {
                return;
            }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            CollectionHelper.DisposeSafetyHandle(ref m_Safety);
#endif
            UnsafeList.Destroy(m_ListData);
            m_ListData = null;
        }
        /// 
        /// Releases all resources (memory and safety handles).
        /// The type of allocator.
        /// The allocator that was used to allocate this list.
        /// 
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(AllocatorManager.AllocatorHandle) })]
        internal void Dispose(ref U allocator) where U : unmanaged, AllocatorManager.IAllocator
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            if (!AtomicSafetyHandle.IsDefaultValue(m_Safety))
            {
                AtomicSafetyHandle.CheckExistsAndThrow(m_Safety);
            }
#endif
            if (!IsCreated)
            {
                return;
            }
            CheckHandleMatches(allocator.Handle);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            CollectionHelper.DisposeSafetyHandle(ref m_Safety);
#endif
            UnsafeList.Destroy(m_ListData, ref allocator);
            m_ListData = null;
        }
        /// 
        /// Creates and schedules a job that releases all resources (memory and safety handles) of this list.
        /// 
        /// The dependency for the new job.
        /// The handle of the new job. The job depends upon `inputDeps` and releases all resources (memory and safety handles) of this list.
        public JobHandle Dispose(JobHandle inputDeps)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            if (!AtomicSafetyHandle.IsDefaultValue(m_Safety))
            {
                AtomicSafetyHandle.CheckExistsAndThrow(m_Safety);
            }
#endif
            if (!IsCreated)
            {
                return inputDeps;
            }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            var jobHandle = new NativeListDisposeJob { Data = new NativeListDispose { m_ListData = (UntypedUnsafeList*)m_ListData, m_Safety = m_Safety } }.Schedule(inputDeps);
            AtomicSafetyHandle.Release(m_Safety);
#else
            var jobHandle = new NativeListDisposeJob { Data = new NativeListDispose { m_ListData = (UntypedUnsafeList*)m_ListData } }.Schedule(inputDeps);
#endif
            m_ListData = null;
            return jobHandle;
        }
        /// 
        /// Sets the length to 0.
        /// 
        /// Does not change the capacity.
        public void Clear()
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
            m_ListData->Clear();
        }
        /// 
        /// **Obsolete.** Use  method to do explicit cast instead.
        /// 
        /// 
        /// Returns a native array that aliases the content of a list.
        /// 
        /// The list to alias.
        /// A native array that aliases the content of the list.
        [Obsolete("Implicit cast from `NativeList` to `NativeArray` has been deprecated; Use '.AsArray()' method to do explicit cast instead.", false)]
        public static implicit operator NativeArray(NativeList nativeList)
        {
            return nativeList.AsArray();
        }
        /// 
        /// Returns a native array that aliases the content of this list.
        /// 
        /// A native array that aliases the content of this list.
        public NativeArray AsArray()
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckGetSecondaryDataPointerAndThrow(m_Safety);
            var arraySafety = m_Safety;
            AtomicSafetyHandle.UseSecondaryVersion(ref arraySafety);
#endif
            var array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(m_ListData->Ptr, m_ListData->Length, Allocator.None);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, arraySafety);
#endif
            return array;
        }
        /// 
        /// Returns an array that aliases this list. The length of the array is updated when the length of
        /// this array is updated in a prior job.
        /// 
        /// 
        /// Useful when a job populates a list that is then used by another job.
        ///
        /// If you pass both jobs the same list, you have to complete the first job before you schedule the second:
        /// otherwise, the second job doesn't see the first job's changes to the list's length.
        ///
        /// If instead you pass the second job a deferred array that aliases the list, the array's length is kept in sync with
        /// the first job's changes to the list's length. Consequently, the first job doesn't have to
        /// be completed before you can schedule the second: the second job simply has to depend upon the first.
        /// 
        /// An array that aliases this list and whose length can be specially modified across jobs.
        /// 
        /// The following example populates a list with integers in one job and passes that data to a second job as
        /// a deferred array. If we tried to pass the list directly to the second job, that job would not see any
        /// modifications made to the list by the first job. To avoid this, we instead pass the second job a deferred array that aliases the list.
        /// 
        /// using UnityEngine;
        /// using Unity.Jobs;
        /// using Unity.Collections;
        ///
        /// public class DeferredArraySum : MonoBehaviour
        ///{
        ///    public struct Populate : IJob
        ///    {
        ///        public NativeList<int> list;
        ///
        ///        public void Execute()
        ///        {
        ///            for (int i = list.Length; i < list.Capacity; i++)
        ///            {
        ///                list.Add(i);
        ///            }
        ///        }
        ///    }
        ///
        ///    // Sums all numbers from deferred.
        ///    public struct Sum : IJob
        ///    {
        ///        [ReadOnly] public NativeArray<int> deferred;
        ///        public NativeArray<int> sum;
        ///
        ///        public void Execute()
        ///        {
        ///            sum[0] = 0;
        ///            for (int i = 0; i < deferred.Length; i++)
        ///            {
        ///                sum[0] += deferred[i];
        ///            }
        ///        }
        ///    }
        ///
        ///    void Start()
        ///    {
        ///        var list = new NativeList<int>(100, Allocator.TempJob);
        ///        var deferred = list.AsDeferredJobArray(),
        ///        var output = new NativeArray<int>(1, Allocator.TempJob);
        ///
        ///        // The Populate job increases the list's length from 0 to 100.
        ///        var populate = new Populate { list = list }.Schedule();
        ///
        ///        // At time of scheduling, the length of the deferred array given to Sum is 0.
        ///        // When Populate increases the list's length, the deferred array's length field in the
        ///        // Sum job is also modified, even though it has already been scheduled.
        ///        var sum = new Sum { deferred = deferred, sum = output }.Schedule(populate);
        ///
        ///        sum.Complete();
        ///
        ///        Debug.Log("Result: " + output[0]);
        ///
        ///        list.Dispose();
        ///        output.Dispose();
        ///    }
        /// }
        /// 
        /// 
        public NativeArray AsDeferredJobArray()
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckExistsAndThrow(m_Safety);
#endif
            byte* buffer = (byte*)m_ListData;
            // We use the first bit of the pointer to infer that the array is in list mode
            // Thus the job scheduling code will need to patch it.
            buffer += 1;
            var array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(buffer, 0, Allocator.Invalid);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, m_Safety);
#endif
            return array;
        }
        /// 
        /// Returns an array containing a copy of this list's content.
        /// 
        /// The allocator to use.
        /// An array containing a copy of this list's content.
        public NativeArray ToArray(AllocatorManager.AllocatorHandle allocator)
        {
            NativeArray result = CollectionHelper.CreateNativeArray(Length, allocator, NativeArrayOptions.UninitializedMemory);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
            AtomicSafetyHandle.CheckWriteAndThrow(result.m_Safety);
#endif
            UnsafeUtility.MemCpy((byte*)result.m_Buffer, (byte*)m_ListData->Ptr, Length * UnsafeUtility.SizeOf());
            return result;
        }
        /// 
        /// Copies all elements of specified container to this container.
        /// 
        /// An container to copy into this container.
        public void CopyFrom(in NativeArray other)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
            AtomicSafetyHandle.CheckReadAndThrow(other.m_Safety);
#endif
            m_ListData->CopyFrom(other);
        }
        /// 
        /// Copies all elements of specified container to this container.
        /// 
        /// An container to copy into this container.
        public void CopyFrom(in UnsafeList other)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
            m_ListData->CopyFrom(other);
        }
        /// 
        /// Copies all elements of specified container to this container.
        /// 
        /// An container to copy into this container.
        public void CopyFrom(in NativeList other)
        {
            CopyFrom(*other.m_ListData);
        }
        /// 
        /// Returns an enumerator over the elements of this list.
        /// 
        /// An enumerator over the elements of this list.
        public NativeArray.Enumerator GetEnumerator()
        {
            var array = AsArray();
            return new NativeArray.Enumerator(ref array);
        }
        /// 
        /// This method is not implemented. Use  instead.
        /// 
        /// Throws NotImplementedException.
        /// Method is not implemented.
        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }
        /// 
        /// This method is not implemented. Use  instead.
        /// 
        /// Throws NotImplementedException.
        /// Method is not implemented.
        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }
        /// 
        /// Sets the length of this list, increasing the capacity if necessary.
        /// 
        /// The new length of this list.
        /// Whether to clear any newly allocated bytes to all zeroes.
        public void Resize(int length, NativeArrayOptions options)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety);
#endif
            m_ListData->Resize(length, options);
        }
        /// 
        /// Sets the length of this list, increasing the capacity if necessary.
        /// 
        /// Does not clear newly allocated bytes.
        /// The new length of this list.
        public void ResizeUninitialized(int length)
        {
            Resize(length, NativeArrayOptions.UninitializedMemory);
        }
        /// 
        /// Sets the capacity.
        /// 
        /// The new capacity.
        public void SetCapacity(int capacity)
        {
            m_ListData->SetCapacity(capacity);
        }
        /// 
        /// Sets the capacity to match the length.
        /// 
        public void TrimExcess()
        {
            m_ListData->TrimExcess();
        }
        /// 
        /// Returns a read only of this list.
        /// 
        /// A read only of this list.
        public NativeArray.ReadOnly AsReadOnly()
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            return new NativeArray.ReadOnly(m_ListData->Ptr, m_ListData->Length, ref m_Safety);
#else
            return new NativeArray.ReadOnly(m_ListData->Ptr, m_ListData->Length);
#endif
        }
        /// 
        /// Returns a parallel reader of this list.
        /// 
        /// A parallel reader of this list.
//        [Obsolete("'AsParallelReader' has been deprecated; use 'AsReadOnly' instead. (UnityUpgradable) -> AsReadOnly")]
        public NativeArray.ReadOnly AsParallelReader()
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            return new NativeArray.ReadOnly(m_ListData->Ptr, m_ListData->Length, ref m_Safety);
#else
            return new NativeArray.ReadOnly(m_ListData->Ptr, m_ListData->Length);
#endif
        }
        /// 
        /// Returns a parallel writer of this list.
        /// 
        /// A parallel writer of this list.
        public ParallelWriter AsParallelWriter()
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            return new ParallelWriter(m_ListData, ref m_Safety);
#else
            return new ParallelWriter(m_ListData);
#endif
        }
        /// 
        /// A parallel writer for a NativeList.
        /// 
        /// 
        /// Use  to create a parallel writer for a list.
        /// 
        [NativeContainer]
        [NativeContainerIsAtomicWriteOnly]
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
        public unsafe struct ParallelWriter
        {
            /// 
            /// The data of the list.
            /// 
            public readonly void* Ptr
            {
                [MethodImpl(MethodImplOptions.AggressiveInlining)]
                get => ListData->Ptr;
            }
            /// 
            /// The internal unsafe list.
            /// 
            /// The internal unsafe list.
            [NativeDisableUnsafePtrRestriction]
            public UnsafeList* ListData;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            internal AtomicSafetyHandle m_Safety;
            internal static readonly SharedStatic s_staticSafetyId = SharedStatic.GetOrCreate();
            [GenerateTestsForBurstCompatibility(CompileTarget = GenerateTestsForBurstCompatibilityAttribute.BurstCompatibleCompileTarget.Editor)]
            internal unsafe ParallelWriter(UnsafeList* listData, ref AtomicSafetyHandle safety)
            {
                ListData = listData;
                m_Safety = safety;
                CollectionHelper.SetStaticSafetyId(ref m_Safety, ref s_staticSafetyId.Data);
            }
#else
            internal unsafe ParallelWriter(UnsafeList* listData)
            {
                ListData = listData;
            }
#endif
            /// 
            /// Appends an element to the end of this list.
            /// 
            /// The value to add to the end of this list.
            /// 
            /// Increments the length by 1 unless doing so would exceed the current capacity.
            /// 
            /// Thrown if adding an element would exceed the capacity.
            public void AddNoResize(T value)
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
#endif
                var idx = Interlocked.Increment(ref ListData->m_length) - 1;
                CheckSufficientCapacity(ListData->Capacity, idx + 1);
                UnsafeUtility.WriteArrayElement(ListData->Ptr, idx, value);
            }
            /// 
            /// Appends elements from a buffer to the end of this list.
            /// 
            /// The buffer to copy from.
            /// The number of elements to copy from the buffer.
            /// 
            /// Increments the length by `count` unless doing so would exceed the current capacity.
            /// 
            /// Thrown if adding the elements would exceed the capacity.
            public void AddRangeNoResize(void* ptr, int count)
            {
                CheckArgPositive(count);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
#endif
                var idx = Interlocked.Add(ref ListData->m_length, count) - count;
                CheckSufficientCapacity(ListData->Capacity, idx + count);
                var sizeOf = sizeof(T);
                void* dst = (byte*)ListData->Ptr + idx * sizeOf;
                UnsafeUtility.MemCpy(dst, ptr, count * sizeOf);
            }
            /// 
            /// Appends the elements of another list to the end of this list.
            /// 
            /// The other list to copy from.
            /// 
            /// Increments the length of this list by the length of the other list unless doing so would exceed the current capacity.
            /// 
            /// Thrown if adding the elements would exceed the capacity.
            public void AddRangeNoResize(UnsafeList list)
            {
                AddRangeNoResize(list.Ptr, list.Length);
            }
            /// 
            /// Appends the elements of another list to the end of this list.
            /// 
            /// The other list to copy from.
            /// 
            /// Increments the length of this list by the length of the other list unless doing so would exceed the current capacity.
            /// 
            /// Thrown if adding the elements would exceed the capacity.
            public void AddRangeNoResize(NativeList list)
            {
                AddRangeNoResize(*list.m_ListData);
            }
        }
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        static void CheckInitialCapacity(int initialCapacity)
        {
            if (initialCapacity < 0)
                throw new ArgumentOutOfRangeException(nameof(initialCapacity), "Capacity must be >= 0");
        }
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        static void CheckTotalSize(int initialCapacity, long totalSize)
        {
            // Make sure we cannot allocate more than int.MaxValue (2,147,483,647 bytes)
            // because the underlying UnsafeUtility.Malloc is expecting a int.
            // TODO: change UnsafeUtility.Malloc to accept a UIntPtr length instead to match C++ API
            if (totalSize > int.MaxValue)
                throw new ArgumentOutOfRangeException(nameof(initialCapacity), $"Capacity * sizeof(T) cannot exceed {int.MaxValue} bytes");
        }
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        static void CheckSufficientCapacity(int capacity, int length)
        {
            if (capacity < length)
                throw new InvalidOperationException($"Length {length} exceeds Capacity {capacity}");
        }
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        static void CheckIndexInRange(int value, int length)
        {
            if (value < 0)
                throw new IndexOutOfRangeException($"Value {value} must be positive.");
            if ((uint)value >= (uint)length)
                throw new IndexOutOfRangeException(
                    $"Value {value} is out of range in NativeList of '{length}' Length.");
        }
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        static void CheckArgPositive(int value)
        {
            if (value < 0)
                throw new ArgumentOutOfRangeException($"Value {value} must be positive.");
        }
        [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
        void CheckHandleMatches(AllocatorManager.AllocatorHandle handle)
        {
            if(m_ListData == null)
                throw new ArgumentOutOfRangeException($"Allocator handle {handle} can't match because container is not initialized.");
            if(m_ListData->Allocator.Index != handle.Index)
                throw new ArgumentOutOfRangeException($"Allocator handle {handle} can't match because container handle index doesn't match.");
            if(m_ListData->Allocator.Version != handle.Version)
                throw new ArgumentOutOfRangeException($"Allocator handle {handle} matches container handle index, but has different version.");
        }
    }
    [NativeContainer]
    [GenerateTestsForBurstCompatibility]
    internal unsafe struct NativeListDispose
    {
        [NativeDisableUnsafePtrRestriction]
        public UntypedUnsafeList* m_ListData;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        internal AtomicSafetyHandle m_Safety;
#endif
        public void Dispose()
        {
            var listData = (UnsafeList*)m_ListData;
            UnsafeList.Destroy(listData);
        }
    }
    [BurstCompile]
    [GenerateTestsForBurstCompatibility]
    internal unsafe struct NativeListDisposeJob : IJob
    {
        internal NativeListDispose Data;
        public void Execute()
        {
            Data.Dispose();
        }
    }
    sealed unsafe class NativeListDebugView where T : unmanaged
    {
        UnsafeList* Data;
        public NativeListDebugView(NativeList array)
        {
            Data = array.m_ListData;
        }
        public T[] Items
        {
            get
            {
                if (Data == null)
                {
                    return default;
                }
                // Trying to avoid safety checks, so that container can be read in debugger if it's safety handle
                // is in write-only mode.
                var length = Data->Length;
                var dst = new T[length];
                fixed (T* pDst = &dst[0])
                {
                    UnsafeUtility.MemCpy(pDst, Data->Ptr, length * UnsafeUtility.SizeOf());
                }
                return dst;
            }
        }
    }
    /// 
    /// Provides extension methods for UnsafeList.
    /// 
    [GenerateTestsForBurstCompatibility]
    public unsafe static class NativeListExtensions
    {
        /// 
        /// Returns true if a particular value is present in this list.
        /// 
        /// The type of elements in this list.
        /// The value type.
        /// The list to search.
        /// The value to locate.
        /// True if the value is present in this list.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(int) })]
        public static bool Contains(this NativeList list, U value)
            where T : unmanaged, IEquatable
        {
            return NativeArrayExtensions.IndexOf(list.GetUnsafeReadOnlyPtr(), list.Length, value) != -1;
        }
        /// 
        /// Finds the index of the first occurrence of a particular value in this list.
        /// 
        /// The type of elements in the list.
        /// The value type.
        /// The list to search.
        /// The value to locate.
        /// The index of the first occurrence of the value in this list. Returns -1 if no occurrence is found.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(int) })]
        public static int IndexOf(this NativeList list, U value)
            where T : unmanaged, IEquatable
        {
            return NativeArrayExtensions.IndexOf(list.GetUnsafeReadOnlyPtr(), list.Length, value);
        }
        /// 
        /// Returns true if this container and another have equal length and content.
        /// 
        /// The type of the source container's elements.
        /// The container to compare for equality.
        /// The other container to compare for equality.
        /// True if the containers have equal length and content.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
        public static bool ArraysEqual(this NativeArray container, in NativeList other)
            where T : unmanaged, IEquatable
        {
            return container.ArraysEqual(other.AsArray());
        }
        /// 
        /// Returns true if this container and another have equal length and content.
        /// 
        /// The type of the source container's elements.
        /// The container to compare for equality.
        /// The other container to compare for equality.
        /// True if the containers have equal length and content.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
        public static bool ArraysEqual(this NativeList container, in NativeArray other)
            where T : unmanaged, IEquatable
        {
            return other.ArraysEqual(container);
        }
        /// 
        /// Returns true if this container and another have equal length and content.
        /// 
        /// The type of the source container's elements.
        /// The container to compare for equality.
        /// The other container to compare for equality.
        /// True if the containers have equal length and content.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
        public static bool ArraysEqual(this NativeList container, in NativeList other)
            where T : unmanaged, IEquatable
        {
            return container.AsArray().ArraysEqual(other.AsArray());
        }
        /// 
        /// Returns true if this container and another have equal length and content.
        /// 
        /// The type of the source container's elements.
        /// The container to compare for equality.
        /// The other container to compare for equality.
        /// True if the containers have equal length and content.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
        public static bool ArraysEqual(this NativeList container, in UnsafeList other)
            where T : unmanaged, IEquatable
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckReadAndThrow(container.m_Safety);
#endif
            return container.m_ListData->ArraysEqual(other);
        }
    }
}
namespace Unity.Collections.LowLevel.Unsafe
{
    /// 
    /// Provides unsafe utility methods for NativeList.
    /// 
    [GenerateTestsForBurstCompatibility]
    public unsafe static class NativeListUnsafeUtility
    {
        /// 
        /// Returns a pointer to this list's internal buffer.
        /// 
        /// Performs a job safety check for read-write access.
        /// The list.
        /// The type of the elements.
        /// A pointer to this list's internal buffer.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
        public static T* GetUnsafePtr(this NativeList list) where T : unmanaged
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckWriteAndThrow(list.m_Safety);
#endif
            return list.m_ListData->Ptr;
        }
        /// 
        /// Returns a pointer to this list's internal buffer.
        /// 
        /// Performs a job safety check for read-only access.
        /// The list.
        /// The type of the elements.
        /// A pointer to this list's internal buffer.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
        public static unsafe T* GetUnsafeReadOnlyPtr(this NativeList list) where T : unmanaged
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckReadAndThrow(list.m_Safety);
#endif
            return list.m_ListData->Ptr;
        }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        /// 
        /// Returns this list's .
        /// 
        /// The list.
        /// The type of the elements.
        /// The atomic safety handle for this list.
        /// 
        /// The job safety checks use a native collection's atomic safety handle to assert safety.
        ///
        /// This method is only available if the symbol `ENABLE_UNITY_COLLECTIONS_CHECKS` is defined.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) }, RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS", CompileTarget = GenerateTestsForBurstCompatibilityAttribute.BurstCompatibleCompileTarget.Editor)]
        public static AtomicSafetyHandle GetAtomicSafetyHandle(ref NativeList list) where T : unmanaged
        {
            return list.m_Safety;
        }
#endif
        /// 
        /// Returns a pointer to this list's internal unsafe list.
        /// 
        /// Performs no job safety checks.
        /// The list.
        /// The type of the elements.
        /// A pointer to this list's internal unsafe list.
        [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
        public static void* GetInternalListDataPtrUnchecked(ref NativeList list) where T : unmanaged
        {
            return list.m_ListData;
        }
    }
}