Mirror of Svelto.ECS because we're a fan of it
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

204 lines
5.9KB

  1. #if DEBUG && !PROFILE_SVELTO
  2. #define ENABLE_DEBUG_CHECKS
  3. #endif
  4. using System;
  5. using System.Diagnostics;
  6. using System.Runtime.CompilerServices;
  7. using Svelto.Common;
  8. using Svelto.Common.DataStructures;
  9. namespace Svelto.ECS.DataStructures
  10. {
  11. /// <summary>
  12. /// Burst friendly RingBuffer on steroid:
  13. /// it can: Enqueue/Dequeue, it wraps around if there is enough space after dequeuing
  14. /// It resizes if there isn't enough space left.
  15. /// It's a "bag", you can queue and dequeue any type and mix them. Just be sure that you dequeue what you queue! No check on type
  16. /// is done.
  17. /// You can reserve a position in the queue to update it later.
  18. /// The datastructure is a struct and it's "copiable"
  19. /// I eventually decided to call it NativeBag and not NativeBag because it can also be used as
  20. /// a preallocated memory pool where any kind of T can be stored as long as T is unmanaged
  21. /// </summary>
  22. public struct NativeBag : IDisposable
  23. {
  24. public uint count
  25. {
  26. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  27. get
  28. {
  29. unsafe
  30. {
  31. BasicTests();
  32. using (_threadSentinel.TestThreadSafety())
  33. {
  34. return _queue->size;
  35. }
  36. }
  37. }
  38. }
  39. public uint capacity
  40. {
  41. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  42. get
  43. {
  44. unsafe
  45. {
  46. BasicTests();
  47. using (_threadSentinel.TestThreadSafety())
  48. {
  49. return _queue->capacity;
  50. }
  51. }
  52. }
  53. }
  54. public NativeBag(Allocator allocator):this()
  55. {
  56. unsafe
  57. {
  58. var listData = (UnsafeBlob*)MemoryUtilities.Alloc<UnsafeBlob>((uint)1, allocator);
  59. listData->allocator = allocator;
  60. _queue = listData;
  61. }
  62. }
  63. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  64. public bool IsEmpty()
  65. {
  66. unsafe
  67. {
  68. BasicTests();
  69. using (_threadSentinel.TestThreadSafety())
  70. {
  71. if (_queue == null || _queue->ptr == null)
  72. return true;
  73. }
  74. }
  75. return count == 0;
  76. }
  77. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  78. public unsafe void Dispose()
  79. {
  80. if (_queue != null)
  81. {
  82. BasicTests();
  83. using (_threadSentinel.TestThreadSafety())
  84. {
  85. _queue->Dispose();
  86. MemoryUtilities.Free((IntPtr)_queue, _queue->allocator);
  87. _queue = null;
  88. }
  89. }
  90. }
  91. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  92. public ref T ReserveEnqueue<T>
  93. (out UnsafeArrayIndex index)
  94. where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints.
  95. {
  96. unsafe
  97. {
  98. BasicTests();
  99. var sizeOf = MemoryUtilities.SizeOf<T>();
  100. using (_threadSentinel.TestThreadSafety())
  101. {
  102. if (_queue->availableSpace - sizeOf < 0)
  103. {
  104. _queue->Grow<T>();
  105. }
  106. return ref _queue->Reserve<T>(out index);
  107. }
  108. }
  109. }
  110. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  111. public void Enqueue<T>
  112. (in T item) where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints.
  113. {
  114. unsafe
  115. {
  116. BasicTests();
  117. using (_threadSentinel.TestThreadSafety())
  118. {
  119. var sizeOf = MemoryUtilities.SizeOf<T>();
  120. if (_queue->availableSpace - sizeOf < 0)
  121. {
  122. _queue->Grow<T>();
  123. }
  124. _queue->Enqueue(item);
  125. }
  126. }
  127. }
  128. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  129. public void Clear()
  130. {
  131. unsafe
  132. {
  133. BasicTests();
  134. using (_threadSentinel.TestThreadSafety())
  135. {
  136. _queue->Clear();
  137. }
  138. }
  139. }
  140. public T Dequeue<T>() where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints.
  141. {
  142. unsafe
  143. {
  144. BasicTests();
  145. using (_threadSentinel.TestThreadSafety())
  146. {
  147. return _queue->Dequeue<T>();
  148. }
  149. }
  150. }
  151. public ref T AccessReserved<T>(UnsafeArrayIndex reservedIndex) where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints.
  152. {
  153. unsafe
  154. {
  155. BasicTests();
  156. using (_threadSentinel.TestThreadSafety())
  157. {
  158. return ref _queue->AccessReserved<T>(reservedIndex);
  159. }
  160. }
  161. }
  162. [Conditional("ENABLE_DEBUG_CHECKS")]
  163. unsafe void BasicTests()
  164. {
  165. if (_queue == null)
  166. throw new Exception("SimpleNativeArray: null-access");
  167. }
  168. readonly Sentinel _threadSentinel;
  169. #if UNITY_COLLECTIONS || UNITY_JOBS || UNITY_BURST
  170. #if UNITY_BURST
  171. [Unity.Burst.NoAlias]
  172. #endif
  173. [Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction]
  174. #endif
  175. unsafe UnsafeBlob* _queue;
  176. }
  177. }