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.

392 lines
13KB

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