DynamicArray.h 10 KB

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