DynamicArray.inl.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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. #include <AnKi/Util/DynamicArray.h>
  6. namespace anki {
  7. template<typename T, typename TSize>
  8. DynamicArray<T, TSize>& DynamicArray<T, TSize>::operator=(DynamicArrayAuto<T, TSize>&& b)
  9. {
  10. ANKI_ASSERT(m_data == nullptr && m_size == 0 && "Cannot move before destroying");
  11. T* data;
  12. Size size, storageSize;
  13. b.moveAndReset(data, size, storageSize);
  14. m_data = data;
  15. m_size = size;
  16. m_capacity = storageSize;
  17. return *this;
  18. }
  19. template<typename T, typename TSize>
  20. template<typename TAllocator>
  21. void DynamicArray<T, TSize>::resizeStorage(TAllocator alloc, Size newSize)
  22. {
  23. if(newSize > m_capacity)
  24. {
  25. // Need to grow
  26. m_capacity = (newSize > Size(F64(m_capacity) * GROW_SCALE)) ? newSize : Size(F64(m_capacity) * GROW_SCALE);
  27. Value* newStorage =
  28. static_cast<Value*>(alloc.getMemoryPool().allocate(m_capacity * sizeof(Value), alignof(Value)));
  29. // Move old elements to the new storage
  30. if(m_data)
  31. {
  32. for(Size i = 0; i < m_size; ++i)
  33. {
  34. alloc.construct(&newStorage[i], std::move(m_data[i]));
  35. m_data[i].~T();
  36. }
  37. alloc.getMemoryPool().free(m_data);
  38. }
  39. m_data = newStorage;
  40. }
  41. else if(newSize < m_size)
  42. {
  43. ANKI_ASSERT(m_capacity > 0);
  44. ANKI_ASSERT(m_size > 0);
  45. ANKI_ASSERT(m_data);
  46. // Delete remaining stuff
  47. for(Size i = newSize; i < m_size; ++i)
  48. {
  49. m_data[i].~T();
  50. }
  51. m_size = newSize;
  52. if(newSize < Size(F64(m_capacity) / SHRINK_SCALE) || newSize == 0)
  53. {
  54. // Need to shrink
  55. m_capacity = newSize;
  56. if(newSize)
  57. {
  58. Value* newStorage =
  59. static_cast<Value*>(alloc.getMemoryPool().allocate(m_capacity * sizeof(Value), alignof(Value)));
  60. for(Size i = 0; i < m_size; ++i)
  61. {
  62. alloc.construct(&newStorage[i], std::move(m_data[i]));
  63. m_data[i].~T();
  64. }
  65. alloc.getMemoryPool().free(m_data);
  66. m_data = newStorage;
  67. }
  68. else
  69. {
  70. alloc.getMemoryPool().free(m_data);
  71. m_data = nullptr;
  72. }
  73. }
  74. }
  75. }
  76. template<typename T, typename TSize>
  77. template<typename TAllocator>
  78. void DynamicArray<T, TSize>::resize(TAllocator alloc, Size newSize, const Value& v)
  79. {
  80. const Bool willGrow = newSize > m_size;
  81. resizeStorage(alloc, newSize);
  82. if(willGrow)
  83. {
  84. // Fill with new values
  85. for(U i = m_size; i < newSize; ++i)
  86. {
  87. alloc.construct(&m_data[i], v);
  88. }
  89. m_size = newSize;
  90. }
  91. ANKI_ASSERT(m_size <= m_capacity);
  92. ANKI_ASSERT(m_size == newSize);
  93. }
  94. template<typename T, typename TSize>
  95. template<typename TAllocator>
  96. void DynamicArray<T, TSize>::resize(TAllocator alloc, Size newSize)
  97. {
  98. const Bool willGrow = newSize > m_size;
  99. resizeStorage(alloc, newSize);
  100. if(willGrow)
  101. {
  102. // Fill with new values
  103. for(U i = m_size; i < newSize; ++i)
  104. {
  105. alloc.construct(&m_data[i]);
  106. }
  107. m_size = newSize;
  108. }
  109. ANKI_ASSERT(m_size <= m_capacity);
  110. ANKI_ASSERT(m_size == newSize);
  111. }
  112. template<typename T, typename TSize>
  113. template<typename TAllocator, typename... TArgs>
  114. typename DynamicArray<T, TSize>::Iterator DynamicArray<T, TSize>::emplaceAt(TAllocator alloc, ConstIterator where,
  115. TArgs&&... args)
  116. {
  117. const Value* wherePtr = where;
  118. Size outIdx = getMaxNumericLimit<Size>();
  119. if(wherePtr != nullptr)
  120. {
  121. // The "where" arg points to an element inside the array or the end.
  122. // Preconditions
  123. ANKI_ASSERT(wherePtr >= m_data);
  124. ANKI_ASSERT(wherePtr <= m_data + m_size);
  125. ANKI_ASSERT(!isEmpty());
  126. const Size oldSize = m_size;
  127. const Size whereIdx = Size(wherePtr - m_data); // Get that before grow the storage
  128. ANKI_ASSERT(whereIdx >= 0u && whereIdx <= oldSize);
  129. // Resize storage
  130. resizeStorage(alloc, oldSize + 1u);
  131. Size elementsToMoveRight = oldSize - whereIdx;
  132. if(elementsToMoveRight == 0)
  133. {
  134. // "where" arg points to the end of the array
  135. outIdx = oldSize;
  136. }
  137. else
  138. {
  139. // Construct the last element because we will move to it
  140. alloc.construct(&m_data[oldSize]);
  141. // Move the elements one place to the right
  142. while(elementsToMoveRight--)
  143. {
  144. const Size idx = whereIdx + elementsToMoveRight;
  145. m_data[idx + 1] = std::move(m_data[idx]);
  146. }
  147. // Even if it's moved, call the destructor
  148. m_data[whereIdx].~Value();
  149. // Construct our object
  150. outIdx = whereIdx;
  151. }
  152. }
  153. else
  154. {
  155. // The "where" arg points to an empty array. Easy to handle
  156. ANKI_ASSERT(isEmpty());
  157. resizeStorage(alloc, 1);
  158. outIdx = 0;
  159. }
  160. // Construct the new object
  161. ANKI_ASSERT(outIdx != getMaxNumericLimit<Size>());
  162. alloc.construct(&m_data[outIdx], std::forward<TArgs>(args)...);
  163. // Increase the size because resizeStorage will not
  164. ++m_size;
  165. return &m_data[outIdx];
  166. }
  167. template<typename T, typename TSize>
  168. template<typename TAllocator>
  169. void DynamicArray<T, TSize>::erase(TAllocator alloc, ConstIterator first, ConstIterator last)
  170. {
  171. ANKI_ASSERT(first != last);
  172. ANKI_ASSERT(m_data);
  173. ANKI_ASSERT(first >= m_data && first < m_data + m_size);
  174. ANKI_ASSERT(last > m_data && last <= m_data + m_size);
  175. // Move from the back to close the gap
  176. const Size firsti = Size(first - m_data);
  177. const Size lasti = Size(last - m_data);
  178. const Size toMove = m_size - lasti;
  179. for(Size i = 0; i < toMove; ++i)
  180. {
  181. m_data[firsti + i] = std::move(m_data[lasti + i]);
  182. }
  183. // Resize storage
  184. const Size newSize = m_size - Size(last - first);
  185. resizeStorage(alloc, newSize);
  186. }
  187. } // end namespace anki