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; } }