using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace LitMotion.Collections
{
///
/// 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 RemoveAtSwapback(int index)
{
Error.IsNull(array);
CheckIndex(index);
array[index] = array[tailIndex - 1];
array[tailIndex - 1] = default;
tailIndex--;
}
[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);
}
}
public readonly T this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => array[index];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => array[index] = value;
}
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 (index < 0 || index > tailIndex) throw new IndexOutOfRangeException();
}
}
}