DynamicArray.inl.h 4.6 KB

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