| 354 | template<typename T, bool = std::is_trivially_copy_constructible<T>::value && |
| 355 | std::is_trivially_move_constructible<T>::value && std::is_trivially_destructible<T>::value> |
| 356 | class SmallVectorTemplate : public SmallVectorTemplateCommon<T> |
| 357 | { |
| 358 | friend class SmallVectorTemplateCommon<T>; |
| 359 | |
| 360 | protected: |
| 361 | /** @brief Whether it's cheap enough to take parameters by value, always `false` for non-trivial types */ |
| 362 | static constexpr bool TakesParamByValue = false; |
| 363 | /** @brief Either `const T&` or `T`, depending on whether it's cheap enough to take parameters by value, always `const T&` for non-trivial types */ |
| 364 | using ValueParamT = const T&; |
| 365 | |
| 366 | SmallVectorTemplate(std::size_t size) : SmallVectorTemplateCommon<T>(size) {} |
| 367 | |
| 368 | /** @brief Calls destructor on every element in the specified range if needed */ |
| 369 | static void destroyRange(T* s, T* e) { |
| 370 | while (s != e) { |
| 371 | --e; |
| 372 | e->~T(); |
| 373 | } |
| 374 | } |
| 375 | |
| 376 | /** @brief Moves the range [I, E) into the uninitialized memory starting with @p dest, constructing elements as needed */ |
| 377 | template<typename It1, typename It2> |
| 378 | static void uninitializedMove(It1 i, It1 e, It2 dest) { |
| 379 | std::uninitialized_move(i, e, dest); |
| 380 | } |
| 381 | |
| 382 | /** @brief Copies the range [I, E) onto the uninitialized memory starting with @p dest, constructing elements as needed */ |
| 383 | template<typename It1, typename It2> |
| 384 | static void uninitializedCopy(It1 i, It1 e, It2 dest) { |
| 385 | std::uninitialized_copy(i, e, dest); |
| 386 | } |
| 387 | |
| 388 | /** @brief Grows the allocated memory (without initializing new elements), doubling the size of the allocated memory */ |
| 389 | void grow(std::size_t minSize = 0); |
| 390 | |
| 391 | /** @brief Creates a new allocation big enough for @p minSize and pass back its size in @p newCapacity */ |
| 392 | T* mallocForGrow(std::size_t minSize, std::size_t& newCapacity); |
| 393 | |
| 394 | /** @brief Move existing elements over to the new allocation @p newElts */ |
| 395 | void moveElementsForGrow(T* newElts); |
| 396 | |
| 397 | /** @brief Transfers ownership of the allocation */ |
| 398 | void takeAllocationForGrow(T* newElts, std::size_t newCapacity); |
| 399 | |
| 400 | /** @brief Reserves enough space to add one element, and returns the updated element pointer in case it was a reference to the storage */ |
| 401 | const T* reserveForParamAndGetAddress(const T& elt, std::size_t n = 1) { |
| 402 | return this->reserveForParamAndGetAddressImpl(this, elt, n); |
| 403 | } |
| 404 | |
| 405 | /** @overload */ |
| 406 | T* reserveForParamAndGetAddress(T& elt, std::size_t n = 1) { |
| 407 | return const_cast<T*>( |
| 408 | this->reserveForParamAndGetAddressImpl(this, elt, n)); |
| 409 | } |
| 410 | |
| 411 | /** @brief Forwards a value */ |
| 412 | static T&& forwardValueParam(T&& v) { |
| 413 | return Death::move(v); |