DynamicArray.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // Copyright (C) 2009-present, 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/MemoryPool.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 that requires manual destruction.
  13. /// 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 TMemoryPool = SingletonMemoryPoolWrapper<DefaultMemoryPool>, typename TSize = U32>
  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 kGrowScale = 2.0f;
  27. static constexpr F32 kShrinkScale = 2.0f;
  28. DynamicArray(const TMemoryPool& pool = TMemoryPool())
  29. : m_pool(pool)
  30. {
  31. }
  32. /// Copy.
  33. DynamicArray(const DynamicArray& b)
  34. {
  35. *this = b;
  36. }
  37. /// Move.
  38. DynamicArray(DynamicArray&& b)
  39. : DynamicArray()
  40. {
  41. *this = std::move(b);
  42. }
  43. ~DynamicArray()
  44. {
  45. destroy();
  46. }
  47. /// Move.
  48. DynamicArray& operator=(DynamicArray&& b)
  49. {
  50. destroy();
  51. m_pool = b.m_pool;
  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. /// Copy and trim extra capacity.
  61. DynamicArray& operator=(const DynamicArray& b)
  62. {
  63. destroy();
  64. m_pool = b.m_pool;
  65. m_size = b.m_size;
  66. m_capacity = b.m_size;
  67. m_data = (m_size) ? static_cast<T*>(m_pool.allocate(sizeof(T) * m_size, alignof(T))) : nullptr;
  68. for(TSize i = 0; i < m_size; ++i)
  69. {
  70. ::new(&m_data[i]) T(b.m_data[i]);
  71. }
  72. return *this;
  73. }
  74. Reference operator[](const Size n)
  75. {
  76. ANKI_ASSERT(n < m_size);
  77. return m_data[n];
  78. }
  79. ConstReference operator[](const Size n) const
  80. {
  81. ANKI_ASSERT(n < m_size);
  82. return m_data[n];
  83. }
  84. Iterator getBegin()
  85. {
  86. return m_data;
  87. }
  88. ConstIterator getBegin() const
  89. {
  90. return m_data;
  91. }
  92. Iterator getEnd()
  93. {
  94. return m_data + m_size;
  95. }
  96. ConstIterator getEnd() const
  97. {
  98. return m_data + m_size;
  99. }
  100. /// Make it compatible with the C++11 range based for loop.
  101. Iterator begin()
  102. {
  103. return getBegin();
  104. }
  105. /// Make it compatible with the C++11 range based for loop.
  106. ConstIterator begin() const
  107. {
  108. return getBegin();
  109. }
  110. /// Make it compatible with the C++11 range based for loop.
  111. Iterator end()
  112. {
  113. return getEnd();
  114. }
  115. /// Make it compatible with the C++11 range based for loop.
  116. ConstIterator end() const
  117. {
  118. return getEnd();
  119. }
  120. /// Get first element.
  121. Reference getFront()
  122. {
  123. ANKI_ASSERT(!isEmpty());
  124. return m_data[0];
  125. }
  126. /// Get first element.
  127. ConstReference getFront() const
  128. {
  129. ANKI_ASSERT(!isEmpty());
  130. return m_data[0];
  131. }
  132. /// Get last element.
  133. Reference getBack()
  134. {
  135. ANKI_ASSERT(!isEmpty());
  136. return m_data[m_size - 1];
  137. }
  138. /// Get last element.
  139. ConstReference getBack() const
  140. {
  141. ANKI_ASSERT(!isEmpty());
  142. return m_data[m_size - 1];
  143. }
  144. Size getSize() const
  145. {
  146. return m_size;
  147. }
  148. Bool isEmpty() const
  149. {
  150. return m_size == 0;
  151. }
  152. PtrSize getSizeInBytes() const
  153. {
  154. return m_size * sizeof(Value);
  155. }
  156. /// Destroy the array.
  157. void destroy()
  158. {
  159. if(m_data)
  160. {
  161. ANKI_ASSERT(m_capacity > 0);
  162. for(TSize i = 0; i < m_size; ++i)
  163. {
  164. m_data[i].~T();
  165. }
  166. m_pool.free(m_data);
  167. m_data = nullptr;
  168. m_size = 0;
  169. m_capacity = 0;
  170. }
  171. ANKI_ASSERT(m_data == nullptr && m_size == 0 && m_capacity == 0);
  172. }
  173. /// Grow or create the array. @a T needs to be copyable and moveable else you might get an assertion.
  174. template<typename... TArgs>
  175. void resize(Size size, TArgs... args);
  176. /// Push back value.
  177. template<typename... TArgs>
  178. Iterator emplaceBack(TArgs&&... args)
  179. {
  180. resizeStorage(m_size + 1);
  181. callConstructor(m_data[m_size], std::forward<TArgs>(args)...);
  182. ++m_size;
  183. return &m_data[m_size - 1];
  184. }
  185. /// Remove the last value.
  186. void popBack()
  187. {
  188. if(m_size > 0)
  189. {
  190. resizeStorage(m_size - 1);
  191. }
  192. }
  193. /// Emplace a new element at a specific position. @a T needs to be movable and default constructible.
  194. /// @param where Points to the position to emplace. Should be less or equal to what getEnd() returns.
  195. /// @param args Constructor arguments.
  196. template<typename... TArgs>
  197. Iterator emplaceAt(ConstIterator where, TArgs&&... args);
  198. /// Removes the (first, last] elements.
  199. /// @param first Points to the position of the first element to remove.
  200. /// @param last Points to the position of the last element to remove minus one.
  201. void erase(ConstIterator first, ConstIterator last);
  202. /// Removes one element.
  203. /// @param at Points to the position of the element to remove.
  204. void erase(ConstIterator at)
  205. {
  206. erase(at, at + 1);
  207. }
  208. /// Validate it. Will only work when assertions are enabled.
  209. void validate() const
  210. {
  211. if(m_data)
  212. {
  213. ANKI_ASSERT(m_size > 0 && m_capacity > 0);
  214. ANKI_ASSERT(m_size <= m_capacity);
  215. }
  216. else
  217. {
  218. ANKI_ASSERT(m_size == 0 && m_capacity == 0);
  219. }
  220. }
  221. /// Move the data from this object. It's like moving (operator or constructor) but instead of moving to another object of the same type it moves
  222. /// to 3 values.
  223. void moveAndReset(Value*& data, Size& size, Size& storageSize)
  224. {
  225. data = m_data;
  226. size = m_size;
  227. storageSize = m_capacity;
  228. m_data = nullptr;
  229. m_size = 0;
  230. m_capacity = 0;
  231. }
  232. /// @copydoc moveAndReset
  233. void moveAndReset(WeakArray<Value, Size>& array)
  234. {
  235. Value* data;
  236. Size size;
  237. Size storageSize;
  238. moveAndReset(data, size, storageSize);
  239. array.setArray(data, size);
  240. }
  241. /// Resizes the storage but DOESN'T CONSTRUCT ANY ELEMENTS. It only moves or destroys.
  242. void resizeStorage(Size newSize);
  243. /// Search the array until you find the 1st value.
  244. Iterator find(const Value& what)
  245. {
  246. Value* it = m_data;
  247. Value* end = m_data + m_size;
  248. for(; it != end; ++it)
  249. {
  250. if(*it == what)
  251. {
  252. return it;
  253. }
  254. }
  255. return end;
  256. }
  257. /// Fill the array.
  258. static void fill(Iterator begin, Iterator end, const T& val)
  259. {
  260. while(begin != end)
  261. {
  262. *begin = val;
  263. ++begin;
  264. }
  265. }
  266. void fill(const T& val)
  267. {
  268. auto begin = getBegin();
  269. auto end = getEnd();
  270. while(begin != end)
  271. {
  272. *begin = val;
  273. ++begin;
  274. }
  275. }
  276. TMemoryPool& getMemoryPool()
  277. {
  278. return m_pool;
  279. }
  280. protected:
  281. TMemoryPool m_pool;
  282. Value* m_data = nullptr;
  283. Size m_size = 0;
  284. Size m_capacity = 0;
  285. };
  286. /// @}
  287. } // end namespace anki
  288. #include <AnKi/Util/DynamicArray.inl.h>