RefStack.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. using System.Collections;
  2. using System.Diagnostics.CodeAnalysis;
  3. using System.Runtime.CompilerServices;
  4. using Jint.Runtime;
  5. namespace Jint.Collections;
  6. /// <summary>
  7. /// Stack for struct types.
  8. /// </summary>
  9. internal sealed class RefStack<T> : IEnumerable<T> where T : struct
  10. {
  11. internal T[] _array;
  12. internal int _size;
  13. private const int DefaultCapacity = 2;
  14. public RefStack(int capacity = DefaultCapacity)
  15. {
  16. _array = new T[capacity];
  17. _size = 0;
  18. }
  19. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  20. public ref readonly T Peek()
  21. {
  22. return ref _array[_size - 1];
  23. }
  24. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  25. public ref readonly T Peek(int fromTop)
  26. {
  27. var index = _size - 1 - fromTop;
  28. return ref _array[index];
  29. }
  30. public T this[int index] => _array[index];
  31. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  32. public bool TryPeek([NotNullWhen(true)] out T item)
  33. {
  34. if (_size > 0)
  35. {
  36. item = _array[_size - 1];
  37. return true;
  38. }
  39. item = default;
  40. return false;
  41. }
  42. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  43. public ref readonly T Pop()
  44. {
  45. if (_size == 0)
  46. {
  47. Throw.InvalidOperationException("stack is empty");
  48. }
  49. _size--;
  50. return ref _array[_size];
  51. }
  52. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  53. public void Push(in T item)
  54. {
  55. if (_size == _array.Length)
  56. {
  57. EnsureCapacity(_size + 1);
  58. }
  59. _array[_size++] = item;
  60. }
  61. private void EnsureCapacity(int min)
  62. {
  63. var array = _array;
  64. if (array.Length < min)
  65. {
  66. var newCapacity = array.Length == 0
  67. ? DefaultCapacity
  68. : array.Length * 2;
  69. if (newCapacity < min)
  70. {
  71. newCapacity = min;
  72. }
  73. Resize(newCapacity);
  74. }
  75. }
  76. private void Resize(int value)
  77. {
  78. if (value != _array.Length)
  79. {
  80. if (value > 0)
  81. {
  82. var newItems = new T[value];
  83. if (_size > 0)
  84. {
  85. Array.Copy(_array, 0, newItems, 0, _size);
  86. }
  87. _array = newItems;
  88. }
  89. else
  90. {
  91. _array = [];
  92. }
  93. }
  94. }
  95. public void Clear()
  96. {
  97. _size = 0;
  98. }
  99. public Enumerator GetEnumerator()
  100. {
  101. return new Enumerator(this);
  102. }
  103. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  104. {
  105. return GetEnumerator();
  106. }
  107. IEnumerator IEnumerable.GetEnumerator()
  108. {
  109. return GetEnumerator();
  110. }
  111. internal struct Enumerator : IEnumerator<T>
  112. {
  113. private readonly RefStack<T> _stack;
  114. private int _index;
  115. private T? _currentElement;
  116. internal Enumerator(RefStack<T> stack)
  117. {
  118. _stack = stack;
  119. _index = -2;
  120. _currentElement = default;
  121. }
  122. public void Dispose()
  123. {
  124. _index = -1;
  125. }
  126. public bool MoveNext()
  127. {
  128. bool returnValue;
  129. if (_index == -2)
  130. {
  131. // First call to enumerator.
  132. _index = _stack._size - 1;
  133. returnValue = (_index >= 0);
  134. if (returnValue)
  135. {
  136. _currentElement = _stack._array[_index];
  137. }
  138. return returnValue;
  139. }
  140. if (_index == -1)
  141. {
  142. // End of enumeration.
  143. return false;
  144. }
  145. returnValue = (--_index >= 0);
  146. if (returnValue)
  147. {
  148. _currentElement = _stack._array[_index];
  149. }
  150. else
  151. {
  152. _currentElement = default;
  153. }
  154. return returnValue;
  155. }
  156. public T Current => (T) _currentElement!;
  157. object? IEnumerator.Current => Current;
  158. void IEnumerator.Reset()
  159. {
  160. _index = -2;
  161. _currentElement = default;
  162. }
  163. }
  164. }