ReversedStack.cs 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. namespace Lua.Internal;
  2. internal sealed class ReversedStack<T>(int capacity = 16)
  3. {
  4. T[] buffer = new T[capacity];
  5. int tail = capacity;
  6. public int Length => buffer.Length - tail;
  7. public Span<T> AsSpan()
  8. {
  9. return buffer.AsSpan(tail, buffer.Length - tail);
  10. }
  11. public void Push(T element)
  12. {
  13. EnsureAdditionalCapacity(1);
  14. buffer[--tail] = element;
  15. }
  16. public void Push(ReadOnlySpan<T> elements)
  17. {
  18. if (elements.Length == 0) return;
  19. EnsureAdditionalCapacity(elements.Length);
  20. tail -= elements.Length;
  21. elements.CopyTo(buffer.AsSpan(tail));
  22. }
  23. public T Pop()
  24. {
  25. if (IsEmpty)
  26. {
  27. ThrowEmpty();
  28. }
  29. static void ThrowEmpty() => throw new InvalidOperationException("Cannot pop an empty stack");
  30. return buffer[tail++];
  31. }
  32. public void Pop(int count)
  33. {
  34. if (count > buffer.Length - tail)
  35. {
  36. ThrowEmpty();
  37. }
  38. static void ThrowEmpty() => throw new InvalidOperationException("Cannot pop more elements than exist in the stack");
  39. tail += count;
  40. }
  41. public void TryPop(out T? element)
  42. {
  43. if (IsEmpty)
  44. {
  45. element = default!;
  46. return;
  47. }
  48. element = buffer[tail++];
  49. }
  50. public void Clear()
  51. {
  52. tail = buffer.Length;
  53. }
  54. public bool IsEmpty => tail == buffer.Length;
  55. public T Peek()
  56. {
  57. if (IsEmpty)
  58. {
  59. ThrowEmpty();
  60. }
  61. static void ThrowEmpty() => throw new InvalidOperationException("Cannot peek an empty stack");
  62. return buffer[tail];
  63. }
  64. void EnsureAdditionalCapacity(int required)
  65. {
  66. if (tail >= required) return;
  67. Resize(required - tail + buffer.Length);
  68. void Resize(int requiredCapacity)
  69. {
  70. int newCapacity = buffer.Length * 2;
  71. while (newCapacity < requiredCapacity)
  72. {
  73. newCapacity *= 2;
  74. }
  75. T[] newBuffer = new T[newCapacity];
  76. AsSpan().CopyTo(newBuffer.AsSpan(newCapacity - buffer.Length));
  77. tail = newCapacity - (buffer.Length - tail);
  78. buffer = newBuffer;
  79. }
  80. }
  81. }