You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
3.5 KiB
C#

using System;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
namespace LanLib.UpdateManager.Jobs.Internal
{
public unsafe struct UnsafeNativeList<T> : IDisposable where T : struct
{
public const float TrimCapacityThreshold = 0.9f;
public static readonly long SizeOfT = UnsafeUtility.SizeOf<T>();
public static readonly int AlignOfT = UnsafeUtility.AlignOf<T>();
[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<T>(_buffer, index);
set => UnsafeUtility.WriteArrayElement<T>(_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<T>(_buffer, index);
}
public void CopyFrom(UnsafeNativeList<T> other)
{
EnsureCapacity(other._length, false);
UnsafeUtility.MemCpy(_buffer, other._buffer, other.BufferLength);
}
public void TrimExcess()
{
if (_length < _capacity * TrimCapacityThreshold)
{
Realloc(_length, true);
}
}
}
}