using System; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEngine; namespace LanLib.UpdateManager.Jobs.Internal { public unsafe struct UnsafeNativeList : IDisposable where T : struct { public const float TrimCapacityThreshold = 0.9f; public static readonly long SizeOfT = UnsafeUtility.SizeOf(); public static readonly int AlignOfT = UnsafeUtility.AlignOf(); [NativeDisableUnsafePtrRestriction] private void* _buffer; private int _length; private int _capacity; private Allocator Allocator; public int Length => _length; public long BufferLength => _length * SizeOfT; public int Capacity => _capacity; public T this[int index] { get => UnsafeUtility.ReadArrayElement(_buffer, index); set => UnsafeUtility.WriteArrayElement(_buffer, index, value); } public UnsafeNativeList(Allocator allocator) { _buffer = null; _capacity = 0; _length = 0; Allocator = allocator; } public void Dispose() { if (_buffer != null) { UnsafeUtility.Free(_buffer, Allocator); _buffer = null; } _capacity = 0; _length = 0; } public void EnsureCapacity(int capacity, bool keepData = true) { if (_capacity < capacity) { Realloc(capacity, keepData); } } public void Realloc(int newCapacity, bool keepData = true) { if (newCapacity == _capacity) { return; } if (newCapacity == 0) { Dispose(); return; } void* newBuffer = UnsafeUtility.Malloc(newCapacity * SizeOfT, AlignOfT, Allocator); if (_buffer != null) { if (keepData) { UnsafeUtility.MemCpy(newBuffer, _buffer, Mathf.Min(_capacity, newCapacity) * SizeOfT); } UnsafeUtility.Free(_buffer, Allocator); } _buffer = newBuffer; _capacity = newCapacity; } public void Add(T value) { _length++; ItemRefAt(_length - 1) = value; } public void RemoveAtSwapBack(int index) { int lastIndex = _length - 1; if (lastIndex > 0 && lastIndex != index) { ItemRefAt(index) = ItemRefAt(lastIndex); } _length--; } public ref T ItemRefAt(int index) { #if UNITY_EDITOR || DEVELOPMENT_BUILD if (index < 0 || index >= _length) { throw new ArgumentOutOfRangeException(nameof(index)); } if (_buffer == null) { throw new NullReferenceException("Buffer is null"); } #endif return ref UnsafeUtility.ArrayElementAsRef(_buffer, index); } public void CopyFrom(UnsafeNativeList other) { EnsureCapacity(other._length, false); UnsafeUtility.MemCpy(_buffer, other._buffer, other.BufferLength); } public void TrimExcess() { if (_length < _capacity * TrimCapacityThreshold) { Realloc(_length, true); } } } }