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.

370 lines
12KB

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