using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Jint.Runtime;
namespace Jint.Collections;
///
/// Stack for struct types.
///
internal sealed class RefStack : IEnumerable where T : struct
{
internal T[] _array;
internal int _size;
private const int DefaultCapacity = 2;
public RefStack(int capacity = DefaultCapacity)
{
_array = new T[capacity];
_size = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly T Peek()
{
return ref _array[_size - 1];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly T Peek(int fromTop)
{
var index = _size - 1 - fromTop;
return ref _array[index];
}
public T this[int index] => _array[index];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPeek([NotNullWhen(true)] out T item)
{
if (_size > 0)
{
item = _array[_size - 1];
return true;
}
item = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly T Pop()
{
if (_size == 0)
{
Throw.InvalidOperationException("stack is empty");
}
_size--;
return ref _array[_size];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Push(in T item)
{
if (_size == _array.Length)
{
EnsureCapacity(_size + 1);
}
_array[_size++] = item;
}
private void EnsureCapacity(int min)
{
var array = _array;
if (array.Length < min)
{
var newCapacity = array.Length == 0
? DefaultCapacity
: array.Length * 2;
if (newCapacity < min)
{
newCapacity = min;
}
Resize(newCapacity);
}
}
private void Resize(int value)
{
if (value != _array.Length)
{
if (value > 0)
{
var newItems = new T[value];
if (_size > 0)
{
Array.Copy(_array, 0, newItems, 0, _size);
}
_array = newItems;
}
else
{
_array = [];
}
}
}
public void Clear()
{
_size = 0;
}
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
internal struct Enumerator : IEnumerator
{
private readonly RefStack _stack;
private int _index;
private T? _currentElement;
internal Enumerator(RefStack stack)
{
_stack = stack;
_index = -2;
_currentElement = default;
}
public void Dispose()
{
_index = -1;
}
public bool MoveNext()
{
bool returnValue;
if (_index == -2)
{
// First call to enumerator.
_index = _stack._size - 1;
returnValue = (_index >= 0);
if (returnValue)
{
_currentElement = _stack._array[_index];
}
return returnValue;
}
if (_index == -1)
{
// End of enumeration.
return false;
}
returnValue = (--_index >= 0);
if (returnValue)
{
_currentElement = _stack._array[_index];
}
else
{
_currentElement = default;
}
return returnValue;
}
public T Current => (T) _currentElement!;
object? IEnumerator.Current => Current;
void IEnumerator.Reset()
{
_index = -2;
_currentElement = default;
}
}
}