DynamicArray.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. // Copyright (C) 2009-2022, 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. #include <AnKi/Util/Forward.h>
  9. namespace anki {
  10. /// @addtogroup util_containers
  11. /// @{
  12. /// Dynamic array with manual destruction. It doesn't hold the allocator and that makes it compact. At the same time
  13. /// that requires manual destruction. Used in permanent classes.
  14. /// @tparam T The type this array will hold.
  15. /// @tparam TSize The type that denotes the maximum number of elements of the array.
  16. template<typename T, typename TSize>
  17. class DynamicArray
  18. {
  19. public:
  20. using Value = T;
  21. using Iterator = Value*;
  22. using ConstIterator = const Value*;
  23. using Reference = Value&;
  24. using ConstReference = const Value&;
  25. using Size = TSize;
  26. static constexpr F32 GROW_SCALE = 2.0f;
  27. static constexpr F32 SHRINK_SCALE = 2.0f;
  28. DynamicArray()
  29. : m_data(nullptr)
  30. , m_size(0)
  31. , m_capacity(0)
  32. {
  33. }
  34. // Non-copyable
  35. DynamicArray(const DynamicArray& b) = delete;
  36. /// Move.
  37. DynamicArray(DynamicArray&& b)
  38. : DynamicArray()
  39. {
  40. *this = std::move(b);
  41. }
  42. ~DynamicArray()
  43. {
  44. ANKI_ASSERT(m_data == nullptr && m_size == 0 && m_capacity == 0 && "Requires manual destruction");
  45. }
  46. /// Move.
  47. DynamicArray& operator=(DynamicArray&& b)
  48. {
  49. ANKI_ASSERT(m_data == nullptr && m_size == 0 && "Cannot move before destroying");
  50. m_data = b.m_data;
  51. b.m_data = nullptr;
  52. m_size = b.m_size;
  53. b.m_size = 0;
  54. m_capacity = b.m_capacity;
  55. b.m_capacity = 0;
  56. return *this;
  57. }
  58. /// Move DynamicArrayAuto to this.
  59. DynamicArray& operator=(DynamicArrayAuto<T, TSize>&& b);
  60. // Non-copyable
  61. DynamicArray& operator=(const DynamicArray& b) = delete;
  62. Reference operator[](const Size n)
  63. {
  64. ANKI_ASSERT(n < m_size);
  65. return m_data[n];
  66. }
  67. ConstReference operator[](const Size n) const
  68. {
  69. ANKI_ASSERT(n < m_size);
  70. return m_data[n];
  71. }
  72. Iterator getBegin()
  73. {
  74. return m_data;
  75. }
  76. ConstIterator getBegin() const
  77. {
  78. return m_data;
  79. }
  80. Iterator getEnd()
  81. {
  82. return m_data + m_size;
  83. }
  84. ConstIterator getEnd() const
  85. {
  86. return m_data + m_size;
  87. }
  88. /// Make it compatible with the C++11 range based for loop.
  89. Iterator begin()
  90. {
  91. return getBegin();
  92. }
  93. /// Make it compatible with the C++11 range based for loop.
  94. ConstIterator begin() const
  95. {
  96. return getBegin();
  97. }
  98. /// Make it compatible with the C++11 range based for loop.
  99. Iterator end()
  100. {
  101. return getEnd();
  102. }
  103. /// Make it compatible with the C++11 range based for loop.
  104. ConstIterator end() const
  105. {
  106. return getEnd();
  107. }
  108. /// Get first element.
  109. Reference getFront()
  110. {
  111. ANKI_ASSERT(!isEmpty());
  112. return m_data[0];
  113. }
  114. /// Get first element.
  115. ConstReference getFront() const
  116. {
  117. ANKI_ASSERT(!isEmpty());
  118. return m_data[0];
  119. }
  120. /// Get last element.
  121. Reference getBack()
  122. {
  123. ANKI_ASSERT(!isEmpty());
  124. return m_data[m_size - 1];
  125. }
  126. /// Get last element.
  127. ConstReference getBack() const
  128. {
  129. ANKI_ASSERT(!isEmpty());
  130. return m_data[m_size - 1];
  131. }
  132. Size getSize() const
  133. {
  134. return m_size;
  135. }
  136. Bool isEmpty() const
  137. {
  138. return m_size == 0;
  139. }
  140. PtrSize getSizeInBytes() const
  141. {
  142. return m_size * sizeof(Value);
  143. }
  144. /// Only create the array. Useful if @a T is non-copyable or movable .
  145. template<typename TAllocator>
  146. void create(TAllocator alloc, Size size)
  147. {
  148. ANKI_ASSERT(m_data == nullptr && m_size == 0 && m_capacity == 0);
  149. if(size > 0)
  150. {
  151. m_data = alloc.template newArray<Value>(size);
  152. m_size = size;
  153. m_capacity = size;
  154. }
  155. }
  156. /// Only create the array. Useful if @a T is non-copyable or movable .
  157. template<typename TAllocator>
  158. void create(TAllocator alloc, Size size, const Value& v)
  159. {
  160. ANKI_ASSERT(m_data == nullptr && m_size == 0 && m_capacity == 0);
  161. if(size > 0)
  162. {
  163. m_data = alloc.template newArray<Value>(size, v);
  164. m_size = size;
  165. m_capacity = size;
  166. }
  167. }
  168. /// Destroy the array.
  169. template<typename TAllocator>
  170. void destroy(TAllocator alloc)
  171. {
  172. if(m_data)
  173. {
  174. ANKI_ASSERT(m_size > 0);
  175. ANKI_ASSERT(m_capacity > 0);
  176. alloc.deleteArray(m_data, m_size);
  177. m_data = nullptr;
  178. m_size = 0;
  179. m_capacity = 0;
  180. }
  181. ANKI_ASSERT(m_data == nullptr && m_size == 0 && m_capacity == 0);
  182. }
  183. /// Grow or create the array. @a T needs to be copyable and moveable.
  184. template<typename TAllocator>
  185. void resize(TAllocator alloc, Size size, const Value& v);
  186. /// Grow or create the array. @a T needs to be copyable, moveable and default constructible.
  187. template<typename TAllocator>
  188. void resize(TAllocator alloc, Size size);
  189. /// Push back value.
  190. template<typename TAllocator, typename... TArgs>
  191. Iterator emplaceBack(TAllocator alloc, TArgs&&... args)
  192. {
  193. resizeStorage(alloc, m_size + 1);
  194. alloc.construct(&m_data[m_size], std::forward<TArgs>(args)...);
  195. ++m_size;
  196. return &m_data[m_size - 1];
  197. }
  198. /// Remove the last value.
  199. template<typename TAllocator>
  200. void popBack(TAllocator alloc)
  201. {
  202. if(m_size > 0)
  203. {
  204. resizeStorage(alloc, m_size - 1);
  205. }
  206. }
  207. /// Emplace a new element at a specific position. @a T needs to be movable and default constructible.
  208. /// @param alloc The allocator.
  209. /// @param where Points to the position to emplace. Should be less or equal to what getEnd() returns.
  210. /// @param args Constructor arguments.
  211. template<typename TAllocator, typename... TArgs>
  212. Iterator emplaceAt(TAllocator alloc, ConstIterator where, TArgs&&... args);
  213. /// Removes the (first, last] elements.
  214. /// @param alloc The allocator.
  215. /// @param first Points to the position of the first element to remove.
  216. /// @param last Points to the position of the last element to remove minus one.
  217. template<typename TAllocator>
  218. void erase(TAllocator alloc, ConstIterator first, ConstIterator last);
  219. /// Removes one element.
  220. /// @param alloc The allocator.
  221. /// @param at Points to the position of the element to remove.
  222. template<typename TAllocator>
  223. void erase(TAllocator alloc, ConstIterator at)
  224. {
  225. erase(alloc, at, at + 1);
  226. }
  227. /// Validate it. Will only work when assertions are enabled.
  228. void validate() const
  229. {
  230. if(m_data)
  231. {
  232. ANKI_ASSERT(m_size > 0 && m_capacity > 0);
  233. ANKI_ASSERT(m_size <= m_capacity);
  234. }
  235. else
  236. {
  237. ANKI_ASSERT(m_size == 0 && m_capacity == 0);
  238. }
  239. }
  240. /// Move the data from this object. It's like moving (operator or constructor) but instead of moving to another
  241. /// object of the same type it moves to 3 values.
  242. void moveAndReset(Value*& data, Size& size, Size& storageSize)
  243. {
  244. data = m_data;
  245. size = m_size;
  246. storageSize = m_capacity;
  247. m_data = nullptr;
  248. m_size = 0;
  249. m_capacity = 0;
  250. }
  251. /// @copydoc moveAndReset
  252. void moveAndReset(WeakArray<Value, Size>& array);
  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>
  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::moveAndReset
  408. void moveAndReset(WeakArray<Value, Size>& array)
  409. {
  410. Base::moveAndReset(array);
  411. // Don't touch the m_alloc
  412. }
  413. /// @copydoc DynamicArray::resizeStorage
  414. void resizeStorage(Size newSize)
  415. {
  416. Base::resizeStorage(m_alloc, newSize);
  417. }
  418. /// Get the allocator.
  419. const GenericMemoryPoolAllocator<T>& getAllocator() const
  420. {
  421. return m_alloc;
  422. }
  423. private:
  424. GenericMemoryPoolAllocator<T> m_alloc;
  425. };
  426. /// @}
  427. } // end namespace anki
  428. #include <AnKi/Util/DynamicArray.inl.h>