DynamicArray.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Util/Allocator.h>
  7. #include <AnKi/Util/Functions.h>
  8. namespace anki
  9. {
  10. // Forward
  11. template<typename T, typename TSize>
  12. class DynamicArrayAuto;
  13. /// @addtogroup util_containers
  14. /// @{
  15. /// Dynamic array with manual destruction. It doesn't hold the allocator and that makes it compact. At the same time
  16. /// that requires manual destruction. Used in permanent classes.
  17. /// @tparam T The type this array will hold.
  18. /// @tparam TSize The type that denotes the maximum number of elements of the array.
  19. template<typename T, typename TSize = U32>
  20. class DynamicArray
  21. {
  22. public:
  23. using Value = T;
  24. using Iterator = Value*;
  25. using ConstIterator = const Value*;
  26. using Reference = Value&;
  27. using ConstReference = const Value&;
  28. using Size = TSize;
  29. static constexpr F32 GROW_SCALE = 2.0f;
  30. static constexpr F32 SHRINK_SCALE = 2.0f;
  31. DynamicArray()
  32. : m_data(nullptr)
  33. , m_size(0)
  34. , m_capacity(0)
  35. {
  36. }
  37. // Non-copyable
  38. DynamicArray(const DynamicArray& b) = delete;
  39. /// Move.
  40. DynamicArray(DynamicArray&& b)
  41. : DynamicArray()
  42. {
  43. *this = std::move(b);
  44. }
  45. ~DynamicArray()
  46. {
  47. ANKI_ASSERT(m_data == nullptr && m_size == 0 && m_capacity == 0 && "Requires manual destruction");
  48. }
  49. /// Move.
  50. DynamicArray& operator=(DynamicArray&& b)
  51. {
  52. ANKI_ASSERT(m_data == nullptr && m_size == 0 && "Cannot move before destroying");
  53. m_data = b.m_data;
  54. b.m_data = nullptr;
  55. m_size = b.m_size;
  56. b.m_size = 0;
  57. m_capacity = b.m_capacity;
  58. b.m_capacity = 0;
  59. return *this;
  60. }
  61. /// Move DynamicArrayAuto to this.
  62. DynamicArray& operator=(DynamicArrayAuto<T, TSize>&& b);
  63. // Non-copyable
  64. DynamicArray& operator=(const DynamicArray& b) = delete;
  65. Reference operator[](const Size n)
  66. {
  67. ANKI_ASSERT(n < m_size);
  68. return m_data[n];
  69. }
  70. ConstReference operator[](const Size n) const
  71. {
  72. ANKI_ASSERT(n < m_size);
  73. return m_data[n];
  74. }
  75. Iterator getBegin()
  76. {
  77. return m_data;
  78. }
  79. ConstIterator getBegin() const
  80. {
  81. return m_data;
  82. }
  83. Iterator getEnd()
  84. {
  85. return m_data + m_size;
  86. }
  87. ConstIterator getEnd() const
  88. {
  89. return m_data + m_size;
  90. }
  91. /// Make it compatible with the C++11 range based for loop.
  92. Iterator begin()
  93. {
  94. return getBegin();
  95. }
  96. /// Make it compatible with the C++11 range based for loop.
  97. ConstIterator begin() const
  98. {
  99. return getBegin();
  100. }
  101. /// Make it compatible with the C++11 range based for loop.
  102. Iterator end()
  103. {
  104. return getEnd();
  105. }
  106. /// Make it compatible with the C++11 range based for loop.
  107. ConstIterator end() const
  108. {
  109. return getEnd();
  110. }
  111. /// Get first element.
  112. Reference getFront()
  113. {
  114. ANKI_ASSERT(!isEmpty());
  115. return m_data[0];
  116. }
  117. /// Get first element.
  118. ConstReference getFront() const
  119. {
  120. ANKI_ASSERT(!isEmpty());
  121. return m_data[0];
  122. }
  123. /// Get last element.
  124. Reference getBack()
  125. {
  126. ANKI_ASSERT(!isEmpty());
  127. return m_data[m_size - 1];
  128. }
  129. /// Get last element.
  130. ConstReference getBack() const
  131. {
  132. ANKI_ASSERT(!isEmpty());
  133. return m_data[m_size - 1];
  134. }
  135. Size getSize() const
  136. {
  137. return m_size;
  138. }
  139. Bool isEmpty() const
  140. {
  141. return m_size == 0;
  142. }
  143. PtrSize getSizeInBytes() const
  144. {
  145. return m_size * sizeof(Value);
  146. }
  147. /// Only create the array. Useful if @a T is non-copyable or movable .
  148. template<typename TAllocator>
  149. void create(TAllocator alloc, Size size)
  150. {
  151. ANKI_ASSERT(m_data == nullptr && m_size == 0 && m_capacity == 0);
  152. if(size > 0)
  153. {
  154. m_data = alloc.template newArray<Value>(size);
  155. m_size = size;
  156. m_capacity = size;
  157. }
  158. }
  159. /// Only create the array. Useful if @a T is non-copyable or movable .
  160. template<typename TAllocator>
  161. void create(TAllocator alloc, Size size, const Value& v)
  162. {
  163. ANKI_ASSERT(m_data == nullptr && m_size == 0 && m_capacity == 0);
  164. if(size > 0)
  165. {
  166. m_data = alloc.template newArray<Value>(size, v);
  167. m_size = size;
  168. m_capacity = size;
  169. }
  170. }
  171. /// Grow or create the array. @a T needs to be copyable and moveable.
  172. template<typename TAllocator>
  173. void resize(TAllocator alloc, Size size, const Value& v);
  174. /// Grow or create the array. @a T needs to be copyable, moveable and default constructible.
  175. template<typename TAllocator>
  176. void resize(TAllocator alloc, Size size);
  177. /// Push back value.
  178. template<typename TAllocator, typename... TArgs>
  179. Iterator emplaceBack(TAllocator alloc, TArgs&&... args)
  180. {
  181. resizeStorage(alloc, m_size + 1);
  182. alloc.construct(&m_data[m_size], std::forward<TArgs>(args)...);
  183. ++m_size;
  184. return &m_data[m_size - 1];
  185. }
  186. /// Remove the last value.
  187. template<typename TAllocator>
  188. void popBack(TAllocator alloc)
  189. {
  190. if(m_size > 0)
  191. {
  192. resizeStorage(alloc, m_size - 1);
  193. }
  194. }
  195. /// Emplace a new element at a specific position. @a T needs to be movable and default constructible.
  196. /// @param alloc The allocator.
  197. /// @param where Points to the position to emplace. Should be less or equal to what getEnd() returns.
  198. /// @param args Constructor arguments.
  199. template<typename TAllocator, typename... TArgs>
  200. Iterator emplaceAt(TAllocator alloc, ConstIterator where, TArgs&&... args);
  201. /// Destroy the array.
  202. template<typename TAllocator>
  203. void destroy(TAllocator alloc)
  204. {
  205. if(m_data)
  206. {
  207. ANKI_ASSERT(m_size > 0);
  208. ANKI_ASSERT(m_capacity > 0);
  209. alloc.deleteArray(m_data, m_size);
  210. m_data = nullptr;
  211. m_size = 0;
  212. m_capacity = 0;
  213. }
  214. ANKI_ASSERT(m_data == nullptr && m_size == 0 && m_capacity == 0);
  215. }
  216. /// Validate it. Will only work when assertions are enabled.
  217. void validate() const
  218. {
  219. if(m_data)
  220. {
  221. ANKI_ASSERT(m_size > 0 && m_capacity > 0);
  222. ANKI_ASSERT(m_size <= m_capacity);
  223. }
  224. else
  225. {
  226. ANKI_ASSERT(m_size == 0 && m_capacity == 0);
  227. }
  228. }
  229. /// Move the data from this object. It's like moving (operator or constructor) but instead of moving to another
  230. /// object of the same type it moves to 3 values.
  231. void moveAndReset(Value*& data, Size& size, Size& storageSize)
  232. {
  233. data = m_data;
  234. size = m_size;
  235. storageSize = m_capacity;
  236. m_data = nullptr;
  237. m_size = 0;
  238. m_capacity = 0;
  239. }
  240. /// Resizes the storage but DOESN'T CONSTRUCT ANY ELEMENTS. It only moves or destroys.
  241. template<typename TAllocator>
  242. void resizeStorage(TAllocator alloc, Size newSize);
  243. protected:
  244. Value* m_data;
  245. Size m_size;
  246. Size m_capacity = 0;
  247. };
  248. /// Dynamic array with automatic destruction. It's the same as DynamicArray but it holds the allocator in order to
  249. /// perform automatic destruction. Use it for temp operations and on transient classes.
  250. template<typename T, typename TSize = U32>
  251. class DynamicArrayAuto : public DynamicArray<T, TSize>
  252. {
  253. public:
  254. using Base = DynamicArray<T, TSize>;
  255. using Base::m_capacity;
  256. using Base::m_data;
  257. using Base::m_size;
  258. using typename Base::Value;
  259. using typename Base::Iterator;
  260. using typename Base::ConstIterator;
  261. using typename Base::Size;
  262. template<typename TAllocator>
  263. DynamicArrayAuto(TAllocator alloc)
  264. : Base()
  265. , m_alloc(alloc)
  266. {
  267. }
  268. /// And resize
  269. template<typename TAllocator>
  270. DynamicArrayAuto(TAllocator alloc, Size size)
  271. : Base()
  272. , m_alloc(alloc)
  273. {
  274. resize(size);
  275. }
  276. /// With default value
  277. template<typename TAllocator>
  278. DynamicArrayAuto(TAllocator alloc, Size size, const T& v)
  279. : Base()
  280. , m_alloc(alloc)
  281. {
  282. create(size, v);
  283. }
  284. /// Move.
  285. DynamicArrayAuto(DynamicArrayAuto&& b)
  286. : Base()
  287. {
  288. *this = std::move(b);
  289. }
  290. ~DynamicArrayAuto()
  291. {
  292. Base::destroy(m_alloc);
  293. }
  294. /// Copy.
  295. DynamicArrayAuto(const DynamicArrayAuto& b)
  296. : Base()
  297. , m_alloc(b.m_alloc)
  298. {
  299. if(b.getSize())
  300. {
  301. create(b.getSize());
  302. for(Size i = 0; i < b.getSize(); ++i)
  303. {
  304. (*this)[i] = b[i];
  305. }
  306. }
  307. }
  308. /// Move.
  309. DynamicArrayAuto& operator=(DynamicArrayAuto&& b)
  310. {
  311. Base::destroy(m_alloc);
  312. m_data = b.m_data;
  313. b.m_data = nullptr;
  314. m_size = b.m_size;
  315. b.m_size = 0;
  316. m_capacity = b.m_capacity;
  317. b.m_capacity = 0;
  318. m_alloc = b.m_alloc;
  319. b.m_alloc = {};
  320. return *this;
  321. }
  322. /// Copy.
  323. DynamicArrayAuto& operator=(const DynamicArrayAuto& b)
  324. {
  325. destroy();
  326. if(b.getSize())
  327. {
  328. create(b.getSize());
  329. for(Size i = 0; i < b.getSize(); ++i)
  330. {
  331. (*this)[i] = b[i];
  332. }
  333. }
  334. return *this;
  335. }
  336. /// @copydoc DynamicArray::create
  337. void create(Size size)
  338. {
  339. Base::create(m_alloc, size);
  340. }
  341. /// @copydoc DynamicArray::create
  342. void create(Size size, const Value& v)
  343. {
  344. Base::create(m_alloc, size, v);
  345. }
  346. /// @copydoc DynamicArray::destroy
  347. void destroy()
  348. {
  349. Base::destroy(m_alloc);
  350. }
  351. /// @copydoc DynamicArray::resize
  352. void resize(Size size, const Value& v)
  353. {
  354. Base::resize(m_alloc, size, v);
  355. }
  356. /// @copydoc DynamicArray::emplaceBack
  357. template<typename... TArgs>
  358. Iterator emplaceBack(TArgs&&... args)
  359. {
  360. return Base::emplaceBack(m_alloc, std::forward<TArgs>(args)...);
  361. }
  362. /// @copydoc DynamicArray::emplaceAt
  363. template<typename... TArgs>
  364. Iterator emplaceAt(ConstIterator where, TArgs&&... args)
  365. {
  366. return Base::emplaceAt(m_alloc, where, std::forward<TArgs>(args)...);
  367. }
  368. /// @copydoc DynamicArray::resize
  369. void resize(Size size)
  370. {
  371. Base::resize(m_alloc, size);
  372. }
  373. /// @copydoc DynamicArray::moveAndReset
  374. void moveAndReset(Value*& data, Size& size, Size& storageSize)
  375. {
  376. Base::moveAndReset(data, size, storageSize);
  377. // Don't touch the m_alloc
  378. }
  379. /// @copydoc DynamicArray::resizeStorage
  380. void resizeStorage(Size newSize)
  381. {
  382. Base::resizeStorage(m_alloc, newSize);
  383. }
  384. /// Get the allocator.
  385. const GenericMemoryPoolAllocator<T>& getAllocator() const
  386. {
  387. return m_alloc;
  388. }
  389. private:
  390. GenericMemoryPoolAllocator<T> m_alloc;
  391. };
  392. /// @}
  393. } // end namespace anki
  394. #include <AnKi/Util/DynamicArray.inl.h>