using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections.Contracts;
using Misaki.HighPerformance.LowLevel.Contracts;
using Misaki.HighPerformance.LowLevel.Utilities;
using System.Collections;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.LowLevel.Collections;
///
/// Provides a high-performance, unsafe stack data structure for unmanaged types, supporting manual memory management
/// and allocation control.
///
/// The type of elements stored in the stack. Must be an unmanaged type.
public unsafe struct UnsafeStack : IUnsafeCollection
where T : unmanaged
{
private UnsafeArray _array;
private int _count;
public readonly int Count => _count;
public readonly bool IsCreated => _array.IsCreated;
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
///
/// Invalid constructor, use or instead.
///
public UnsafeStack()
: this(0, Allocator.Invalid)
{
}
///
/// Initializes a new instance of the UnsafeStack class with the specified initial capacity and allocation options.
///
/// The number of elements the stack can initially hold. Must be greater than zero.
/// A reference to an AllocationHandle used to manage the underlying memory allocation for the stack.
/// Specifies additional options for memory allocation. The default is AllocationOption.None.
public UnsafeStack(int initialCapacity, ref AllocationHandle handle, AllocationOption allocationOption = AllocationOption.None)
{
_array = new UnsafeArray(initialCapacity, ref handle, allocationOption);
}
///
/// Initializes a new instance of the UnsafeStack class with the specified initial capacity, allocator, and
/// allocation options.
///
/// The initial number of elements that the stack can hold. Must be greater than zero.
/// The allocator to use for memory management of the stack's storage.
/// The allocation option that determines how memory is allocated for the stack. The default is AllocationOption.None.
public UnsafeStack(int initialCapacity, Allocator allocator, AllocationOption allocationOption = AllocationOption.None)
: this(initialCapacity, ref AllocationManager.GetAllocationHandle(allocator), allocationOption)
{
}
///
/// Adds an element to the top of the stack.
///
/// The element to add to the stack.
public void Push(T value)
{
if (_count >= _array.Count)
{
Resize(_array.Count + (int)(_array.Count * 0.5f));
}
UnsafeUtilities.WriteArrayElement(_array.GetUnsafePtr(), _count, value);
_count++;
}
///
/// Removes and returns the object at the top of the stack.
///
/// The object removed from the top of the stack.
/// Thrown when the stack is empty.
public T Pop()
{
if (_count == 0)
{
throw new InvalidOperationException("Stack is empty.");
}
_count--;
return _array[_count];
}
///
/// Attempts to remove and return the object at the top of the stack.
///
/// When this method returns, contains the object removed from the top of the stack, if the operation succeeded;
/// otherwise, the default value of .
/// true if an object was successfully removed and returned from the stack; otherwise, false.
public bool TryPop(out T value)
{
if (_count == 0)
{
value = default;
return false;
}
_count--;
value = _array[_count];
return true;
}
///
/// Returns the item at the top of the stack without removing it.
///
/// The item of type at the top of the stack.
/// Thrown when the stack is empty.
public readonly T Peek()
{
if (_count == 0)
{
throw new InvalidOperationException("Stack is empty.");
}
return _array[_count - 1];
}
public void Resize(int newSize)
{
_array.Resize(newSize);
if (_count > newSize)
{
_count = newSize;
}
}
public void Clear()
{
_array.Clear();
_count = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly void* GetUnsafePtr()
{
return _array.GetUnsafePtr();
}
public void Dispose()
{
_array.Dispose();
_count = 0;
}
}