LuaStack.cs 4.0 KB

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