Mirror of Svelto.ECS because we're a fan of it
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

516 řádky
15KB

  1. #if DEBUG && !PROFILE_SVELTO
  2. #define ENABLE_DEBUG_CHECKS
  3. #endif
  4. using System;
  5. using System.Runtime.CompilerServices;
  6. using Svelto.Common;
  7. using Svelto.Common.DataStructures;
  8. using Allocator = Svelto.Common.Allocator;
  9. namespace Svelto.ECS.DataStructures
  10. {
  11. public struct NativeDynamicArray : IDisposable
  12. {
  13. public bool isValid
  14. {
  15. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  16. get
  17. {
  18. unsafe
  19. {
  20. return _list != null;
  21. }
  22. }
  23. }
  24. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  25. public int Count<T>() where T : struct
  26. {
  27. unsafe
  28. {
  29. #if ENABLE_DEBUG_CHECKS
  30. if (_list == null)
  31. throw new Exception("NativeDynamicArray: null-access");
  32. if (_hashType != TypeHash<T>.hash)
  33. throw new Exception($"NativeDynamicArray: not expected type used");
  34. #endif
  35. return (_list->count / MemoryUtilities.SizeOf<T>());
  36. }
  37. }
  38. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  39. public int SizeInBytes()
  40. {
  41. unsafe
  42. {
  43. #if ENABLE_DEBUG_CHECKS
  44. if (_list == null)
  45. throw new Exception("NativeDynamicArray: null-access");
  46. #endif
  47. return (_list->count);
  48. }
  49. }
  50. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  51. public int Capacity<T>() where T : struct
  52. {
  53. unsafe
  54. {
  55. #if ENABLE_DEBUG_CHECKS
  56. if (_list == null)
  57. throw new Exception("NativeDynamicArray: null-access");
  58. if (_hashType != TypeHash<T>.hash)
  59. throw new Exception("NativeDynamicArray: not expected type used");
  60. #endif
  61. return (_list->capacity / MemoryUtilities.SizeOf<T>());
  62. }
  63. }
  64. public static NativeDynamicArray Alloc<T>(uint newLength = 0) where T : struct
  65. {
  66. return Alloc<T>(Allocator.Persistent, newLength);
  67. }
  68. public static NativeDynamicArray Alloc<T>(Allocator allocator, uint newLength = 0) where T : struct
  69. {
  70. unsafe
  71. {
  72. #if ENABLE_DEBUG_CHECKS
  73. var rtnStruc = new NativeDynamicArray
  74. {
  75. _hashType = TypeHash<T>.hash,
  76. };
  77. #else
  78. NativeDynamicArray rtnStruc = default;
  79. #endif
  80. UnsafeArray* listData = (UnsafeArray*)MemoryUtilities.Alloc<UnsafeArray>(1, allocator);
  81. //clear to nullify the pointers
  82. //MemoryUtilities.MemClear((IntPtr) listData, structSize);
  83. rtnStruc._allocator = allocator;
  84. listData->Realloc<T>(newLength, allocator);
  85. rtnStruc._list = listData;
  86. return rtnStruc;
  87. }
  88. }
  89. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  90. public ref T Get<T>(uint index) where T : struct
  91. {
  92. unsafe
  93. {
  94. #if ENABLE_DEBUG_CHECKS
  95. if (_list == null)
  96. throw new Exception("NativeDynamicArray: null-access");
  97. if (_hashType != TypeHash<T>.hash)
  98. throw new Exception("NativeDynamicArray: not expected type used");
  99. if (index >= Count<T>())
  100. throw new Exception($"NativeDynamicArray: out of bound access, index {index} count {Count<T>()}");
  101. #endif
  102. #if ENABLE_DEBUG_CHECKS
  103. using (_threadSentinel.TestThreadSafety())
  104. {
  105. #endif
  106. return ref _list->Get<T>(index);
  107. #if ENABLE_DEBUG_CHECKS
  108. }
  109. #endif
  110. }
  111. }
  112. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  113. public ref T Get<T>(int index) where T : struct
  114. {
  115. return ref Get<T>((uint)index);
  116. }
  117. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  118. public void Set<T>(uint index, in T value) where T : struct
  119. {
  120. unsafe
  121. {
  122. #if ENABLE_DEBUG_CHECKS
  123. if (_list == null)
  124. throw new Exception("NativeDynamicArray: null-access");
  125. if (_hashType != TypeHash<T>.hash)
  126. throw new Exception("NativeDynamicArray: not expected type used");
  127. if (index >= Capacity<T>())
  128. throw new Exception(
  129. $"NativeDynamicArray: out of bound access, index {index} capacity {Capacity<T>()}");
  130. #endif
  131. #if ENABLE_DEBUG_CHECKS
  132. using (_threadSentinel.TestThreadSafety())
  133. {
  134. #endif
  135. _list->Set(index, value);
  136. #if ENABLE_DEBUG_CHECKS
  137. }
  138. #endif
  139. }
  140. }
  141. public unsafe void Dispose()
  142. {
  143. #if ENABLE_DEBUG_CHECKS
  144. if (_list == null)
  145. throw new Exception("NativeDynamicArray: null-access");
  146. #endif
  147. #if ENABLE_DEBUG_CHECKS
  148. using (_threadSentinel.TestThreadSafety())
  149. {
  150. #endif
  151. _list->Dispose(_allocator);
  152. MemoryUtilities.Free((IntPtr)_list, _allocator);
  153. #if ENABLE_DEBUG_CHECKS
  154. }
  155. #endif
  156. _list = null;
  157. }
  158. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  159. public void Add<T>(in T item) where T : struct
  160. {
  161. unsafe
  162. {
  163. #if ENABLE_DEBUG_CHECKS
  164. if (_list == null)
  165. throw new Exception("NativeDynamicArray: null-access");
  166. if (_hashType != TypeHash<T>.hash)
  167. throw new Exception("NativeDynamicArray: not expected type used");
  168. #endif
  169. #if ENABLE_DEBUG_CHECKS
  170. using (_threadSentinel.TestThreadSafety())
  171. {
  172. #endif
  173. if (Count<T>() == Capacity<T>())
  174. {
  175. _list->Realloc<T>((uint)((Capacity<T>() + 1) * 1.5f), _allocator);
  176. }
  177. _list->Add(item);
  178. #if ENABLE_DEBUG_CHECKS
  179. }
  180. #endif
  181. }
  182. }
  183. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  184. public ref T AddAt<T>(uint index) where T : struct
  185. {
  186. unsafe
  187. {
  188. #if ENABLE_DEBUG_CHECKS
  189. if (_list == null)
  190. throw new Exception("NativeDynamicArray: null-access");
  191. if (_hashType != TypeHash<T>.hash)
  192. throw new Exception("NativeDynamicArray: not expected type used");
  193. #endif
  194. var structSize = (uint)MemoryUtilities.SizeOf<T>();
  195. #if ENABLE_DEBUG_CHECKS
  196. using (_threadSentinel.TestThreadSafety())
  197. {
  198. #endif
  199. if (index >= Capacity<T>())
  200. _list->Realloc<T>((uint)((index + 1) * 1.5f), _allocator);
  201. var writeIndex = (index + 1) * structSize;
  202. if (_list->count < writeIndex)
  203. _list->SetCountTo(writeIndex);
  204. return ref _list->Get<T>(index);
  205. #if ENABLE_DEBUG_CHECKS
  206. }
  207. #endif
  208. }
  209. }
  210. public void Resize<T>(uint newCapacity) where T : struct
  211. {
  212. unsafe
  213. {
  214. #if ENABLE_DEBUG_CHECKS
  215. if (_list == null)
  216. throw new Exception("NativeDynamicArray: null-access");
  217. if (_hashType != TypeHash<T>.hash)
  218. throw new Exception("NativeDynamicArray: not expected type used");
  219. #endif
  220. #if ENABLE_DEBUG_CHECKS
  221. using (_threadSentinel.TestThreadSafety())
  222. {
  223. #endif
  224. _list->Realloc<T>((uint)newCapacity, _allocator);
  225. #if ENABLE_DEBUG_CHECKS
  226. }
  227. #endif
  228. }
  229. }
  230. public void SetCount<T>(uint count) where T : struct
  231. {
  232. unsafe
  233. {
  234. #if ENABLE_DEBUG_CHECKS
  235. if (_list == null)
  236. throw new Exception("NativeDynamicArray: null-access");
  237. if (_hashType != TypeHash<T>.hash)
  238. throw new Exception("NativeDynamicArray: not expected type used");
  239. #endif
  240. uint structSize = (uint)MemoryUtilities.SizeOf<T>();
  241. uint size = (uint)(count * structSize);
  242. #if ENABLE_DEBUG_CHECKS
  243. using (_threadSentinel.TestThreadSafety())
  244. {
  245. #endif
  246. _list->SetCountTo((uint)size);
  247. #if ENABLE_DEBUG_CHECKS
  248. }
  249. #endif
  250. }
  251. }
  252. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  253. public void AddWithoutGrow<T>(in T item) where T : struct
  254. {
  255. unsafe
  256. {
  257. #if ENABLE_DEBUG_CHECKS
  258. if (_list == null)
  259. throw new Exception("NativeDynamicArray: null-access");
  260. if (_hashType != TypeHash<T>.hash)
  261. throw new Exception("NativeDynamicArray: not expected type used");
  262. var structSize = (uint)MemoryUtilities.SizeOf<T>();
  263. if (_list->space - (int)structSize < 0)
  264. throw new Exception("NativeDynamicArray: no writing authorized");
  265. #endif
  266. #if ENABLE_DEBUG_CHECKS
  267. using (_threadSentinel.TestThreadSafety())
  268. {
  269. #endif
  270. _list->Add(item);
  271. #if ENABLE_DEBUG_CHECKS
  272. }
  273. #endif
  274. }
  275. }
  276. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  277. public void UnorderedRemoveAt<T>(uint index) where T : struct
  278. {
  279. unsafe
  280. {
  281. #if ENABLE_DEBUG_CHECKS
  282. if (_list == null)
  283. throw new Exception("NativeDynamicArray: null-access");
  284. if (_hashType != TypeHash<T>.hash)
  285. throw new Exception("NativeDynamicArray: not expected type used");
  286. if (Count<T>() == 0)
  287. throw new Exception("NativeDynamicArray: empty array invalid operation");
  288. #endif
  289. #if ENABLE_DEBUG_CHECKS
  290. using (_threadSentinel.TestThreadSafety())
  291. {
  292. #endif
  293. var indexToMove = Count<T>() - 1;
  294. if (index < indexToMove)
  295. {
  296. Set<T>(index, Get<T>((uint)indexToMove));
  297. }
  298. _list->Pop<T>();
  299. #if ENABLE_DEBUG_CHECKS
  300. }
  301. #endif
  302. }
  303. }
  304. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  305. public void FastClear()
  306. {
  307. unsafe
  308. {
  309. #if ENABLE_DEBUG_CHECKS
  310. if (_list == null)
  311. throw new Exception("NativeDynamicArray: null-access");
  312. #endif
  313. #if ENABLE_DEBUG_CHECKS
  314. using (_threadSentinel.TestThreadSafety())
  315. {
  316. #endif
  317. _list->Clear();
  318. #if ENABLE_DEBUG_CHECKS
  319. }
  320. #endif
  321. }
  322. }
  323. public unsafe T* ToPTR<T>() where T : unmanaged
  324. {
  325. #if ENABLE_DEBUG_CHECKS
  326. if (_list == null)
  327. throw new Exception("NativeDynamicArray: null-access");
  328. if (_hashType != TypeHash<T>.hash)
  329. throw new Exception("NativeDynamicArray: not expected type used");
  330. #endif
  331. return (T*)_list->ptr;
  332. }
  333. public IntPtr ToIntPTR<T>() where T : struct
  334. {
  335. unsafe
  336. {
  337. #if ENABLE_DEBUG_CHECKS
  338. if (_list == null)
  339. throw new Exception("NativeDynamicArray: null-access");
  340. if (_hashType != TypeHash<T>.hash)
  341. throw new Exception("NativeDynamicArray: not expected type used");
  342. #endif
  343. return (IntPtr)_list->ptr;
  344. }
  345. }
  346. public T[] ToManagedArray<T>() where T : unmanaged
  347. {
  348. unsafe
  349. {
  350. #if ENABLE_DEBUG_CHECKS
  351. if (_list == null)
  352. throw new Exception("NativeDynamicArray: null-access");
  353. if (_hashType != TypeHash<T>.hash)
  354. throw new Exception("NativeDynamicArray: not expected type used");
  355. #endif
  356. var count = Count<T>();
  357. var ret = new T[count];
  358. var lengthToCopyInBytes = count * MemoryUtilities.SizeOf<T>();
  359. #if ENABLE_DEBUG_CHECKS
  360. using (_threadSentinel.TestThreadSafety())
  361. {
  362. #endif
  363. fixed (void* handle = ret)
  364. {
  365. Unsafe.CopyBlock(handle, _list->ptr, (uint)lengthToCopyInBytes);
  366. }
  367. return ret;
  368. #if ENABLE_DEBUG_CHECKS
  369. }
  370. #endif
  371. }
  372. }
  373. public T[] ToManagedArrayUntrimmed<T>() where T : unmanaged
  374. {
  375. unsafe
  376. {
  377. #if ENABLE_DEBUG_CHECKS
  378. if (_list == null)
  379. throw new Exception("NativeDynamicArray: null-access");
  380. if (_hashType != TypeHash<T>.hash)
  381. throw new Exception("NativeDynamicArray: not expected type used");
  382. #endif
  383. var capacity = Capacity<T>();
  384. var ret = new T[capacity];
  385. #if ENABLE_DEBUG_CHECKS
  386. using (_threadSentinel.TestThreadSafety())
  387. {
  388. #endif
  389. fixed (void* handle = ret)
  390. {
  391. MemoryUtilities.MemCpy<T>((IntPtr)_list->ptr, 0, (IntPtr)handle, 0, (uint)capacity);
  392. }
  393. #if ENABLE_DEBUG_CHECKS
  394. }
  395. #endif
  396. return ret;
  397. }
  398. }
  399. public void RemoveAt<T>(uint index) where T : struct
  400. {
  401. unsafe
  402. {
  403. #if ENABLE_DEBUG_CHECKS
  404. if (_list == null)
  405. throw new Exception("NativeDynamicArray: null-access");
  406. if (_hashType != TypeHash<T>.hash)
  407. throw new Exception("NativeDynamicArray: not expected type used");
  408. #endif
  409. #if ENABLE_DEBUG_CHECKS
  410. using (_threadSentinel.TestThreadSafety())
  411. {
  412. #endif
  413. MemoryUtilities.MemMove<T>((IntPtr)_list->ptr, index + 1, index, (uint)(Count<T>() - (index + 1)));
  414. _list->Pop<T>();
  415. #if ENABLE_DEBUG_CHECKS
  416. }
  417. #endif
  418. }
  419. }
  420. public void MemClear()
  421. {
  422. unsafe
  423. {
  424. #if ENABLE_DEBUG_CHECKS
  425. using (_threadSentinel.TestThreadSafety())
  426. {
  427. #endif
  428. MemoryUtilities.MemClear((IntPtr)_list->ptr, (uint)_list->capacity);
  429. #if ENABLE_DEBUG_CHECKS
  430. }
  431. #endif
  432. }
  433. }
  434. #if UNITY_COLLECTIONS || UNITY_JOBS || UNITY_BURST
  435. #if UNITY_BURST
  436. [Unity.Burst.NoAlias]
  437. #endif
  438. [Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction]
  439. #endif
  440. unsafe UnsafeArray* _list;
  441. #if DEBUG && !PROFILE_SVELTO
  442. int _hashType;
  443. #endif
  444. Sentinel _threadSentinel;
  445. Allocator _allocator;
  446. }
  447. }