LuaStack.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. using System.Runtime.CompilerServices;
  2. using System.Runtime.InteropServices;
  3. using Lua.Internal;
  4. namespace Lua.Runtime;
  5. public sealed class LuaStack(int initialSize = 256)
  6. {
  7. LuaValue[] array = new LuaValue[initialSize];
  8. int top;
  9. public int Count => top;
  10. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  11. public void EnsureCapacity(int newSize)
  12. {
  13. if (array.Length >= newSize) return;
  14. Resize(ref array, newSize);
  15. return;
  16. static void Resize(ref LuaValue[] array, int newSize)
  17. {
  18. var size = array.Length;
  19. while (size < newSize)
  20. {
  21. size *= 2;
  22. }
  23. Array.Resize(ref array, size);
  24. }
  25. }
  26. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  27. public void NotifyTop(int top)
  28. {
  29. if (this.top < top) this.top = top;
  30. }
  31. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  32. public void Push(LuaValue value)
  33. {
  34. EnsureCapacity(top + 1);
  35. array[top] = value;
  36. top++;
  37. }
  38. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  39. public void PushRange(ReadOnlySpan<LuaValue> values)
  40. {
  41. EnsureCapacity(top + values.Length);
  42. values.CopyTo(array.AsSpan()[top..]);
  43. top += values.Length;
  44. }
  45. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  46. public LuaValue Pop()
  47. {
  48. if (top == 0) ThrowEmptyStack();
  49. top--;
  50. var item = array[top];
  51. array[top] = default;
  52. return item;
  53. }
  54. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  55. public void PopUntil(int newSize)
  56. {
  57. if (newSize >= top) return;
  58. array.AsSpan(newSize,top-newSize).Clear();
  59. top = newSize;
  60. }
  61. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  62. public void Clear()
  63. {
  64. array.AsSpan().Clear();
  65. top = 0;
  66. }
  67. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  68. public Span<LuaValue> AsSpan()
  69. {
  70. return new Span<LuaValue>(array, 0, top);
  71. }
  72. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  73. public Span<LuaValue> GetBuffer()
  74. {
  75. return array.AsSpan();
  76. }
  77. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  78. public Memory<LuaValue> GetBufferMemory()
  79. {
  80. return array.AsMemory();
  81. }
  82. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  83. public ref LuaValue UnsafeGet(int index)
  84. {
  85. return ref MemoryMarshalEx.UnsafeElementAt(array, index);
  86. }
  87. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  88. internal ref LuaValue Get(int index)
  89. {
  90. return ref array[index];
  91. }
  92. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  93. internal ref LuaValue FastGet(int index)
  94. {
  95. #if NET6_0_OR_GREATER
  96. return ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), index);
  97. #endif
  98. return ref array[index];
  99. }
  100. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  101. internal ref LuaValue GetWithNotifyTop(int index)
  102. {
  103. if (this.top <= index) this.top = index + 1;
  104. return ref array[index];
  105. }
  106. static void ThrowEmptyStack()
  107. {
  108. throw new InvalidOperationException("Empty stack");
  109. }
  110. }