using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections.Contracts; using Misaki.HighPerformance.LowLevel.Utilities; using System.Collections; using System.Diagnostics; using System.Runtime.CompilerServices; namespace Misaki.HighPerformance.LowLevel.Collections; internal class UnsafeStackDebugView where T : unmanaged { private readonly UnsafeStack _stack; public UnsafeStackDebugView(UnsafeStack stack) { _stack = stack; } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public unsafe T[] Items { get { var items = new T[_stack.Count]; var pItems = (T*)_stack.GetUnsafePtr(); for (int i = 0; i < _stack.Count; i++) { items[i] = pItems[i]; } return items; } } } /// /// 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. [DebuggerTypeProxy(typeof(UnsafeStackDebugView<>))] public unsafe struct UnsafeStack : IUnsafeCollection where T : unmanaged { public struct Enumerator : IEnumerator { private readonly UnsafeStack* _collection; private int _index; public readonly ref T Current => ref _collection->_array[_index]; readonly T IEnumerator.Current => Current; readonly object IEnumerator.Current => Current; public Enumerator(UnsafeStack* collection) { _collection = collection; _index = collection->Count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { _index--; return _index >= 0; } public void Reset() { _index = _collection->Count; } public readonly void Dispose() { } } private UnsafeArray _array; private int _count; public readonly int Count => _count; public readonly int Capacity => _array.Count; public readonly bool IsCreated => _array.IsCreated; public Enumerator GetEnumerator() => new((UnsafeStack*)UnsafeUtility.AddressOf(ref this)); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => 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 capacity, AllocationHandle handle, AllocationOption allocationOption = AllocationOption.None) { _array = new UnsafeArray(capacity, 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 capacity, Allocator allocator, AllocationOption allocationOption = AllocationOption.None) : this(capacity, 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 >= Capacity) { Resize(Math.Max(1, Capacity * 2)); } UnsafeUtility.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, AllocationOption option = AllocationOption.None) { _array.Resize(newSize, option); 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; } }