FastListCore.cs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. using System.Runtime.CompilerServices;
  2. using System.Runtime.InteropServices;
  3. namespace Lua.Internal;
  4. /// <summary>
  5. /// A list of minimal features. Note that it is NOT thread-safe and must NOT be marked readonly as it is a mutable struct.
  6. /// </summary>
  7. /// <typeparam name="T">Element type</typeparam>
  8. [StructLayout(LayoutKind.Auto)]
  9. public struct FastListCore<T>
  10. {
  11. const int InitialCapacity = 8;
  12. public static readonly FastListCore<T> Empty = default;
  13. T[]? array;
  14. int tailIndex;
  15. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  16. public void Add(T element)
  17. {
  18. if (array == null)
  19. {
  20. array = new T[InitialCapacity];
  21. }
  22. else if (array.Length == tailIndex)
  23. {
  24. Array.Resize(ref array, tailIndex * 2);
  25. }
  26. array[tailIndex] = element;
  27. tailIndex++;
  28. }
  29. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  30. public void Pop()
  31. {
  32. CheckIndex(tailIndex - 1);
  33. array![tailIndex - 1] = default!;
  34. tailIndex--;
  35. }
  36. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  37. public void RemoveAtSwapBack(int index)
  38. {
  39. CheckIndex(index);
  40. array![index] = array[tailIndex - 1];
  41. array[tailIndex - 1] = default!;
  42. tailIndex--;
  43. }
  44. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  45. public void Shrink(int newSize)
  46. {
  47. if (newSize >= tailIndex) return;
  48. array.AsSpan(newSize).Clear();
  49. tailIndex = newSize;
  50. }
  51. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  52. public void Clear(bool removeArray = false)
  53. {
  54. if (array == null) return;
  55. array.AsSpan().Clear();
  56. tailIndex = 0;
  57. if (removeArray) array = null;
  58. }
  59. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  60. public void EnsureCapacity(int capacity)
  61. {
  62. if (array == null)
  63. {
  64. array = new T[InitialCapacity];
  65. }
  66. while (array.Length < capacity)
  67. {
  68. Array.Resize(ref array, array.Length * 2);
  69. }
  70. }
  71. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  72. public void CopyTo(ref FastListCore<T> destination)
  73. {
  74. destination.EnsureCapacity(tailIndex);
  75. destination.tailIndex = tailIndex;
  76. AsSpan().CopyTo(destination.AsSpan());
  77. }
  78. public ref T this[int index]
  79. {
  80. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  81. get => ref array![index];
  82. }
  83. public readonly int Length
  84. {
  85. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  86. get => tailIndex;
  87. }
  88. public readonly Span<T> AsSpan() => array == null ? Span<T>.Empty : array.AsSpan(0, tailIndex);
  89. public readonly T[]? AsArray() => array;
  90. readonly void CheckIndex(int index)
  91. {
  92. if (array == null||index < 0 || index > tailIndex) ThrowIndexOutOfRange();
  93. }
  94. static void ThrowIndexOutOfRange() => throw new IndexOutOfRangeException();
  95. }