diff --git a/doc/container.qbk b/doc/container.qbk index 61ef914..06423fc 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1467,7 +1467,7 @@ collect them containers and build [*Boost.Container], a library targeted to a wi * Fixed bugs/issues: * [@https://github.com/boostorg/container/issues/334 GitHub #334: ['"Wrong overload resolution protection in implementation of P2363R5"]]. -* Added [memberref boost::container::vector::unchecked_emplace_back unchecked_emplace_back] to [classref boost::container::vector vector], +* Added `unchecked_emplace_back` and `unchecked_push_back` to [classref boost::container::vector vector], [classref boost::container::static_vector static_vector] and [classref boost::container::small_vector small_vector]. [endsect] diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp index 1d9418a..25aba1a 100644 --- a/include/boost/container/static_vector.hpp +++ b/include/boost/container/static_vector.hpp @@ -608,7 +608,35 @@ public: //! //! @par Complexity //! Constant O(1). - void push_back(BOOST_RV_REF(value_type) value); + void push_back(value_type &&value); + + //! @pre size() < capacity(). Otherwise, the behavior is undefined. + //! + //! @brief Adds a copy of value at the end. + //! + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! @li If T's copy constructor throws. + //! @li If \c throw_on_overflow option is set and the container runs out of capacity. + //! + //! @par Complexity + //! Constant O(1). + void unchecked_push_back(value_type const& value); + + //! @pre size() < capacity(). Otherwise, the behavior is undefined. + //! + //! @brief Moves value to the end. + //! + //! @param value The value to move construct the new element. + //! + //! @par Throws + //! @li If T's move constructor throws. + //! @li If \c throw_on_overflow option is set and the container runs out of capacity. + //! + //! @par Complexity + //! Constant O(1). + void unchecked_push_back(value_type &&value); //! @pre !empty() //! diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 99138ac..f5aa457 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -1984,7 +1984,7 @@ private: //! //! Note: Non-standard extension. template - inline reference unchecked_emplace_back(BOOST_FWD_REF(Args)...args) + BOOST_CONTAINER_FORCEINLINE reference unchecked_emplace_back(BOOST_FWD_REF(Args)...args) { BOOST_ASSERT(this->size() < this->capacity()); T* const p = this->priv_raw_end(); @@ -2086,8 +2086,30 @@ private: //! //! Complexity: Amortized constant time. void push_back(T &&x); + + //! Requires: Before the call to this function size() < capacity() must be true. + //! Otherwise, the behavior is undefined. + //! + //! Effects: Inserts a copy of x at the end of the vector. + //! + //! Throws: If T's copy/move constructor throws. + //! + //! Complexity: Constant time. + void unchecked_push_back(const T &x); + + //! Requires: Before the call to this function size() < capacity() must be true. + //! Otherwise, the behavior is undefined. + //! + //! Effects: Constructs a new element in the end of the vector + //! and moves the resources of x to this new element. + //! + //! Throws: If T's copy/move constructor throws. + //! + //! Complexity: Constant time. + void unchecked_push_back(T &&x); #else BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) + BOOST_MOVE_CONVERSION_AWARE_CATCH(unchecked_push_back, T, void, priv_unchecked_push_back) #endif #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -2976,10 +2998,20 @@ private: this->emplace_back(::boost::forward(u)); } + template + BOOST_CONTAINER_FORCEINLINE void priv_unchecked_push_back(BOOST_FWD_REF(U) u) + { + this->unchecked_emplace_back(::boost::forward(u)); + } + //Overload to support compiler errors that instantiate too much inline void priv_push_back(::boost::move_detail::nat) {} + //Overload to support compiler errors that instantiate too much + inline void priv_unchecked_push_back(::boost::move_detail::nat) + {} + inline iterator priv_insert(const_iterator, ::boost::move_detail::nat) { return iterator(); } diff --git a/test/vector_test.hpp b/test/vector_test.hpp index 70bcad0..aefc1ea 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -42,17 +42,71 @@ namespace boost{ namespace container { namespace test{ -template -struct vector_has_function_capacity -{ - typedef typename Vector::size_type size_type; - template struct Check; - template static char func(Check *); - template static int func(...); - public: - static const bool value = sizeof(func(0)) == sizeof(char); -}; +#define BOOST_VECTOR_TEST_HAS_MEMBER_FUNC(FUNC) \ + \ +template \ +struct vector_has_function_##FUNC \ +{ \ + typedef char yes[1]; \ + typedef char no[2]; \ + \ + struct fallback { int FUNC; }; \ + struct derived : T, fallback {}; \ + \ + template \ + struct check; \ + \ + template \ + static no& test(check*); \ + \ + template \ + static yes& test(...); \ + \ + static const bool value = sizeof(test(0)) == sizeof(yes); \ +}; \ +// + +BOOST_VECTOR_TEST_HAS_MEMBER_FUNC(capacity) +BOOST_VECTOR_TEST_HAS_MEMBER_FUNC(unchecked_push_back) + +template +bool vector_unchecked_push_back_test(V1&, V2&, boost::container::dtl::false_type) +{ + return true; +} + +template +bool vector_unchecked_push_back_test(MyBoostVector& , MyStdVector& , boost::container::dtl::true_type) +{ + typedef typename MyBoostVector::value_type IntType; + + MyBoostVector bv; + MyStdVector sv; + + bv.reserve(10); + sv.reserve(10); + + for (std::size_t i = 0, max = bv.capacity(); i < max; ++i) { + bv.unchecked_push_back(IntType((int)i)); + sv.push_back((int)i); + } + + if(!test::CheckEqualContainers(bv, sv)) return false; + + bv.clear(); + sv.clear(); + + for (std::size_t i = 0, max = bv.capacity(); i < max; ++i) { + IntType move_me((int)i); + bv.unchecked_push_back(boost::move(move_me)); + sv.push_back((int)i); + } + + if(!test::CheckEqualContainers(bv, sv)) return false; + + return true; +} template bool vector_capacity_test(V1&, V2&, boost::container::dtl::false_type) @@ -94,19 +148,20 @@ bool vector_capacity_test(MyBoostVector&boostvector, MyStdVector&stdvector, boos const std::size_t sz = a.size(); const std::size_t cap = a.capacity(); - a.resize(1000); + a.resize(sz); + b.resize(sz/10); a.swap(b); - if( !(b.capacity() == cap) ) return false; + if( !(b.capacity() >= cap) ) return false; if( !(b.size() == sz) ) return false; - if( !(a.capacity() != cap) ) return false; - if( !(a.empty()) ) return false; + if( !(a.capacity() >= cap/10) ) return false; + if( !(a.size() == sz/10) ) return false; a.swap(b); - if( !(a.capacity() == cap) ) return false; + if( !(a.capacity() >= cap) ) return false; if( !(a.size() == sz) ) return false; - if( !(b.capacity() != cap) ) return false; - if( !(b.empty()) ) return false; + if( !(b.capacity() >= cap/10) ) return false; + if( !(b.size() == sz/10) ) return false; } return true; @@ -287,6 +342,9 @@ bool vector_copyable_only(MyBoostVector &boostvector, MyStdVector &stdvector, bo bcopy2 = boostvector; scopy2 = stdvector; if(!test::CheckEqualContainers(bcopy2, scopy2)) return false; + + if(!vector_unchecked_push_back_test(boostvector, stdvector, dtl::bool_::value>())) + return 1; } return true;