using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Lua.Internal;
///
/// A list of minimal features. Note that it is NOT thread-safe and must NOT be marked readonly as it is a mutable struct.
///
/// Element type
[StructLayout(LayoutKind.Auto)]
public struct FastListCore
{
const int InitialCapacity = 8;
public static readonly FastListCore Empty = default;
T[]? array;
int tailIndex;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(T element)
{
if (array == null)
{
array = new T[InitialCapacity];
}
else if (array.Length == tailIndex)
{
Array.Resize(ref array, tailIndex * 2);
}
array[tailIndex] = element;
tailIndex++;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Pop()
{
CheckIndex(tailIndex - 1);
array![tailIndex - 1] = default!;
tailIndex--;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveAtSwapBack(int index)
{
CheckIndex(index);
array![index] = array[tailIndex - 1];
array[tailIndex - 1] = default!;
tailIndex--;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Shrink(int newSize)
{
if (newSize >= tailIndex) return;
array.AsSpan(newSize).Clear();
tailIndex = newSize;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear(bool removeArray = false)
{
if (array == null) return;
array.AsSpan().Clear();
tailIndex = 0;
if (removeArray) array = null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EnsureCapacity(int capacity)
{
if (array == null)
{
array = new T[InitialCapacity];
}
while (array.Length < capacity)
{
Array.Resize(ref array, array.Length * 2);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(ref FastListCore destination)
{
destination.EnsureCapacity(tailIndex);
destination.tailIndex = tailIndex;
AsSpan().CopyTo(destination.AsSpan());
}
public ref T this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref array![index];
}
public readonly int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => tailIndex;
}
public readonly Span AsSpan() => array == null ? Span.Empty : array.AsSpan(0, tailIndex);
public readonly T[]? AsArray() => array;
readonly void CheckIndex(int index)
{
if (array == null||index < 0 || index > tailIndex) ThrowIndexOutOfRange();
}
static void ThrowIndexOutOfRange() => throw new IndexOutOfRangeException();
}