From 750033d8cfa72242a7a912b7861a0951dc03c2b6 Mon Sep 17 00:00:00 2001 From: Alexander Neumann <30894796+Neumann-A@users.noreply.github.com> Date: Sat, 18 May 2024 08:27:55 +0200 Subject: [PATCH 1/9] Remove dep on boost::static_assert --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78acbe2..01e97c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,6 @@ target_link_libraries(boost_container Boost::config Boost::intrusive Boost::move - Boost::static_assert ) target_compile_definitions(boost_container From 59d760c08bd1431b732dcb42d693d772dc61bac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 21 May 2024 14:08:36 +0200 Subject: [PATCH 2/9] Document block_size option in deque_options. --- include/boost/container/deque.hpp | 59 +++--- include/boost/container/detail/tree.hpp | 77 ++++---- include/boost/container/devector.hpp | 199 +++++++++++++++------ include/boost/container/list.hpp | 49 ++--- include/boost/container/node_allocator.hpp | 6 +- include/boost/container/node_handle.hpp | 4 +- include/boost/container/options.hpp | 2 +- include/boost/container/slist.hpp | 51 +++--- include/boost/container/small_vector.hpp | 11 +- include/boost/container/stable_vector.hpp | 60 ++++--- include/boost/container/string.hpp | 51 +++--- include/boost/container/vector.hpp | 58 +++--- test/deque_test.cpp | 11 +- test/devector_test.cpp | 15 +- test/list_test.cpp | 34 ++-- test/list_test.hpp | 96 ++++++---- test/map_test.cpp | 9 + test/map_test.hpp | 107 +++++++++-- test/movable_int.hpp | 12 ++ test/set_test.cpp | 9 + test/set_test.hpp | 42 ++--- test/slist_test.cpp | 43 ++++- test/small_vector_test.cpp | 4 +- test/stable_vector_test.cpp | 11 +- test/vector_test.cpp | 10 +- test/vector_test.hpp | 41 ++++- 26 files changed, 712 insertions(+), 359 deletions(-) diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index e599581..188f65a 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -1318,28 +1318,13 @@ class deque : protected deque_base::type, || allocator_traits_type::is_always_equal::value) { if (BOOST_LIKELY(this != &x)) { - allocator_type &this_alloc = this->alloc(); - allocator_type &x_alloc = x.alloc(); - const bool propagate_alloc = allocator_traits_type:: - propagate_on_container_move_assignment::value; - dtl::bool_ flag; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - dtl::move_alloc(this_alloc, x_alloc, flag); - dtl::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); - //Nothrow swap - this->swap_members(x); - } - //Else do a one by one move - else{ - this->assign( boost::make_move_iterator(x.begin()) - , boost::make_move_iterator(x.end())); - } + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -2378,6 +2363,30 @@ class deque : protected deque_base::type, #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + void priv_move_assign(BOOST_RV_REF(deque) x, dtl::bool_ /*steal_resources*/) + { + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + dtl::bool_ flag; + dtl::move_alloc(this->alloc(), x.alloc(), flag); + dtl::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); + //Nothrow swap + this->swap_members(x); + } + + void priv_move_assign(BOOST_RV_REF(deque) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->alloc() == x.alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); + } + } + inline size_type priv_index_of(const_iterator p) const { BOOST_ASSERT(this->cbegin() <= p); @@ -2493,7 +2502,8 @@ class deque : protected deque_base::type, void priv_destroy_range(iterator p, iterator p2) { - if(!Base::traits_t::trivial_dctr){ + (void)p; (void)p2; + BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){ for(;p != p2; ++p){ allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); } @@ -2502,7 +2512,8 @@ class deque : protected deque_base::type, void priv_destroy_range(pointer p, pointer p2) { - if(!Base::traits_t::trivial_dctr){ + (void)p; (void)p2; + BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){ for(;p != p2; ++p){ allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); } diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index b5430fe..7add430 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -688,40 +688,13 @@ class tree boost::container::dtl::is_nothrow_move_assignable::value) { if (BOOST_LIKELY(this != &x)) { - NodeAlloc &this_alloc = this->node_alloc(); - NodeAlloc &x_alloc = x.node_alloc(); - const bool propagate_alloc = allocator_traits:: - propagate_on_container_move_assignment::value; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - //Destroy - this->clear(); - //Move allocator if needed - this->AllocHolder::move_assign_alloc(x); - //Obtain resources - this->icont() = boost::move(x.icont()); - } - //Else do a one by one move - else{ - //Transfer all the nodes to a temporary tree - //If anything goes wrong, all the nodes will be destroyed - //automatically - Icont other_tree(::boost::move(this->icont())); - - //Now recreate the source tree reusing nodes stored by other_tree - this->icont().clone_from - (::boost::move(x.icont()) - , RecyclingCloner(*this, other_tree) - , Destroyer(this->node_alloc())); - - //If there are remaining nodes, destroy them - NodePtr p; - while((p = other_tree.unlink_leftmost_without_rebalance())){ - AllocHolder::destroy_node(p); - } - } + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -895,6 +868,42 @@ class tree private: + void priv_move_assign(BOOST_RV_REF(tree) x, dtl::bool_ /*steal_resources*/) + { + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(x); + //Obtain resources + this->icont() = boost::move(x.icont()); + } + + void priv_move_assign(BOOST_RV_REF(tree) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->node_alloc() == x.node_alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + //Transfer all the nodes to a temporary tree + //If anything goes wrong, all the nodes will be destroyed + //automatically + Icont other_tree(::boost::move(this->icont())); + + //Now recreate the source tree reusing nodes stored by other_tree + this->icont().clone_from + (::boost::move(x.icont()) + , RecyclingCloner(*this, other_tree) + , Destroyer(this->node_alloc())); + + //If there are remaining nodes, destroy them + NodePtr p; + while ((p = other_tree.unlink_leftmost_without_rebalance())) { + AllocHolder::destroy_node(p); + } + } + } template iiterator priv_insert_or_assign_commit diff --git a/include/boost/container/devector.hpp b/include/boost/container/devector.hpp index 27e11f0..1020c5d 100644 --- a/include/boost/container/devector.hpp +++ b/include/boost/container/devector.hpp @@ -512,20 +512,21 @@ class devector const devector &x = rhs; if (this == &x) { return *this; } // skip self - BOOST_IF_CONSTEXPR(allocator_traits_type::propagate_on_container_copy_assignment::value) + const bool do_propagate = allocator_traits_type::propagate_on_container_copy_assignment::value; + BOOST_IF_CONSTEXPR(do_propagate) { - allocator_type &this_alloc = this->get_allocator_ref(); - const allocator_type &other_alloc = x.get_allocator_ref(); - if (this_alloc != other_alloc) - { - // new allocator cannot free existing storage - this->clear(); - this->deallocate_buffer(); - m_.capacity = 0u; - m_.buffer = pointer(); - } - - this_alloc = other_alloc; + allocator_type &this_alloc = this->get_allocator_ref(); + const allocator_type &other_alloc = x.get_allocator_ref(); + if (this_alloc != other_alloc) + { + // new allocator cannot free existing storage + this->clear(); + this->deallocate_buffer(); + m_.capacity = 0u; + m_.buffer = pointer(); + } + dtl::bool_ flag; + dtl::assign_alloc(this_alloc, other_alloc, flag); } size_type n = x.size(); @@ -565,53 +566,16 @@ class devector BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) { - BOOST_CONSTEXPR_OR_CONST bool copy_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; - - BOOST_IF_CONSTEXPR (copy_alloc || get_allocator_ref() == x.get_allocator_ref()) - { - this->clear(); - this->deallocate_buffer(); - - if (copy_alloc) - { - this->get_allocator_ref() = boost::move(x.get_allocator_ref()); - } - - m_.capacity = x.m_.capacity; - m_.buffer = x.m_.buffer; - m_.front_idx = x.m_.front_idx; - m_.back_idx = x.m_.back_idx; - - // leave x in valid state - x.m_.capacity = 0u; - x.m_.buffer = pointer(); - x.m_.back_idx = x.m_.front_idx = 0; + if (BOOST_LIKELY(this != &x)) { + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } - else - { - // if the allocator shouldn't be copied and they do not compare equal - // we can't steal memory. - - move_iterator xbegin = boost::make_move_iterator(x.begin()); - move_iterator xend = boost::make_move_iterator(x.end()); - - if (copy_alloc) - { - get_allocator_ref() = boost::move(x.get_allocator_ref()); - } - - if (m_.capacity >= x.size()) - { - overwrite_buffer(xbegin, xend); - } - else - { - allocate_and_copy_range(xbegin, xend); - } - } - BOOST_ASSERT(invariants_ok()); - return *this; } @@ -1309,6 +1273,78 @@ class devector return m_.buffer[m_.front_idx + n]; } + //! Requires: size() >= n. + //! + //! Effects: Returns an iterator to the nth element + //! from the beginning of the container. Returns end() + //! if n == size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline + iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(n <= size()); + return iterator(m_.buffer + (m_.front_idx + n)); + } + + //! Requires: size() >= n. + //! + //! Effects: Returns a const_iterator to the nth element + //! from the beginning of the container. Returns end() + //! if n == size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline + const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(n <= size()); + return const_iterator(m_.buffer + (m_.front_idx + n)); + } + + //! Requires: begin() <= p <= end(). + //! + //! Effects: Returns the index of the element pointed by p + //! and size() if p == end(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline + size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(p >= begin()); + BOOST_ASSERT(p <= end()); + return static_cast(p - this->begin()); + } + + //! Requires: begin() <= p <= end(). + //! + //! Effects: Returns the index of the element pointed by p + //! and size() if p == end(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline + size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(p >= cbegin()); + BOOST_ASSERT(p <= cend()); + return static_cast(p - this->cbegin()); + } + /** * **Returns**: A reference to the `n`th element in the devector. * @@ -2136,6 +2172,53 @@ class devector private: + void priv_move_assign(BOOST_RV_REF(devector) x, dtl::bool_ /*steal_resources*/) + { + this->clear(); + this->deallocate_buffer(); + + //Move allocator if needed + dtl::bool_ flag; + dtl::move_alloc(this->get_allocator_ref(), x.get_allocator_ref(), flag); + + m_.capacity = x.m_.capacity; + m_.buffer = x.m_.buffer; + m_.front_idx = x.m_.front_idx; + m_.back_idx = x.m_.back_idx; + + // leave x in valid state + x.m_.capacity = 0u; + x.m_.buffer = pointer(); + x.m_.back_idx = x.m_.front_idx = 0; + } + + void priv_move_assign(BOOST_RV_REF(devector) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (get_allocator_ref() == x.get_allocator_ref()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + // We can't steal memory. + move_iterator xbegin = boost::make_move_iterator(x.begin()); + move_iterator xend = boost::make_move_iterator(x.end()); + + //Move allocator if needed + dtl::bool_ flag; + dtl::move_alloc(this->get_allocator_ref(), x.get_allocator_ref(), flag); + + if (m_.capacity >= x.size()) { + overwrite_buffer(xbegin, xend); + } + else { + allocate_and_copy_range(xbegin, xend); + } + } + } + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline size_type pos_to_index(const_iterator i) const { diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index 117e275..6dbd71b 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -343,26 +343,13 @@ class list || allocator_traits_type::is_always_equal::value) { if (BOOST_LIKELY(this != &x)) { - NodeAlloc &this_alloc = this->node_alloc(); - NodeAlloc &x_alloc = x.node_alloc(); - const bool propagate_alloc = allocator_traits_type:: - propagate_on_container_move_assignment::value; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - //Destroy - this->clear(); - //Move allocator if needed - this->AllocHolder::move_assign_alloc(x); - //Obtain resources - this->icont() = boost::move(x.icont()); - } - //Else do a one by one move - else{ - this->assign( boost::make_move_iterator(x.begin()) - , boost::make_move_iterator(x.end())); - } + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -1391,6 +1378,28 @@ class list #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + void priv_move_assign(BOOST_RV_REF(list) x, dtl::bool_ /*steal_resources*/) + { + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(x); + //Obtain resources + this->icont() = boost::move(x.icont()); + } + + void priv_move_assign(BOOST_RV_REF(list) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->node_alloc() == x.node_alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); + } + } + static bool priv_is_linked(const_iterator const position) { const_iterator cur(position); diff --git a/include/boost/container/node_allocator.hpp b/include/boost/container/node_allocator.hpp index d6076f4..a38e96e 100644 --- a/include/boost/container/node_allocator.hpp +++ b/include/boost/container/node_allocator.hpp @@ -8,8 +8,8 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP -#define BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP +#ifndef BOOST_CONTAINER_NODE_ALLOCATOR_HPP +#define BOOST_CONTAINER_NODE_ALLOCATOR_HPP #ifndef BOOST_CONFIG_HPP # include @@ -337,4 +337,4 @@ class node_allocator #include -#endif //#ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP +#endif //#ifndef BOOST_CONTAINER_NODE_ALLOCATOR_HPP diff --git a/include/boost/container/node_handle.hpp b/include/boost/container/node_handle.hpp index 4b6e021..5179022 100644 --- a/include/boost/container/node_handle.hpp +++ b/include/boost/container/node_handle.hpp @@ -232,7 +232,7 @@ class node_handle if(was_nh_non_null){ if(was_this_non_null){ this->destroy_deallocate_node(); - if(nator_traits::propagate_on_container_move_assignment::value){ + BOOST_IF_CONSTEXPR(nator_traits::propagate_on_container_move_assignment::value){ this->node_alloc() = ::boost::move(nh.node_alloc()); } } @@ -336,7 +336,7 @@ class node_handle if(was_nh_non_null){ if(was_this_non_null){ - if(nator_traits::propagate_on_container_swap::value){ + BOOST_IF_CONSTEXPR(nator_traits::propagate_on_container_swap::value){ ::boost::adl_move_swap(this->node_alloc(), nh.node_alloc()); } } diff --git a/include/boost/container/options.hpp b/include/boost/container/options.hpp index 48edd38..ce00b48 100644 --- a/include/boost/container/options.hpp +++ b/include/boost/container/options.hpp @@ -617,7 +617,7 @@ typedef deque_opt<0u, 0u> deque_null_opt; //! Helper metafunction to combine options into a single type to be used //! by \c boost::container::deque. -//! Supported options are: \c boost::container::block_bytes +//! Supported options are: \c boost::container::block_bytes and \c boost::container::block_size #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) template #else diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index a863d1a..0d96927 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -368,28 +368,14 @@ class slist BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) { - slist & sr = x; - if (BOOST_LIKELY(this != &sr)) { - NodeAlloc &this_alloc = this->node_alloc(); - NodeAlloc &x_alloc = sr.node_alloc(); - const bool propagate_alloc = allocator_traits_type:: - propagate_on_container_move_assignment::value; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - //Destroy - this->clear(); - //Move allocator if needed - this->AllocHolder::move_assign_alloc(sr); - //Obtain resources - this->icont() = boost::move(sr.icont()); - } - //Else do a one by one move - else{ - this->assign( boost::make_move_iterator(sr.begin()) - , boost::make_move_iterator(sr.end())); - } + if (BOOST_LIKELY(this != &x)) { + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -1579,6 +1565,27 @@ class slist #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + void priv_move_assign(BOOST_RV_REF(slist) x, dtl::bool_ /*steal_resources*/) + { + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(x); + //Obtain resources + this->icont() = boost::move(x.icont()); + } + + void priv_move_assign(BOOST_RV_REF(slist) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->node_alloc() == x.node_alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); + } + } template void priv_push_front(BOOST_FWD_REF(U) x) diff --git a/include/boost/container/small_vector.hpp b/include/boost/container/small_vector.hpp index 086b30a..860840e 100644 --- a/include/boost/container/small_vector.hpp +++ b/include/boost/container/small_vector.hpp @@ -346,9 +346,10 @@ class small_vector_base public: //Make it public as it will be inherited by small_vector and container //must have this public member - typedef typename real_allocator::type allocator_type; - typedef typename allocator_traits:: - template portable_rebind_alloc::type void_allocator_t; + typedef typename real_allocator::type underlying_allocator_t; + typedef typename allocator_traits:: + template portable_rebind_alloc::type void_underlying_allocator_t; + typedef small_vector_allocatorallocator_type; typedef typename dtl::get_small_vector_opt::type options_t; typedef typename dtl::vector_for_small_vector ::type base_type; @@ -356,12 +357,12 @@ class small_vector_base typedef typename allocator_traits::const_pointer const_pointer; typedef typename allocator_traits::void_pointer void_pointer; typedef typename allocator_traits::const_void_pointer const_void_pointer; - typedef small_vector_allocator small_allocator_type; + private: BOOST_COPYABLE_AND_MOVABLE(small_vector_base) - friend class small_vector_allocator; + friend class small_vector_allocator; inline const_pointer internal_storage() const BOOST_NOEXCEPT_OR_NOTHROW diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index 6718122..b4fbae9 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -872,31 +872,14 @@ class stable_vector BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) { - //for move constructor, no aliasing (&x != this) is assumed. if (BOOST_LIKELY(this != &x)) { - node_allocator_type &this_alloc = this->priv_node_alloc(); - node_allocator_type &x_alloc = x.priv_node_alloc(); - const bool propagate_alloc = allocator_traits_type:: - propagate_on_container_move_assignment::value; - dtl::bool_ flag; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - dtl::move_alloc(this_alloc, x_alloc, flag); - //Take resources - this->index.swap(x.index); - this->priv_swap_members(x); - } - //Else do a one by one move - else{ - this->assign( boost::make_move_iterator(x.begin()) - , boost::make_move_iterator(x.end())); - } + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -1852,6 +1835,35 @@ class stable_vector #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + void priv_move_assign(BOOST_RV_REF(stable_vector) x, dtl::bool_ /*steal_resources*/) + { + //Resources can be transferred if both allocators are + //going to be equal after this function (either propagated or already equal) + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + dtl::bool_ flag; + dtl::move_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); + + //Take resources + this->index = boost::move(x.index); //this also moves the vector's allocator if needed + this->priv_swap_members(x); + } + + void priv_move_assign(BOOST_RV_REF(stable_vector) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->priv_node_alloc() == x.priv_node_alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); + } + } + bool priv_in_range(const_iterator pos) const { return (this->begin() <= pos) && (pos < this->end()); diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index e7cfc23..c78da98 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -913,26 +913,13 @@ class basic_string || allocator_traits_type::is_always_equal::value) { if (BOOST_LIKELY(this != &x)) { - allocator_type &this_alloc = this->alloc(); - allocator_type &x_alloc = x.alloc(); - const bool propagate_alloc = allocator_traits_type:: - propagate_on_container_move_assignment::value; - dtl::bool_ flag; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - dtl::move_alloc(this_alloc, x_alloc, flag); - //Nothrow swap - this->swap_data(x); - } - //Else do a one by one move - else{ - this->assign( x.begin(), x.end()); - } + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -2908,6 +2895,30 @@ class basic_string #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + void priv_move_assign(BOOST_RV_REF(basic_string) x, dtl::bool_ /*steal_resources*/) + { + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + dtl::bool_ flag; + dtl::move_alloc(this->alloc(), x.alloc(), flag); + //Nothrow swap + this->swap_data(x); + } + + void priv_move_assign(BOOST_RV_REF(basic_string) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->alloc() == x.alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + this->assign(x.begin(), x.end()); + } + } + bool priv_reserve_no_null_end(size_type res_arg) { if (res_arg > this->max_size()){ diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 038b8b4..5046be9 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -2531,6 +2531,38 @@ private: x.clear(); } + template + void priv_move_assign_steal_or_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x, dtl::true_type /*data_can_be_always_stolen*/) + { + this->clear(); + if (BOOST_LIKELY(!!this->m_holder.m_start)) + this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity); + this->m_holder.steal_resources(x.m_holder); + } + + template + void priv_move_assign_steal_or_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x, dtl::false_type /*data_can_be_always_stolen*/) + { + const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; + allocator_type& this_alloc = this->m_holder.alloc(); + allocator_type& x_alloc = x.m_holder.alloc(); + + //In this allocator move constructor the allocator might will be propagated, but to support small_vector-like + //types, we need to check the currently owned buffers to know if they are propagable. + const bool is_buffer_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc); + + if (is_buffer_propagable_from_x) { + this->priv_move_assign_steal_or_assign(boost::move(x), dtl::true_type()); + } + //Else do a one by one move. Also, clear the source as users find confusing + //elements are still alive in the source container. + else { + this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin())) + , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end())) ); + x.clear(); + } + } + template void priv_move_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x , typename dtl::disable_if_or @@ -2542,30 +2574,16 @@ private: //for move assignment, no aliasing (&x != this) is assumed. //x.size() == 0 is allowed for buggy std libraries. BOOST_ASSERT(this != &x || x.size() == 0); - allocator_type &this_alloc = this->m_holder.alloc(); - allocator_type &x_alloc = x.m_holder.alloc(); + const bool alloc_is_always_equal = allocator_traits_type::is_always_equal::value; const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; + const bool partially_propagable_alloc = allocator_traits_type::is_partially_propagable::value; + const bool data_can_be_always_be_stolen = alloc_is_always_equal || (propagate_alloc && !partially_propagable_alloc); - //In this allocator move constructor the allocator maybe will be propagated -----------------------v - const bool is_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc); + this->priv_move_assign_steal_or_assign(boost::move(x), dtl::bool_()); - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(is_propagable_from_x){ - this->clear(); - if(BOOST_LIKELY(!!this->m_holder.m_start)) - this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity); - this->m_holder.steal_resources(x.m_holder); - } - //Else do a one by one move. Also, clear the source as users find confusing - //elements are still alive in the source container. - else{ - this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin())) - , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end() )) - ); - x.clear(); - } //Move allocator if needed + allocator_type& this_alloc = this->m_holder.alloc(); + allocator_type& x_alloc = x.m_holder.alloc(); dtl::move_alloc(this_alloc, x_alloc, dtl::bool_()); } diff --git a/test/deque_test.cpp b/test/deque_test.cpp index f81069c..849699e 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -307,14 +307,17 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) + return 1; + if (test::vector_test()) return 1; return 0; } diff --git a/test/devector_test.cpp b/test/devector_test.cpp index b637c85..23327d4 100644 --- a/test/devector_test.cpp +++ b/test/devector_test.cpp @@ -3903,7 +3903,7 @@ struct GetAllocatorCont template struct apply { - typedef vector< ValueType + typedef devector< ValueType , typename allocator_traits ::template portable_rebind_alloc::type > type; @@ -3962,14 +3962,19 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) + return 1; + if (test::vector_test()) + return 1; + if (test::vector_test()) return 1; return 0; } diff --git a/test/list_test.cpp b/test/list_test.cpp index c371df8..3a7f004 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "dummy_test_allocator.hpp" #include @@ -78,9 +79,9 @@ struct GetAllocatorCont struct apply { typedef list< ValueType - , typename allocator_traits + , typename allocator_traits ::template portable_rebind_alloc::type - > type; + > type; }; }; @@ -91,9 +92,11 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; if(test::list_test()) return 1; + if(test::list_test()) return 1; if(test::list_test()) @@ -102,6 +105,8 @@ int test_cont_variants() return 1; if(test::list_test()) return 1; + if (test::list_test()) + return 1; return 0; } @@ -171,20 +176,27 @@ int main () //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// - // int variants - if (test::list_test >, true>()) + if (test_cont_variants< new_allocator >()) { + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; return 1; - if (test::list_test, true>()) + } + + if (test_cont_variants< std::allocator >()) { + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; return 1; + } if (test::list_test >, true>()) return 1; - if (test::list_test, true>()) - return 1; - if (test::list_test, true>()) - return 1; - if (test::list_test, true>()) - return 1; + if (test::list_test >, false>()) + return 1; +/* + // boost::container::allocator + if (test_cont_variants< allocator >()) { + std::cerr << "test_cont_variants< allocator > failed" << std::endl; + return 1; + } +*/ //////////////////////////////////// // Emplace testing //////////////////////////////////// diff --git a/test/list_test.hpp b/test/list_test.hpp index e07b4cc..404c5b1 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -166,6 +166,61 @@ struct list_pop_back_function } }; +template +int list_move_assignable_only(boost::container::dtl::false_type) +{ + return 0; +} + +//Function to check if both sets are equal +template < class MyBoostList + , bool DoublyLinked > +int list_move_assignable_only(boost::container::dtl::true_type) +{ + typedef std::list MyStdList; + typedef typename MyBoostList::value_type IntType; + const std::size_t max = 100u; + typedef list_push_data_function push_data_t; + + { + ::boost::movelib::unique_ptr const stdlistp = ::boost::movelib::make_unique(100u); + ::boost::movelib::unique_ptr const boostlistp = ::boost::movelib::make_unique(100u); + MyBoostList& boostlist = *boostlistp; + MyStdList& stdlist = *stdlistp; + + if (push_data_t::execute(max, boostlist, stdlist)) { + return 1; + } + + IntType aux_vect[50]; + for (int i = 0; i < 50; ++i) { + aux_vect[i] = -1; + } + int aux_vect2[50]; + for (int i = 0; i < 50; ++i) { + aux_vect2[i] = -1; + } + boostlist.assign(boost::make_move_iterator(&aux_vect[0]) + , boost::make_move_iterator(&aux_vect[50])); + stdlist.assign(&aux_vect2[0], &aux_vect2[50]); + if (!CheckEqualContainers(boostlist, stdlist)) return 1; + + for (int i = 0; i < 50; ++i) { + aux_vect[i] = -1; + } + + for (int i = 0; i < 50; ++i) { + aux_vect2[i] = -1; + } + boostlist.assign(boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) + , boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); + stdlist.assign(&aux_vect2[0], &aux_vect2[50]); + if (!CheckEqualContainers(boostlist, stdlist)) return 1; + } + return 0; +} + template int list_test (bool copied_allocators_equal = true) @@ -203,9 +258,10 @@ int list_test (bool copied_allocators_equal = true) ::boost::movelib::unique_ptr const boostlistp = ::boost::movelib::make_unique(100u); ::boost::movelib::unique_ptr const boostlistp2 = ::boost::movelib::make_unique(); *boostlistp2 = ::boost::move(*boostlistp); - if(!test::CheckEqualContainers(*boostlistp2, *stdlistp)) return 1; + if (!test::CheckEqualContainers(*boostlistp2, *stdlistp)) return 1; } + ::boost::movelib::unique_ptr const pboostlist = ::boost::movelib::make_unique(); ::boost::movelib::unique_ptr const pstdlist = ::boost::movelib::make_unique(); @@ -228,35 +284,9 @@ int list_test (bool copied_allocators_equal = true) stdlist.pop_front(); if(!CheckEqualContainers(boostlist, stdlist)) return 1; - { - IntType aux_vect[50]; - for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); - } - int aux_vect2[50]; - for(int i = 0; i < 50; ++i){ - aux_vect2[i] = -1; - } - boostlist.assign(boost::make_move_iterator(&aux_vect[0]) - ,boost::make_move_iterator(&aux_vect[50])); - stdlist.assign(&aux_vect2[0], &aux_vect2[50]); - if(!CheckEqualContainers(boostlist, stdlist)) return 1; - - for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); - } - - for(int i = 0; i < 50; ++i){ - aux_vect2[i] = -1; - } - boostlist.assign(boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) - ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); - stdlist.assign(&aux_vect2[0], &aux_vect2[50]); - if(!CheckEqualContainers(boostlist, stdlist)) return 1; - } - + if (0 != list_move_assignable_only(dtl::bool_::value>())) + return 1; + if(copied_allocators_equal){ boostlist.sort(); stdlist.sort(); @@ -274,8 +304,7 @@ int list_test (bool copied_allocators_equal = true) { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = -1; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -294,8 +323,7 @@ int list_test (bool copied_allocators_equal = true) return 1; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = -1; } for(int i = 0; i < 50; ++i){ diff --git a/test/map_test.cpp b/test/map_test.cpp index 9d3a145..a0c1fbe 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -557,6 +557,15 @@ int main () std::cout << "Error in map_test, red_black_tree>" << std::endl; return 1; } + + if (0 != test::map_test + < GetAllocatorMap, red_black_tree>::apply::map_type + , MyStdMap + , GetAllocatorMap, red_black_tree>::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, red_black_tree>" << std::endl; + return 1; + } } //////////////////////////////////// diff --git a/test/map_test.hpp b/test/map_test.hpp index 1922526..5cbfa6b 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -54,6 +54,78 @@ void map_test_rebalanceable(C &c, boost::container::dtl::true_type) c.rebalance(); } +template +int map_move_assignable_only(boost::container::dtl::false_type) +{ + return 0; +} + +//Function to check if both sets are equal +template +int map_move_assignable_only(boost::container::dtl::true_type) +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[(std::size_t)MaxElem]; + for (int i = 0; i < MaxElem; ++i) { + IntType i1(i / 2); + IntType i2(i / 2); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + typedef typename MyStdMap::value_type StdValueType; + typedef typename MyStdMap::key_type StdKeyType; + typedef typename MyStdMap::mapped_type StdMappedType; + StdValueType aux_vect2[(std::size_t)MaxElem]; + for (int i = 0; i < MaxElem; ++i) { + new(&aux_vect2[i])StdValueType(StdKeyType(i / 2), StdMappedType(i / 2)); + } + + IntPairType aux_vect3[(std::size_t)MaxElem]; + for (int i = 0; i < MaxElem; ++i) { + IntType i1(i / 2); + IntType i2(i / 2); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + ::boost::movelib::unique_ptr const pboostmap2 = ::boost::movelib::make_unique + (boost::make_move_iterator(&aux_vect[0]) + , boost::make_move_iterator(&aux_vect[0] + MaxElem)); + ::boost::movelib::unique_ptr const pstdmap2 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem); + ::boost::movelib::unique_ptr const pboostmultimap2 = ::boost::movelib::make_unique + (boost::make_move_iterator(&aux_vect3[0]) + , boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + ::boost::movelib::unique_ptr const pstdmultimap2 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem); + MyBoostMap& boostmap2 = *pboostmap2; + MyStdMap& stdmap2 = *pstdmap2; + + /* fix assignable */ + { + IntType i0(0); + IntType i1(1); + boostmap2[::boost::move(i0)] = ::boost::move(i1); + } + { + IntType i1(1); + boostmap2[IntType(0)] = ::boost::move(i1); + } + stdmap2[0] = 1; + if (!CheckEqualContainers(boostmap2, stdmap2)) return 1; + + + return 0; +} + template int map_test_copyable(boost::container::dtl::true_type) { - typedef typename MyBoostMap::key_type IntType; - typedef dtl::pair IntPairType; + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; typedef typename MyStdMap::value_type StdPairType; ::boost::movelib::unique_ptr const pboostmap = ::boost::movelib::make_unique(); @@ -366,6 +438,9 @@ int map_test_step(MyBoostMap &, MyStdMap &, MyBoostMultiMap &, MyStdMultiMap &) return 1; } + if (0 != map_move_assignable_only(dtl::bool_::value>())) + return 1; + { IntType i0(0); boostmap2.erase(i0); @@ -373,17 +448,6 @@ int map_test_step(MyBoostMap &, MyStdMap &, MyBoostMultiMap &, MyStdMultiMap &) stdmap2.erase(0); stdmultimap2.erase(0); } - { - IntType i0(0); - IntType i1(1); - boostmap2[::boost::move(i0)] = ::boost::move(i1); - } - { - IntType i1(1); - boostmap2[IntType(0)] = ::boost::move(i1); - } - stdmap2[0] = 1; - if(!CheckEqualContainers(boostmap2, stdmap2)) return 1; } return 0; } @@ -819,12 +883,12 @@ int map_test_indexing(MyBoostMap &boostmap, MyStdMap &stdmap, MyBoostMultiMap &b IntType i2(i); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - +/* for(int i = 0; i < MaxElem; ++i){ boostmap[boost::move(aux_vect[i].first)] = boost::move(aux_vect[i].second); stdmap[i] = i; } - +*/ if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; } @@ -934,14 +998,20 @@ int map_test_insert_or_assign_impl() return 0; } +template< class MyBoostMap, class StdMap, class Copyable> +int map_test_insert_or_assign(dtl::bool_, Copyable)//noncopyable +{ + return 0; +} + template< class MyBoostMap, class StdMap> -int map_test_insert_or_assign(dtl::bool_ )//noncopyable +int map_test_insert_or_assign(dtl::bool_, dtl::bool_ )//noncopyable { return map_test_insert_or_assign_impl(); } template< class MyBoostMap, class StdMap> -int map_test_insert_or_assign(dtl::bool_ )//copyable +int map_test_insert_or_assign(dtl::bool_, dtl::bool_ )//copyable { int r = map_test_insert_or_assign_impl(); if (r) @@ -1165,6 +1235,7 @@ int map_test() MyBoostMultiMap &boostmultimap = *pboostmultimap; MyStdMultiMap &stdmultimap = *pstdmultimap; typedef dtl::bool_::value> copyable_t; + typedef dtl::bool_::value> move_assignable_t; if (map_test_step(boostmap, stdmap, boostmultimap, stdmultimap)) return 1; @@ -1190,7 +1261,7 @@ int map_test() if (map_test_merge(boostmap, stdmap, boostmultimap, stdmultimap)) return 1; - if (map_test_insert_or_assign(copyable_t())) + if (map_test_insert_or_assign(move_assignable_t(), copyable_t())) return 1; if(map_test_copyable(copyable_t())) diff --git a/test/movable_int.hpp b/test/movable_int.hpp index beab5b3..58cdf89 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -37,6 +37,11 @@ struct is_move_assignable static const bool value = true; }; +template +struct is_move_constructible +{ + static const bool value = true; +}; ///////////////////////// @@ -594,6 +599,13 @@ struct life_count< non_copymovable_int > { return c == non_copymovable_int::count; } }; +template<> +struct is_move_constructible +{ + static const bool value = false; +}; + + } //namespace test { } //namespace container { } //namespace boost { diff --git a/test/set_test.cpp b/test/set_test.cpp index 3999ace..756138a 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -544,6 +544,15 @@ int main () std::cout << "Error in set_test, red_black_tree>" << std::endl; return 1; } + + if (0 != test::set_test + < GetAllocatorSet, red_black_tree>::apply::set_type + , MyStdSet + , GetAllocatorSet, red_black_tree>::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test, red_black_tree>" << std::endl; + return 1; + } } //////////////////////////////////// diff --git a/test/set_test.hpp b/test/set_test.hpp index 9395640..5846748 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -161,8 +161,7 @@ int set_test () { //Set(beg, end, compare) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = i/2; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -170,8 +169,7 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = i/2; } ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique (boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0]+50), typename MyBoostSet::key_compare()); @@ -185,8 +183,7 @@ int set_test () { //Set(beg, end, alloc) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = i/2; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -194,8 +191,7 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = i/2; } ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique (boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0]+50), typename MyBoostSet::allocator_type()); @@ -209,8 +205,7 @@ int set_test () { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = i/2; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -218,8 +213,7 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = i/2; } ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique @@ -249,8 +243,7 @@ int set_test () //ordered range insertion for(int i = 0; i < 50; ++i){ - IntType move_me(i); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = i; } for(int i = 0; i < 50; ++i){ @@ -258,8 +251,7 @@ int set_test () } for(int i = 0; i < 50; ++i){ - IntType move_me(i); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = i; } //some comparison operators @@ -410,8 +402,7 @@ int set_test () { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = -1; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -419,8 +410,7 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = -1; } boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50)); @@ -455,8 +445,7 @@ int set_test () { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = -1; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -464,20 +453,17 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = -1; } IntType aux_vect4[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect4[i] = boost::move(move_me); + aux_vect4[i] = -1; } IntType aux_vect5[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect5[i] = boost::move(move_me); + aux_vect5[i] = -1; } boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50)); diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 932c65c..ab648a2 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -9,6 +9,7 @@ ////////////////////////////////////////////////////////////////////////////// #include #include +#include #include #include "dummy_test_allocator.hpp" @@ -54,6 +55,32 @@ struct GetAllocatorCont }; }; +template +int test_cont_variants() +{ + typedef typename GetAllocatorCont::template apply::type MyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; + + if(test::list_test()) + return 1; + + if(test::list_test()) + return 1; + if(test::list_test()) + return 1; + if(test::list_test()) + return 1; + if(test::list_test()) + return 1; + if (test::list_test()) + return 1; + + return 0; +} + bool test_support_for_initializer_list() { #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -168,18 +195,18 @@ int main () //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// - if (test::list_test >, false>()) + if (test_cont_variants< new_allocator >()) { + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; return 1; - if (test::list_test, false>()) + } + if (test_cont_variants< std::allocator >()) { + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; + return 1; + } + if (test::list_test >, false>()) return 1; if (test::list_test >, false>()) return 1; - if (test::list_test, false>()) - return 1; - if (test::list_test, false>()) - return 1; - if (test::list_test, false>()) - return 1; //////////////////////////////////// // Emplace testing diff --git a/test/small_vector_test.cpp b/test/small_vector_test.cpp index 8d1aaf5..2b32e5a 100644 --- a/test/small_vector_test.cpp +++ b/test/small_vector_test.cpp @@ -193,10 +193,10 @@ int main() if(!test_swap()) return 1; - if(test::vector_test< small_vector >()) + if (test::vector_test< small_vector >()) return 1; - if(test::vector_test< small_vector >()) + if (test::vector_test< small_vector >()) return 1; if (test_cont_variants< new_allocator >()) diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp index 0d64628..bdbe4cb 100644 --- a/test/stable_vector_test.cpp +++ b/test/stable_vector_test.cpp @@ -72,14 +72,17 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) + return 1; + if (test::vector_test()) return 1; return 0; diff --git a/test/vector_test.cpp b/test/vector_test.cpp index d896bdf..ed367af 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include "check_equal_containers.hpp" @@ -129,13 +131,13 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyCopyCont; typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; if (test::vector_test()) return 1; diff --git a/test/vector_test.hpp b/test/vector_test.hpp index 9ebe4a0..8b54380 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -269,6 +269,8 @@ bool vector_copyable_only(MyBoostVector &boostvector, MyStdVector &stdvector, bo return true; } + + template int vector_move_assignable_only(boost::container::dtl::false_type) { @@ -345,9 +347,7 @@ int vector_move_assignable_only(boost::container::dtl::true_type) //Initialize values IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType new_int(-1); - BOOST_CONTAINER_STATIC_ASSERT((boost::container::test::is_copyable::value == false)); - aux_vect[i] = boost::move(new_int); + aux_vect[i] = -1; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -374,8 +374,7 @@ int vector_move_assignable_only(boost::container::dtl::true_type) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType new_int(-i); - aux_vect[i] = boost::move(new_int); + aux_vect[i] = -i; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -391,8 +390,7 @@ int vector_move_assignable_only(boost::container::dtl::true_type) if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; for(int i = 0; i < 50; ++i){ - IntType new_int(-i); - aux_vect[i] = boost::move(new_int); + aux_vect[i] = -i; } for(int i = 0; i < 50; ++i){ @@ -511,6 +509,30 @@ int vector_move_assignable_only(boost::container::dtl::true_type) return 0; } +template +int vector_test_fully_propagable(dtl::true_ /* fully_propagable */) +{ + typedef std::vector MyStdVector; + { + //operator=(Vector &&) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100u); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100u); + ::boost::movelib::unique_ptr const boostvectorp2 = + ::boost::movelib::make_unique(); + *boostvectorp2 = ::boost::move(*boostvectorp); + if (!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; + } + return 0; +} + +template +int vector_test_fully_propagable(dtl::false_ /* fully_propagable */) +{ + return 0; +} + template int vector_test() { @@ -551,7 +573,10 @@ int vector_test() if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; } - if (0 != vector_move_assignable_only< MyBoostVector>(dtl::bool_::value>())) + if (0 != vector_test_fully_propagable + ( dtl::bool_< !allocator_traits::is_partially_propagable::value >() )) return 1; + + if (0 != vector_move_assignable_only< MyBoostVector>(dtl::bool_::value>())) return 1; std::cout << std::endl << "Test OK!" << std::endl; From 292bab35c6019dfe48b1b547efec5302044326c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 21 May 2024 14:11:30 +0200 Subject: [PATCH 3/9] Revert accidental commit --- include/boost/container/deque.hpp | 59 +++--- include/boost/container/detail/tree.hpp | 77 ++++---- include/boost/container/devector.hpp | 199 ++++++--------------- include/boost/container/list.hpp | 49 +++-- include/boost/container/node_allocator.hpp | 6 +- include/boost/container/node_handle.hpp | 4 +- include/boost/container/options.hpp | 2 +- include/boost/container/slist.hpp | 51 +++--- include/boost/container/small_vector.hpp | 11 +- include/boost/container/stable_vector.hpp | 60 +++---- include/boost/container/string.hpp | 51 +++--- include/boost/container/vector.hpp | 58 +++--- test/deque_test.cpp | 11 +- test/devector_test.cpp | 15 +- test/list_test.cpp | 34 ++-- test/list_test.hpp | 96 ++++------ test/map_test.cpp | 9 - test/map_test.hpp | 107 ++--------- test/movable_int.hpp | 12 -- test/set_test.cpp | 9 - test/set_test.hpp | 42 +++-- test/slist_test.cpp | 43 +---- test/small_vector_test.cpp | 4 +- test/stable_vector_test.cpp | 11 +- test/vector_test.cpp | 10 +- test/vector_test.hpp | 41 +---- 26 files changed, 359 insertions(+), 712 deletions(-) diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index 188f65a..e599581 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -1318,13 +1318,28 @@ class deque : protected deque_base::type, || allocator_traits_type::is_always_equal::value) { if (BOOST_LIKELY(this != &x)) { - //We know resources can be transferred at comiple time if both allocators are - //always equal or the allocator is going to be propagated - const bool can_steal_resources_alloc - = allocator_traits_type::propagate_on_container_move_assignment::value - || allocator_traits_type::is_always_equal::value; - dtl::bool_ flag; - this->priv_move_assign(boost::move(x), flag); + allocator_type &this_alloc = this->alloc(); + allocator_type &x_alloc = x.alloc(); + const bool propagate_alloc = allocator_traits_type:: + propagate_on_container_move_assignment::value; + dtl::bool_ flag; + const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; + //Resources can be transferred if both allocators are + //going to be equal after this function (either propagated or already equal) + if(propagate_alloc || allocators_equal){ + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + dtl::move_alloc(this_alloc, x_alloc, flag); + dtl::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); + //Nothrow swap + this->swap_members(x); + } + //Else do a one by one move + else{ + this->assign( boost::make_move_iterator(x.begin()) + , boost::make_move_iterator(x.end())); + } } return *this; } @@ -2363,30 +2378,6 @@ class deque : protected deque_base::type, #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: - void priv_move_assign(BOOST_RV_REF(deque) x, dtl::bool_ /*steal_resources*/) - { - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - dtl::bool_ flag; - dtl::move_alloc(this->alloc(), x.alloc(), flag); - dtl::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); - //Nothrow swap - this->swap_members(x); - } - - void priv_move_assign(BOOST_RV_REF(deque) x, dtl::bool_ /*steal_resources*/) - { - //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime - //Resources can be transferred if both allocators are equal - if (this->alloc() == x.alloc()) { - this->priv_move_assign(boost::move(x), dtl::true_()); - } - else { - this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); - } - } - inline size_type priv_index_of(const_iterator p) const { BOOST_ASSERT(this->cbegin() <= p); @@ -2502,8 +2493,7 @@ class deque : protected deque_base::type, void priv_destroy_range(iterator p, iterator p2) { - (void)p; (void)p2; - BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){ + if(!Base::traits_t::trivial_dctr){ for(;p != p2; ++p){ allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); } @@ -2512,8 +2502,7 @@ class deque : protected deque_base::type, void priv_destroy_range(pointer p, pointer p2) { - (void)p; (void)p2; - BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){ + if(!Base::traits_t::trivial_dctr){ for(;p != p2; ++p){ allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); } diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 7add430..b5430fe 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -688,13 +688,40 @@ class tree boost::container::dtl::is_nothrow_move_assignable::value) { if (BOOST_LIKELY(this != &x)) { - //We know resources can be transferred at comiple time if both allocators are - //always equal or the allocator is going to be propagated - const bool can_steal_resources_alloc - = allocator_traits_type::propagate_on_container_move_assignment::value - || allocator_traits_type::is_always_equal::value; - dtl::bool_ flag; - this->priv_move_assign(boost::move(x), flag); + NodeAlloc &this_alloc = this->node_alloc(); + NodeAlloc &x_alloc = x.node_alloc(); + const bool propagate_alloc = allocator_traits:: + propagate_on_container_move_assignment::value; + const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; + //Resources can be transferred if both allocators are + //going to be equal after this function (either propagated or already equal) + if(propagate_alloc || allocators_equal){ + //Destroy + this->clear(); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(x); + //Obtain resources + this->icont() = boost::move(x.icont()); + } + //Else do a one by one move + else{ + //Transfer all the nodes to a temporary tree + //If anything goes wrong, all the nodes will be destroyed + //automatically + Icont other_tree(::boost::move(this->icont())); + + //Now recreate the source tree reusing nodes stored by other_tree + this->icont().clone_from + (::boost::move(x.icont()) + , RecyclingCloner(*this, other_tree) + , Destroyer(this->node_alloc())); + + //If there are remaining nodes, destroy them + NodePtr p; + while((p = other_tree.unlink_leftmost_without_rebalance())){ + AllocHolder::destroy_node(p); + } + } } return *this; } @@ -868,42 +895,6 @@ class tree private: - void priv_move_assign(BOOST_RV_REF(tree) x, dtl::bool_ /*steal_resources*/) - { - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - this->AllocHolder::move_assign_alloc(x); - //Obtain resources - this->icont() = boost::move(x.icont()); - } - - void priv_move_assign(BOOST_RV_REF(tree) x, dtl::bool_ /*steal_resources*/) - { - //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime - //Resources can be transferred if both allocators are equal - if (this->node_alloc() == x.node_alloc()) { - this->priv_move_assign(boost::move(x), dtl::true_()); - } - else { - //Transfer all the nodes to a temporary tree - //If anything goes wrong, all the nodes will be destroyed - //automatically - Icont other_tree(::boost::move(this->icont())); - - //Now recreate the source tree reusing nodes stored by other_tree - this->icont().clone_from - (::boost::move(x.icont()) - , RecyclingCloner(*this, other_tree) - , Destroyer(this->node_alloc())); - - //If there are remaining nodes, destroy them - NodePtr p; - while ((p = other_tree.unlink_leftmost_without_rebalance())) { - AllocHolder::destroy_node(p); - } - } - } template iiterator priv_insert_or_assign_commit diff --git a/include/boost/container/devector.hpp b/include/boost/container/devector.hpp index 1020c5d..27e11f0 100644 --- a/include/boost/container/devector.hpp +++ b/include/boost/container/devector.hpp @@ -512,21 +512,20 @@ class devector const devector &x = rhs; if (this == &x) { return *this; } // skip self - const bool do_propagate = allocator_traits_type::propagate_on_container_copy_assignment::value; - BOOST_IF_CONSTEXPR(do_propagate) + BOOST_IF_CONSTEXPR(allocator_traits_type::propagate_on_container_copy_assignment::value) { - allocator_type &this_alloc = this->get_allocator_ref(); - const allocator_type &other_alloc = x.get_allocator_ref(); - if (this_alloc != other_alloc) - { - // new allocator cannot free existing storage - this->clear(); - this->deallocate_buffer(); - m_.capacity = 0u; - m_.buffer = pointer(); - } - dtl::bool_ flag; - dtl::assign_alloc(this_alloc, other_alloc, flag); + allocator_type &this_alloc = this->get_allocator_ref(); + const allocator_type &other_alloc = x.get_allocator_ref(); + if (this_alloc != other_alloc) + { + // new allocator cannot free existing storage + this->clear(); + this->deallocate_buffer(); + m_.capacity = 0u; + m_.buffer = pointer(); + } + + this_alloc = other_alloc; } size_type n = x.size(); @@ -566,16 +565,53 @@ class devector BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) { - if (BOOST_LIKELY(this != &x)) { - //We know resources can be transferred at comiple time if both allocators are - //always equal or the allocator is going to be propagated - const bool can_steal_resources_alloc - = allocator_traits_type::propagate_on_container_move_assignment::value - || allocator_traits_type::is_always_equal::value; - dtl::bool_ flag; - this->priv_move_assign(boost::move(x), flag); + BOOST_CONSTEXPR_OR_CONST bool copy_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; + + BOOST_IF_CONSTEXPR (copy_alloc || get_allocator_ref() == x.get_allocator_ref()) + { + this->clear(); + this->deallocate_buffer(); + + if (copy_alloc) + { + this->get_allocator_ref() = boost::move(x.get_allocator_ref()); + } + + m_.capacity = x.m_.capacity; + m_.buffer = x.m_.buffer; + m_.front_idx = x.m_.front_idx; + m_.back_idx = x.m_.back_idx; + + // leave x in valid state + x.m_.capacity = 0u; + x.m_.buffer = pointer(); + x.m_.back_idx = x.m_.front_idx = 0; } + else + { + // if the allocator shouldn't be copied and they do not compare equal + // we can't steal memory. + + move_iterator xbegin = boost::make_move_iterator(x.begin()); + move_iterator xend = boost::make_move_iterator(x.end()); + + if (copy_alloc) + { + get_allocator_ref() = boost::move(x.get_allocator_ref()); + } + + if (m_.capacity >= x.size()) + { + overwrite_buffer(xbegin, xend); + } + else + { + allocate_and_copy_range(xbegin, xend); + } + } + BOOST_ASSERT(invariants_ok()); + return *this; } @@ -1273,78 +1309,6 @@ class devector return m_.buffer[m_.front_idx + n]; } - //! Requires: size() >= n. - //! - //! Effects: Returns an iterator to the nth element - //! from the beginning of the container. Returns end() - //! if n == size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(n <= size()); - return iterator(m_.buffer + (m_.front_idx + n)); - } - - //! Requires: size() >= n. - //! - //! Effects: Returns a const_iterator to the nth element - //! from the beginning of the container. Returns end() - //! if n == size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(n <= size()); - return const_iterator(m_.buffer + (m_.front_idx + n)); - } - - //! Requires: begin() <= p <= end(). - //! - //! Effects: Returns the index of the element pointed by p - //! and size() if p == end(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(p >= begin()); - BOOST_ASSERT(p <= end()); - return static_cast(p - this->begin()); - } - - //! Requires: begin() <= p <= end(). - //! - //! Effects: Returns the index of the element pointed by p - //! and size() if p == end(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(p >= cbegin()); - BOOST_ASSERT(p <= cend()); - return static_cast(p - this->cbegin()); - } - /** * **Returns**: A reference to the `n`th element in the devector. * @@ -2172,53 +2136,6 @@ class devector private: - void priv_move_assign(BOOST_RV_REF(devector) x, dtl::bool_ /*steal_resources*/) - { - this->clear(); - this->deallocate_buffer(); - - //Move allocator if needed - dtl::bool_ flag; - dtl::move_alloc(this->get_allocator_ref(), x.get_allocator_ref(), flag); - - m_.capacity = x.m_.capacity; - m_.buffer = x.m_.buffer; - m_.front_idx = x.m_.front_idx; - m_.back_idx = x.m_.back_idx; - - // leave x in valid state - x.m_.capacity = 0u; - x.m_.buffer = pointer(); - x.m_.back_idx = x.m_.front_idx = 0; - } - - void priv_move_assign(BOOST_RV_REF(devector) x, dtl::bool_ /*steal_resources*/) - { - //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime - //Resources can be transferred if both allocators are equal - if (get_allocator_ref() == x.get_allocator_ref()) { - this->priv_move_assign(boost::move(x), dtl::true_()); - } - else { - // We can't steal memory. - move_iterator xbegin = boost::make_move_iterator(x.begin()); - move_iterator xend = boost::make_move_iterator(x.end()); - - //Move allocator if needed - dtl::bool_ flag; - dtl::move_alloc(this->get_allocator_ref(), x.get_allocator_ref(), flag); - - if (m_.capacity >= x.size()) { - overwrite_buffer(xbegin, xend); - } - else { - allocate_and_copy_range(xbegin, xend); - } - } - } - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline size_type pos_to_index(const_iterator i) const { diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index 6dbd71b..117e275 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -343,13 +343,26 @@ class list || allocator_traits_type::is_always_equal::value) { if (BOOST_LIKELY(this != &x)) { - //We know resources can be transferred at comiple time if both allocators are - //always equal or the allocator is going to be propagated - const bool can_steal_resources_alloc - = allocator_traits_type::propagate_on_container_move_assignment::value - || allocator_traits_type::is_always_equal::value; - dtl::bool_ flag; - this->priv_move_assign(boost::move(x), flag); + NodeAlloc &this_alloc = this->node_alloc(); + NodeAlloc &x_alloc = x.node_alloc(); + const bool propagate_alloc = allocator_traits_type:: + propagate_on_container_move_assignment::value; + const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; + //Resources can be transferred if both allocators are + //going to be equal after this function (either propagated or already equal) + if(propagate_alloc || allocators_equal){ + //Destroy + this->clear(); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(x); + //Obtain resources + this->icont() = boost::move(x.icont()); + } + //Else do a one by one move + else{ + this->assign( boost::make_move_iterator(x.begin()) + , boost::make_move_iterator(x.end())); + } } return *this; } @@ -1378,28 +1391,6 @@ class list #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: - void priv_move_assign(BOOST_RV_REF(list) x, dtl::bool_ /*steal_resources*/) - { - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - this->AllocHolder::move_assign_alloc(x); - //Obtain resources - this->icont() = boost::move(x.icont()); - } - - void priv_move_assign(BOOST_RV_REF(list) x, dtl::bool_ /*steal_resources*/) - { - //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime - //Resources can be transferred if both allocators are equal - if (this->node_alloc() == x.node_alloc()) { - this->priv_move_assign(boost::move(x), dtl::true_()); - } - else { - this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); - } - } - static bool priv_is_linked(const_iterator const position) { const_iterator cur(position); diff --git a/include/boost/container/node_allocator.hpp b/include/boost/container/node_allocator.hpp index a38e96e..d6076f4 100644 --- a/include/boost/container/node_allocator.hpp +++ b/include/boost/container/node_allocator.hpp @@ -8,8 +8,8 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_CONTAINER_NODE_ALLOCATOR_HPP -#define BOOST_CONTAINER_NODE_ALLOCATOR_HPP +#ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP +#define BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP #ifndef BOOST_CONFIG_HPP # include @@ -337,4 +337,4 @@ class node_allocator #include -#endif //#ifndef BOOST_CONTAINER_NODE_ALLOCATOR_HPP +#endif //#ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP diff --git a/include/boost/container/node_handle.hpp b/include/boost/container/node_handle.hpp index 5179022..4b6e021 100644 --- a/include/boost/container/node_handle.hpp +++ b/include/boost/container/node_handle.hpp @@ -232,7 +232,7 @@ class node_handle if(was_nh_non_null){ if(was_this_non_null){ this->destroy_deallocate_node(); - BOOST_IF_CONSTEXPR(nator_traits::propagate_on_container_move_assignment::value){ + if(nator_traits::propagate_on_container_move_assignment::value){ this->node_alloc() = ::boost::move(nh.node_alloc()); } } @@ -336,7 +336,7 @@ class node_handle if(was_nh_non_null){ if(was_this_non_null){ - BOOST_IF_CONSTEXPR(nator_traits::propagate_on_container_swap::value){ + if(nator_traits::propagate_on_container_swap::value){ ::boost::adl_move_swap(this->node_alloc(), nh.node_alloc()); } } diff --git a/include/boost/container/options.hpp b/include/boost/container/options.hpp index ce00b48..48edd38 100644 --- a/include/boost/container/options.hpp +++ b/include/boost/container/options.hpp @@ -617,7 +617,7 @@ typedef deque_opt<0u, 0u> deque_null_opt; //! Helper metafunction to combine options into a single type to be used //! by \c boost::container::deque. -//! Supported options are: \c boost::container::block_bytes and \c boost::container::block_size +//! Supported options are: \c boost::container::block_bytes #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) template #else diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index 0d96927..a863d1a 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -368,14 +368,28 @@ class slist BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) { - if (BOOST_LIKELY(this != &x)) { - //We know resources can be transferred at comiple time if both allocators are - //always equal or the allocator is going to be propagated - const bool can_steal_resources_alloc - = allocator_traits_type::propagate_on_container_move_assignment::value - || allocator_traits_type::is_always_equal::value; - dtl::bool_ flag; - this->priv_move_assign(boost::move(x), flag); + slist & sr = x; + if (BOOST_LIKELY(this != &sr)) { + NodeAlloc &this_alloc = this->node_alloc(); + NodeAlloc &x_alloc = sr.node_alloc(); + const bool propagate_alloc = allocator_traits_type:: + propagate_on_container_move_assignment::value; + const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; + //Resources can be transferred if both allocators are + //going to be equal after this function (either propagated or already equal) + if(propagate_alloc || allocators_equal){ + //Destroy + this->clear(); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(sr); + //Obtain resources + this->icont() = boost::move(sr.icont()); + } + //Else do a one by one move + else{ + this->assign( boost::make_move_iterator(sr.begin()) + , boost::make_move_iterator(sr.end())); + } } return *this; } @@ -1565,27 +1579,6 @@ class slist #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: - void priv_move_assign(BOOST_RV_REF(slist) x, dtl::bool_ /*steal_resources*/) - { - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - this->AllocHolder::move_assign_alloc(x); - //Obtain resources - this->icont() = boost::move(x.icont()); - } - - void priv_move_assign(BOOST_RV_REF(slist) x, dtl::bool_ /*steal_resources*/) - { - //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime - //Resources can be transferred if both allocators are equal - if (this->node_alloc() == x.node_alloc()) { - this->priv_move_assign(boost::move(x), dtl::true_()); - } - else { - this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); - } - } template void priv_push_front(BOOST_FWD_REF(U) x) diff --git a/include/boost/container/small_vector.hpp b/include/boost/container/small_vector.hpp index 860840e..086b30a 100644 --- a/include/boost/container/small_vector.hpp +++ b/include/boost/container/small_vector.hpp @@ -346,10 +346,9 @@ class small_vector_base public: //Make it public as it will be inherited by small_vector and container //must have this public member - typedef typename real_allocator::type underlying_allocator_t; - typedef typename allocator_traits:: - template portable_rebind_alloc::type void_underlying_allocator_t; - typedef small_vector_allocatorallocator_type; + typedef typename real_allocator::type allocator_type; + typedef typename allocator_traits:: + template portable_rebind_alloc::type void_allocator_t; typedef typename dtl::get_small_vector_opt::type options_t; typedef typename dtl::vector_for_small_vector ::type base_type; @@ -357,12 +356,12 @@ class small_vector_base typedef typename allocator_traits::const_pointer const_pointer; typedef typename allocator_traits::void_pointer void_pointer; typedef typename allocator_traits::const_void_pointer const_void_pointer; - + typedef small_vector_allocator small_allocator_type; private: BOOST_COPYABLE_AND_MOVABLE(small_vector_base) - friend class small_vector_allocator; + friend class small_vector_allocator; inline const_pointer internal_storage() const BOOST_NOEXCEPT_OR_NOTHROW diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index b4fbae9..6718122 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -872,14 +872,31 @@ class stable_vector BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) { + //for move constructor, no aliasing (&x != this) is assumed. if (BOOST_LIKELY(this != &x)) { - //We know resources can be transferred at comiple time if both allocators are - //always equal or the allocator is going to be propagated - const bool can_steal_resources_alloc - = allocator_traits_type::propagate_on_container_move_assignment::value - || allocator_traits_type::is_always_equal::value; - dtl::bool_ flag; - this->priv_move_assign(boost::move(x), flag); + node_allocator_type &this_alloc = this->priv_node_alloc(); + node_allocator_type &x_alloc = x.priv_node_alloc(); + const bool propagate_alloc = allocator_traits_type:: + propagate_on_container_move_assignment::value; + dtl::bool_ flag; + const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; + //Resources can be transferred if both allocators are + //going to be equal after this function (either propagated or already equal) + if(propagate_alloc || allocators_equal){ + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + dtl::move_alloc(this_alloc, x_alloc, flag); + //Take resources + this->index.swap(x.index); + this->priv_swap_members(x); + } + //Else do a one by one move + else{ + this->assign( boost::make_move_iterator(x.begin()) + , boost::make_move_iterator(x.end())); + } } return *this; } @@ -1835,35 +1852,6 @@ class stable_vector #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: - void priv_move_assign(BOOST_RV_REF(stable_vector) x, dtl::bool_ /*steal_resources*/) - { - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - dtl::bool_ flag; - dtl::move_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); - - //Take resources - this->index = boost::move(x.index); //this also moves the vector's allocator if needed - this->priv_swap_members(x); - } - - void priv_move_assign(BOOST_RV_REF(stable_vector) x, dtl::bool_ /*steal_resources*/) - { - //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime - //Resources can be transferred if both allocators are equal - if (this->priv_node_alloc() == x.priv_node_alloc()) { - this->priv_move_assign(boost::move(x), dtl::true_()); - } - else { - this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); - } - } - bool priv_in_range(const_iterator pos) const { return (this->begin() <= pos) && (pos < this->end()); diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index c78da98..e7cfc23 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -913,13 +913,26 @@ class basic_string || allocator_traits_type::is_always_equal::value) { if (BOOST_LIKELY(this != &x)) { - //We know resources can be transferred at comiple time if both allocators are - //always equal or the allocator is going to be propagated - const bool can_steal_resources_alloc - = allocator_traits_type::propagate_on_container_move_assignment::value - || allocator_traits_type::is_always_equal::value; - dtl::bool_ flag; - this->priv_move_assign(boost::move(x), flag); + allocator_type &this_alloc = this->alloc(); + allocator_type &x_alloc = x.alloc(); + const bool propagate_alloc = allocator_traits_type:: + propagate_on_container_move_assignment::value; + dtl::bool_ flag; + const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; + //Resources can be transferred if both allocators are + //going to be equal after this function (either propagated or already equal) + if(propagate_alloc || allocators_equal){ + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + dtl::move_alloc(this_alloc, x_alloc, flag); + //Nothrow swap + this->swap_data(x); + } + //Else do a one by one move + else{ + this->assign( x.begin(), x.end()); + } } return *this; } @@ -2895,30 +2908,6 @@ class basic_string #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: - void priv_move_assign(BOOST_RV_REF(basic_string) x, dtl::bool_ /*steal_resources*/) - { - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - dtl::bool_ flag; - dtl::move_alloc(this->alloc(), x.alloc(), flag); - //Nothrow swap - this->swap_data(x); - } - - void priv_move_assign(BOOST_RV_REF(basic_string) x, dtl::bool_ /*steal_resources*/) - { - //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime - //Resources can be transferred if both allocators are equal - if (this->alloc() == x.alloc()) { - this->priv_move_assign(boost::move(x), dtl::true_()); - } - else { - this->assign(x.begin(), x.end()); - } - } - bool priv_reserve_no_null_end(size_type res_arg) { if (res_arg > this->max_size()){ diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 5046be9..038b8b4 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -2531,38 +2531,6 @@ private: x.clear(); } - template - void priv_move_assign_steal_or_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x, dtl::true_type /*data_can_be_always_stolen*/) - { - this->clear(); - if (BOOST_LIKELY(!!this->m_holder.m_start)) - this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity); - this->m_holder.steal_resources(x.m_holder); - } - - template - void priv_move_assign_steal_or_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x, dtl::false_type /*data_can_be_always_stolen*/) - { - const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; - allocator_type& this_alloc = this->m_holder.alloc(); - allocator_type& x_alloc = x.m_holder.alloc(); - - //In this allocator move constructor the allocator might will be propagated, but to support small_vector-like - //types, we need to check the currently owned buffers to know if they are propagable. - const bool is_buffer_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc); - - if (is_buffer_propagable_from_x) { - this->priv_move_assign_steal_or_assign(boost::move(x), dtl::true_type()); - } - //Else do a one by one move. Also, clear the source as users find confusing - //elements are still alive in the source container. - else { - this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin())) - , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end())) ); - x.clear(); - } - } - template void priv_move_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x , typename dtl::disable_if_or @@ -2574,16 +2542,30 @@ private: //for move assignment, no aliasing (&x != this) is assumed. //x.size() == 0 is allowed for buggy std libraries. BOOST_ASSERT(this != &x || x.size() == 0); - const bool alloc_is_always_equal = allocator_traits_type::is_always_equal::value; + allocator_type &this_alloc = this->m_holder.alloc(); + allocator_type &x_alloc = x.m_holder.alloc(); const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; - const bool partially_propagable_alloc = allocator_traits_type::is_partially_propagable::value; - const bool data_can_be_always_be_stolen = alloc_is_always_equal || (propagate_alloc && !partially_propagable_alloc); - this->priv_move_assign_steal_or_assign(boost::move(x), dtl::bool_()); + //In this allocator move constructor the allocator maybe will be propagated -----------------------v + const bool is_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc); + //Resources can be transferred if both allocators are + //going to be equal after this function (either propagated or already equal) + if(is_propagable_from_x){ + this->clear(); + if(BOOST_LIKELY(!!this->m_holder.m_start)) + this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity); + this->m_holder.steal_resources(x.m_holder); + } + //Else do a one by one move. Also, clear the source as users find confusing + //elements are still alive in the source container. + else{ + this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin())) + , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end() )) + ); + x.clear(); + } //Move allocator if needed - allocator_type& this_alloc = this->m_holder.alloc(); - allocator_type& x_alloc = x.m_holder.alloc(); dtl::move_alloc(this_alloc, x_alloc, dtl::bool_()); } diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 849699e..f81069c 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -307,17 +307,14 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; - typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) - return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; return 0; } diff --git a/test/devector_test.cpp b/test/devector_test.cpp index 23327d4..b637c85 100644 --- a/test/devector_test.cpp +++ b/test/devector_test.cpp @@ -3903,7 +3903,7 @@ struct GetAllocatorCont template struct apply { - typedef devector< ValueType + typedef vector< ValueType , typename allocator_traits ::template portable_rebind_alloc::type > type; @@ -3962,19 +3962,14 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; - typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) - return 1; - if (test::vector_test()) - return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; return 0; } diff --git a/test/list_test.cpp b/test/list_test.cpp index 3a7f004..c371df8 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -10,7 +10,6 @@ #include #include -#include #include "dummy_test_allocator.hpp" #include @@ -79,9 +78,9 @@ struct GetAllocatorCont struct apply { typedef list< ValueType - , typename allocator_traits + , typename allocator_traits ::template portable_rebind_alloc::type - > type; + > type; }; }; @@ -92,11 +91,9 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; - typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; if(test::list_test()) return 1; - if(test::list_test()) return 1; if(test::list_test()) @@ -105,8 +102,6 @@ int test_cont_variants() return 1; if(test::list_test()) return 1; - if (test::list_test()) - return 1; return 0; } @@ -176,27 +171,20 @@ int main () //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// - if (test_cont_variants< new_allocator >()) { - std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; + // int variants + if (test::list_test >, true>()) return 1; - } - - if (test_cont_variants< std::allocator >()) { - std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; + if (test::list_test, true>()) return 1; - } if (test::list_test >, true>()) return 1; + if (test::list_test, true>()) + return 1; + if (test::list_test, true>()) + return 1; + if (test::list_test, true>()) + return 1; - if (test::list_test >, false>()) - return 1; -/* - // boost::container::allocator - if (test_cont_variants< allocator >()) { - std::cerr << "test_cont_variants< allocator > failed" << std::endl; - return 1; - } -*/ //////////////////////////////////// // Emplace testing //////////////////////////////////// diff --git a/test/list_test.hpp b/test/list_test.hpp index 404c5b1..e07b4cc 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -166,61 +166,6 @@ struct list_pop_back_function } }; -template -int list_move_assignable_only(boost::container::dtl::false_type) -{ - return 0; -} - -//Function to check if both sets are equal -template < class MyBoostList - , bool DoublyLinked > -int list_move_assignable_only(boost::container::dtl::true_type) -{ - typedef std::list MyStdList; - typedef typename MyBoostList::value_type IntType; - const std::size_t max = 100u; - typedef list_push_data_function push_data_t; - - { - ::boost::movelib::unique_ptr const stdlistp = ::boost::movelib::make_unique(100u); - ::boost::movelib::unique_ptr const boostlistp = ::boost::movelib::make_unique(100u); - MyBoostList& boostlist = *boostlistp; - MyStdList& stdlist = *stdlistp; - - if (push_data_t::execute(max, boostlist, stdlist)) { - return 1; - } - - IntType aux_vect[50]; - for (int i = 0; i < 50; ++i) { - aux_vect[i] = -1; - } - int aux_vect2[50]; - for (int i = 0; i < 50; ++i) { - aux_vect2[i] = -1; - } - boostlist.assign(boost::make_move_iterator(&aux_vect[0]) - , boost::make_move_iterator(&aux_vect[50])); - stdlist.assign(&aux_vect2[0], &aux_vect2[50]); - if (!CheckEqualContainers(boostlist, stdlist)) return 1; - - for (int i = 0; i < 50; ++i) { - aux_vect[i] = -1; - } - - for (int i = 0; i < 50; ++i) { - aux_vect2[i] = -1; - } - boostlist.assign(boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) - , boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); - stdlist.assign(&aux_vect2[0], &aux_vect2[50]); - if (!CheckEqualContainers(boostlist, stdlist)) return 1; - } - return 0; -} - template int list_test (bool copied_allocators_equal = true) @@ -258,10 +203,9 @@ int list_test (bool copied_allocators_equal = true) ::boost::movelib::unique_ptr const boostlistp = ::boost::movelib::make_unique(100u); ::boost::movelib::unique_ptr const boostlistp2 = ::boost::movelib::make_unique(); *boostlistp2 = ::boost::move(*boostlistp); - if (!test::CheckEqualContainers(*boostlistp2, *stdlistp)) return 1; + if(!test::CheckEqualContainers(*boostlistp2, *stdlistp)) return 1; } - ::boost::movelib::unique_ptr const pboostlist = ::boost::movelib::make_unique(); ::boost::movelib::unique_ptr const pstdlist = ::boost::movelib::make_unique(); @@ -284,9 +228,35 @@ int list_test (bool copied_allocators_equal = true) stdlist.pop_front(); if(!CheckEqualContainers(boostlist, stdlist)) return 1; - if (0 != list_move_assignable_only(dtl::bool_::value>())) - return 1; - + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + boostlist.assign(boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(&aux_vect[50])); + stdlist.assign(&aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) return 1; + + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + boostlist.assign(boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); + stdlist.assign(&aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) return 1; + } + if(copied_allocators_equal){ boostlist.sort(); stdlist.sort(); @@ -304,7 +274,8 @@ int list_test (bool copied_allocators_equal = true) { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - aux_vect[i] = -1; + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -323,7 +294,8 @@ int list_test (bool copied_allocators_equal = true) return 1; for(int i = 0; i < 50; ++i){ - aux_vect[i] = -1; + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); } for(int i = 0; i < 50; ++i){ diff --git a/test/map_test.cpp b/test/map_test.cpp index a0c1fbe..9d3a145 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -557,15 +557,6 @@ int main () std::cout << "Error in map_test, red_black_tree>" << std::endl; return 1; } - - if (0 != test::map_test - < GetAllocatorMap, red_black_tree>::apply::map_type - , MyStdMap - , GetAllocatorMap, red_black_tree>::apply::multimap_type - , MyStdMultiMap>()) { - std::cout << "Error in map_test, red_black_tree>" << std::endl; - return 1; - } } //////////////////////////////////// diff --git a/test/map_test.hpp b/test/map_test.hpp index 5cbfa6b..1922526 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -54,78 +54,6 @@ void map_test_rebalanceable(C &c, boost::container::dtl::true_type) c.rebalance(); } -template -int map_move_assignable_only(boost::container::dtl::false_type) -{ - return 0; -} - -//Function to check if both sets are equal -template -int map_move_assignable_only(boost::container::dtl::true_type) -{ - typedef typename MyBoostMap::key_type IntType; - typedef dtl::pair IntPairType; - - //This is really nasty, but we have no other simple choice - IntPairType aux_vect[(std::size_t)MaxElem]; - for (int i = 0; i < MaxElem; ++i) { - IntType i1(i / 2); - IntType i2(i / 2); - new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); - } - - typedef typename MyStdMap::value_type StdValueType; - typedef typename MyStdMap::key_type StdKeyType; - typedef typename MyStdMap::mapped_type StdMappedType; - StdValueType aux_vect2[(std::size_t)MaxElem]; - for (int i = 0; i < MaxElem; ++i) { - new(&aux_vect2[i])StdValueType(StdKeyType(i / 2), StdMappedType(i / 2)); - } - - IntPairType aux_vect3[(std::size_t)MaxElem]; - for (int i = 0; i < MaxElem; ++i) { - IntType i1(i / 2); - IntType i2(i / 2); - new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); - } - - ::boost::movelib::unique_ptr const pboostmap2 = ::boost::movelib::make_unique - (boost::make_move_iterator(&aux_vect[0]) - , boost::make_move_iterator(&aux_vect[0] + MaxElem)); - ::boost::movelib::unique_ptr const pstdmap2 = ::boost::movelib::make_unique - (&aux_vect2[0], &aux_vect2[0] + MaxElem); - ::boost::movelib::unique_ptr const pboostmultimap2 = ::boost::movelib::make_unique - (boost::make_move_iterator(&aux_vect3[0]) - , boost::make_move_iterator(&aux_vect3[0] + MaxElem)); - ::boost::movelib::unique_ptr const pstdmultimap2 = ::boost::movelib::make_unique - (&aux_vect2[0], &aux_vect2[0] + MaxElem); - MyBoostMap& boostmap2 = *pboostmap2; - MyStdMap& stdmap2 = *pstdmap2; - - /* fix assignable */ - { - IntType i0(0); - IntType i1(1); - boostmap2[::boost::move(i0)] = ::boost::move(i1); - } - { - IntType i1(1); - boostmap2[IntType(0)] = ::boost::move(i1); - } - stdmap2[0] = 1; - if (!CheckEqualContainers(boostmap2, stdmap2)) return 1; - - - return 0; -} - template int map_test_copyable(boost::container::dtl::true_type) { - typedef typename MyBoostMap::key_type IntType; - typedef dtl::pair IntPairType; + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; typedef typename MyStdMap::value_type StdPairType; ::boost::movelib::unique_ptr const pboostmap = ::boost::movelib::make_unique(); @@ -438,9 +366,6 @@ int map_test_step(MyBoostMap &, MyStdMap &, MyBoostMultiMap &, MyStdMultiMap &) return 1; } - if (0 != map_move_assignable_only(dtl::bool_::value>())) - return 1; - { IntType i0(0); boostmap2.erase(i0); @@ -448,6 +373,17 @@ int map_test_step(MyBoostMap &, MyStdMap &, MyBoostMultiMap &, MyStdMultiMap &) stdmap2.erase(0); stdmultimap2.erase(0); } + { + IntType i0(0); + IntType i1(1); + boostmap2[::boost::move(i0)] = ::boost::move(i1); + } + { + IntType i1(1); + boostmap2[IntType(0)] = ::boost::move(i1); + } + stdmap2[0] = 1; + if(!CheckEqualContainers(boostmap2, stdmap2)) return 1; } return 0; } @@ -883,12 +819,12 @@ int map_test_indexing(MyBoostMap &boostmap, MyStdMap &stdmap, MyBoostMultiMap &b IntType i2(i); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } -/* + for(int i = 0; i < MaxElem; ++i){ boostmap[boost::move(aux_vect[i].first)] = boost::move(aux_vect[i].second); stdmap[i] = i; } -*/ + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; } @@ -998,20 +934,14 @@ int map_test_insert_or_assign_impl() return 0; } -template< class MyBoostMap, class StdMap, class Copyable> -int map_test_insert_or_assign(dtl::bool_, Copyable)//noncopyable -{ - return 0; -} - template< class MyBoostMap, class StdMap> -int map_test_insert_or_assign(dtl::bool_, dtl::bool_ )//noncopyable +int map_test_insert_or_assign(dtl::bool_ )//noncopyable { return map_test_insert_or_assign_impl(); } template< class MyBoostMap, class StdMap> -int map_test_insert_or_assign(dtl::bool_, dtl::bool_ )//copyable +int map_test_insert_or_assign(dtl::bool_ )//copyable { int r = map_test_insert_or_assign_impl(); if (r) @@ -1235,7 +1165,6 @@ int map_test() MyBoostMultiMap &boostmultimap = *pboostmultimap; MyStdMultiMap &stdmultimap = *pstdmultimap; typedef dtl::bool_::value> copyable_t; - typedef dtl::bool_::value> move_assignable_t; if (map_test_step(boostmap, stdmap, boostmultimap, stdmultimap)) return 1; @@ -1261,7 +1190,7 @@ int map_test() if (map_test_merge(boostmap, stdmap, boostmultimap, stdmultimap)) return 1; - if (map_test_insert_or_assign(move_assignable_t(), copyable_t())) + if (map_test_insert_or_assign(copyable_t())) return 1; if(map_test_copyable(copyable_t())) diff --git a/test/movable_int.hpp b/test/movable_int.hpp index 58cdf89..beab5b3 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -37,11 +37,6 @@ struct is_move_assignable static const bool value = true; }; -template -struct is_move_constructible -{ - static const bool value = true; -}; ///////////////////////// @@ -599,13 +594,6 @@ struct life_count< non_copymovable_int > { return c == non_copymovable_int::count; } }; -template<> -struct is_move_constructible -{ - static const bool value = false; -}; - - } //namespace test { } //namespace container { } //namespace boost { diff --git a/test/set_test.cpp b/test/set_test.cpp index 756138a..3999ace 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -544,15 +544,6 @@ int main () std::cout << "Error in set_test, red_black_tree>" << std::endl; return 1; } - - if (0 != test::set_test - < GetAllocatorSet, red_black_tree>::apply::set_type - , MyStdSet - , GetAllocatorSet, red_black_tree>::apply::multiset_type - , MyStdMultiSet>()) { - std::cout << "Error in set_test, red_black_tree>" << std::endl; - return 1; - } } //////////////////////////////////// diff --git a/test/set_test.hpp b/test/set_test.hpp index 5846748..9395640 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -161,7 +161,8 @@ int set_test () { //Set(beg, end, compare) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - aux_vect[i] = i/2; + IntType move_me(i/2); + aux_vect[i] = boost::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -169,7 +170,8 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - aux_vect3[i] = i/2; + IntType move_me(i/2); + aux_vect3[i] = boost::move(move_me); } ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique (boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0]+50), typename MyBoostSet::key_compare()); @@ -183,7 +185,8 @@ int set_test () { //Set(beg, end, alloc) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - aux_vect[i] = i/2; + IntType move_me(i/2); + aux_vect[i] = boost::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -191,7 +194,8 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - aux_vect3[i] = i/2; + IntType move_me(i/2); + aux_vect3[i] = boost::move(move_me); } ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique (boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0]+50), typename MyBoostSet::allocator_type()); @@ -205,7 +209,8 @@ int set_test () { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - aux_vect[i] = i/2; + IntType move_me(i/2); + aux_vect[i] = boost::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -213,7 +218,8 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - aux_vect3[i] = i/2; + IntType move_me(i/2); + aux_vect3[i] = boost::move(move_me); } ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique @@ -243,7 +249,8 @@ int set_test () //ordered range insertion for(int i = 0; i < 50; ++i){ - aux_vect[i] = i; + IntType move_me(i); + aux_vect[i] = boost::move(move_me); } for(int i = 0; i < 50; ++i){ @@ -251,7 +258,8 @@ int set_test () } for(int i = 0; i < 50; ++i){ - aux_vect3[i] = i; + IntType move_me(i); + aux_vect3[i] = boost::move(move_me); } //some comparison operators @@ -402,7 +410,8 @@ int set_test () { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - aux_vect[i] = -1; + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -410,7 +419,8 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - aux_vect3[i] = -1; + IntType move_me(-1); + aux_vect3[i] = boost::move(move_me); } boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50)); @@ -445,7 +455,8 @@ int set_test () { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - aux_vect[i] = -1; + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -453,17 +464,20 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - aux_vect3[i] = -1; + IntType move_me(-1); + aux_vect3[i] = boost::move(move_me); } IntType aux_vect4[50]; for(int i = 0; i < 50; ++i){ - aux_vect4[i] = -1; + IntType move_me(-1); + aux_vect4[i] = boost::move(move_me); } IntType aux_vect5[50]; for(int i = 0; i < 50; ++i){ - aux_vect5[i] = -1; + IntType move_me(-1); + aux_vect5[i] = boost::move(move_me); } boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50)); diff --git a/test/slist_test.cpp b/test/slist_test.cpp index ab648a2..932c65c 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -9,7 +9,6 @@ ////////////////////////////////////////////////////////////////////////////// #include #include -#include #include #include "dummy_test_allocator.hpp" @@ -55,32 +54,6 @@ struct GetAllocatorCont }; }; -template -int test_cont_variants() -{ - typedef typename GetAllocatorCont::template apply::type MyCont; - typedef typename GetAllocatorCont::template apply::type MyMoveCont; - typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; - typedef typename GetAllocatorCont::template apply::type MyCopyCont; - typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - - if(test::list_test()) - return 1; - - if(test::list_test()) - return 1; - if(test::list_test()) - return 1; - if(test::list_test()) - return 1; - if(test::list_test()) - return 1; - if (test::list_test()) - return 1; - - return 0; -} - bool test_support_for_initializer_list() { #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -195,18 +168,18 @@ int main () //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// - if (test_cont_variants< new_allocator >()) { - std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; + if (test::list_test >, false>()) return 1; - } - if (test_cont_variants< std::allocator >()) { - std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; - return 1; - } - if (test::list_test >, false>()) + if (test::list_test, false>()) return 1; if (test::list_test >, false>()) return 1; + if (test::list_test, false>()) + return 1; + if (test::list_test, false>()) + return 1; + if (test::list_test, false>()) + return 1; //////////////////////////////////// // Emplace testing diff --git a/test/small_vector_test.cpp b/test/small_vector_test.cpp index 2b32e5a..8d1aaf5 100644 --- a/test/small_vector_test.cpp +++ b/test/small_vector_test.cpp @@ -193,10 +193,10 @@ int main() if(!test_swap()) return 1; - if (test::vector_test< small_vector >()) + if(test::vector_test< small_vector >()) return 1; - if (test::vector_test< small_vector >()) + if(test::vector_test< small_vector >()) return 1; if (test_cont_variants< new_allocator >()) diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp index bdbe4cb..0d64628 100644 --- a/test/stable_vector_test.cpp +++ b/test/stable_vector_test.cpp @@ -72,17 +72,14 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; - typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) - return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; return 0; diff --git a/test/vector_test.cpp b/test/vector_test.cpp index ed367af..d896bdf 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -19,8 +19,6 @@ #include #include -#include -#include #include #include "check_equal_containers.hpp" @@ -131,13 +129,13 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyCopyCont; typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; - if (test::vector_test()) + if(test::vector_test()) return 1; if (test::vector_test()) return 1; diff --git a/test/vector_test.hpp b/test/vector_test.hpp index 8b54380..9ebe4a0 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -269,8 +269,6 @@ bool vector_copyable_only(MyBoostVector &boostvector, MyStdVector &stdvector, bo return true; } - - template int vector_move_assignable_only(boost::container::dtl::false_type) { @@ -347,7 +345,9 @@ int vector_move_assignable_only(boost::container::dtl::true_type) //Initialize values IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - aux_vect[i] = -1; + IntType new_int(-1); + BOOST_CONTAINER_STATIC_ASSERT((boost::container::test::is_copyable::value == false)); + aux_vect[i] = boost::move(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -374,7 +374,8 @@ int vector_move_assignable_only(boost::container::dtl::true_type) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - aux_vect[i] = -i; + IntType new_int(-i); + aux_vect[i] = boost::move(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -390,7 +391,8 @@ int vector_move_assignable_only(boost::container::dtl::true_type) if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; for(int i = 0; i < 50; ++i){ - aux_vect[i] = -i; + IntType new_int(-i); + aux_vect[i] = boost::move(new_int); } for(int i = 0; i < 50; ++i){ @@ -509,30 +511,6 @@ int vector_move_assignable_only(boost::container::dtl::true_type) return 0; } -template -int vector_test_fully_propagable(dtl::true_ /* fully_propagable */) -{ - typedef std::vector MyStdVector; - { - //operator=(Vector &&) - ::boost::movelib::unique_ptr const stdvectorp = - ::boost::movelib::make_unique(100u); - ::boost::movelib::unique_ptr const boostvectorp = - ::boost::movelib::make_unique(100u); - ::boost::movelib::unique_ptr const boostvectorp2 = - ::boost::movelib::make_unique(); - *boostvectorp2 = ::boost::move(*boostvectorp); - if (!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; - } - return 0; -} - -template -int vector_test_fully_propagable(dtl::false_ /* fully_propagable */) -{ - return 0; -} - template int vector_test() { @@ -573,10 +551,7 @@ int vector_test() if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; } - if (0 != vector_test_fully_propagable - ( dtl::bool_< !allocator_traits::is_partially_propagable::value >() )) return 1; - - if (0 != vector_move_assignable_only< MyBoostVector>(dtl::bool_::value>())) + if (0 != vector_move_assignable_only< MyBoostVector>(dtl::bool_::value>())) return 1; std::cout << std::endl << "Test OK!" << std::endl; From 8d179787482f389d9dc564273e81b651b4a4f088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 21 May 2024 14:16:18 +0200 Subject: [PATCH 4/9] Document block_size option in deque_options --- include/boost/container/options.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/container/options.hpp b/include/boost/container/options.hpp index 48edd38..ce00b48 100644 --- a/include/boost/container/options.hpp +++ b/include/boost/container/options.hpp @@ -617,7 +617,7 @@ typedef deque_opt<0u, 0u> deque_null_opt; //! Helper metafunction to combine options into a single type to be used //! by \c boost::container::deque. -//! Supported options are: \c boost::container::block_bytes +//! Supported options are: \c boost::container::block_bytes and \c boost::container::block_size #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) template #else From c09c9b5804c656f56754eb7be4fb4ff285f58c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 23 May 2024 22:53:14 +0200 Subject: [PATCH 5/9] Avoid using transform iterator as null pointer dereferences might happen --- .../detail/multiallocation_chain.hpp | 106 ++++++++++++++++-- 1 file changed, 96 insertions(+), 10 deletions(-) diff --git a/include/boost/container/detail/multiallocation_chain.hpp b/include/boost/container/detail/multiallocation_chain.hpp index 749ef5a..fa58a00 100644 --- a/include/boost/container/detail/multiallocation_chain.hpp +++ b/include/boost/container/detail/multiallocation_chain.hpp @@ -25,15 +25,17 @@ #include // container/detail #include -#include #include #include +#include // intrusive #include #include #include // move #include +#include + namespace boost { namespace container { @@ -187,15 +189,100 @@ class basic_multiallocation_chain } }; -template -struct cast_functor +template +class multialloc_iterator + : public boost::container::iterator + < typename Iterator::iterator_category + , T + , typename Iterator::difference_type + , T* + , T& + > { - typedef typename dtl::add_reference::type result_type; - template - result_type operator()(U &ptr) const - { return *static_cast(static_cast(&ptr)); } + public: + inline explicit multialloc_iterator(const Iterator &it) + : m_it(it) + {} + + inline explicit multialloc_iterator() + : m_it() + {} + + //Constructors + inline multialloc_iterator& operator++() + { increment(); return *this; } + + inline multialloc_iterator operator++(int) + { + multialloc_iterator result (*this); + increment(); + return result; + } + + inline friend bool operator== (const multialloc_iterator& i, const multialloc_iterator& i2) + { return i.equal(i2); } + + inline friend bool operator!= (const multialloc_iterator& i, const multialloc_iterator& i2) + { return !(i == i2); } + + inline friend typename Iterator::difference_type operator- (const multialloc_iterator& i, const multialloc_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + inline multialloc_iterator& operator+=(typename Iterator::difference_type off) + { this->advance(off); return *this; } + + inline multialloc_iterator operator+(typename Iterator::difference_type off) const + { + multialloc_iterator other(*this); + other.advance(off); + return other; + } + + inline friend multialloc_iterator operator+(typename Iterator::difference_type off, const multialloc_iterator& right) + { return right + off; } + + inline multialloc_iterator& operator-=(typename Iterator::difference_type off) + { this->advance(-off); return *this; } + + inline multialloc_iterator operator-(typename Iterator::difference_type off) const + { return *this + (-off); } + + inline T& operator*() const + { return *this->operator->(); } + + inline T* operator->() const + { return static_cast(static_cast(boost::movelib::iterator_to_raw_pointer(m_it))); } + + inline Iterator & base() + { return m_it; } + + inline const Iterator & base() const + { return m_it; } + + private: + Iterator m_it; + + inline void increment() + { ++m_it; } + + inline void decrement() + { --m_it; } + + inline bool equal(const multialloc_iterator &other) const + { return m_it == other.m_it; } + + inline bool less(const multialloc_iterator &other) const + { return other.m_it < m_it; } + + inline void advance(typename Iterator::difference_type n) + { boost::container::iterator_advance(m_it, n); } + + inline typename Iterator::difference_type distance_to(const multialloc_iterator &other)const + { return boost::container::iterator_distance(other.m_it, m_it); } }; + template class transform_multiallocation_chain : public MultiallocationChain @@ -217,9 +304,8 @@ class transform_multiallocation_chain { return pointer_traits::static_cast_from(p); } public: - typedef transform_iterator - < typename MultiallocationChain::iterator - , dtl::cast_functor > iterator; + typedef multialloc_iterator + iterator; typedef typename MultiallocationChain::size_type size_type; typedef boost::intrusive::twin pointer_pair; From c38fe90e9aaca25e05be941c12edf26eab3e6e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 23 May 2024 22:53:35 +0200 Subject: [PATCH 6/9] Reduce iterations for resgresion tests --- bench/bench_vectors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/bench_vectors.cpp b/bench/bench_vectors.cpp index 4304ced..8c8a65a 100644 --- a/bench/bench_vectors.cpp +++ b/bench/bench_vectors.cpp @@ -293,7 +293,7 @@ void test_vectors() #endif std::size_t numele [] = { 100000 }; #elif defined SIMPLE_IT - std::size_t numit [] = { 100 }; + std::size_t numit [] = { 10 }; std::size_t numele [] = { 100000 }; #else #ifdef NDEBUG From 397fbda8be9cd6f74a8cb337dfde5397ee720d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 23 May 2024 23:28:54 +0200 Subject: [PATCH 7/9] Fixes #280 ("Several containers don't support non-movable types when move assigning") --- doc/container.qbk | 7 + include/boost/container/deque.hpp | 59 +++--- include/boost/container/detail/tree.hpp | 77 ++++---- include/boost/container/devector.hpp | 199 +++++++++++++++------ include/boost/container/list.hpp | 49 ++--- include/boost/container/node_allocator.hpp | 21 ++- include/boost/container/node_handle.hpp | 4 +- include/boost/container/slist.hpp | 51 +++--- include/boost/container/small_vector.hpp | 11 +- include/boost/container/stable_vector.hpp | 60 ++++--- include/boost/container/string.hpp | 51 +++--- include/boost/container/vector.hpp | 58 +++--- test/deque_test.cpp | 11 +- test/devector_test.cpp | 15 +- test/list_test.cpp | 34 ++-- test/list_test.hpp | 96 ++++++---- test/map_test.cpp | 9 + test/map_test.hpp | 107 +++++++++-- test/movable_int.hpp | 12 ++ test/set_test.cpp | 9 + test/set_test.hpp | 42 ++--- test/slist_test.cpp | 43 ++++- test/small_vector_test.cpp | 4 +- test/stable_vector_test.cpp | 11 +- test/vector_test.cpp | 10 +- test/vector_test.hpp | 41 ++++- 26 files changed, 729 insertions(+), 362 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index d76b629..2efe886 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1409,6 +1409,13 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] +[section:release_notes_boost_1_86_00 Boost 1.86 Release] + +* Fixed bugs/issues: + * [@https://github.com/boostorg/container/issues/280 GitHub #280: ['"Several containers don't support non-movable types when move assigning"]]. + +[endsect] + [section:release_notes_boost_1_85_00 Boost 1.85 Release] * Removed Boost.StaticAssert dependency. diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index e599581..188f65a 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -1318,28 +1318,13 @@ class deque : protected deque_base::type, || allocator_traits_type::is_always_equal::value) { if (BOOST_LIKELY(this != &x)) { - allocator_type &this_alloc = this->alloc(); - allocator_type &x_alloc = x.alloc(); - const bool propagate_alloc = allocator_traits_type:: - propagate_on_container_move_assignment::value; - dtl::bool_ flag; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - dtl::move_alloc(this_alloc, x_alloc, flag); - dtl::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); - //Nothrow swap - this->swap_members(x); - } - //Else do a one by one move - else{ - this->assign( boost::make_move_iterator(x.begin()) - , boost::make_move_iterator(x.end())); - } + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -2378,6 +2363,30 @@ class deque : protected deque_base::type, #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + void priv_move_assign(BOOST_RV_REF(deque) x, dtl::bool_ /*steal_resources*/) + { + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + dtl::bool_ flag; + dtl::move_alloc(this->alloc(), x.alloc(), flag); + dtl::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); + //Nothrow swap + this->swap_members(x); + } + + void priv_move_assign(BOOST_RV_REF(deque) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->alloc() == x.alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); + } + } + inline size_type priv_index_of(const_iterator p) const { BOOST_ASSERT(this->cbegin() <= p); @@ -2493,7 +2502,8 @@ class deque : protected deque_base::type, void priv_destroy_range(iterator p, iterator p2) { - if(!Base::traits_t::trivial_dctr){ + (void)p; (void)p2; + BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){ for(;p != p2; ++p){ allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); } @@ -2502,7 +2512,8 @@ class deque : protected deque_base::type, void priv_destroy_range(pointer p, pointer p2) { - if(!Base::traits_t::trivial_dctr){ + (void)p; (void)p2; + BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){ for(;p != p2; ++p){ allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); } diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index b5430fe..7add430 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -688,40 +688,13 @@ class tree boost::container::dtl::is_nothrow_move_assignable::value) { if (BOOST_LIKELY(this != &x)) { - NodeAlloc &this_alloc = this->node_alloc(); - NodeAlloc &x_alloc = x.node_alloc(); - const bool propagate_alloc = allocator_traits:: - propagate_on_container_move_assignment::value; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - //Destroy - this->clear(); - //Move allocator if needed - this->AllocHolder::move_assign_alloc(x); - //Obtain resources - this->icont() = boost::move(x.icont()); - } - //Else do a one by one move - else{ - //Transfer all the nodes to a temporary tree - //If anything goes wrong, all the nodes will be destroyed - //automatically - Icont other_tree(::boost::move(this->icont())); - - //Now recreate the source tree reusing nodes stored by other_tree - this->icont().clone_from - (::boost::move(x.icont()) - , RecyclingCloner(*this, other_tree) - , Destroyer(this->node_alloc())); - - //If there are remaining nodes, destroy them - NodePtr p; - while((p = other_tree.unlink_leftmost_without_rebalance())){ - AllocHolder::destroy_node(p); - } - } + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -895,6 +868,42 @@ class tree private: + void priv_move_assign(BOOST_RV_REF(tree) x, dtl::bool_ /*steal_resources*/) + { + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(x); + //Obtain resources + this->icont() = boost::move(x.icont()); + } + + void priv_move_assign(BOOST_RV_REF(tree) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->node_alloc() == x.node_alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + //Transfer all the nodes to a temporary tree + //If anything goes wrong, all the nodes will be destroyed + //automatically + Icont other_tree(::boost::move(this->icont())); + + //Now recreate the source tree reusing nodes stored by other_tree + this->icont().clone_from + (::boost::move(x.icont()) + , RecyclingCloner(*this, other_tree) + , Destroyer(this->node_alloc())); + + //If there are remaining nodes, destroy them + NodePtr p; + while ((p = other_tree.unlink_leftmost_without_rebalance())) { + AllocHolder::destroy_node(p); + } + } + } template iiterator priv_insert_or_assign_commit diff --git a/include/boost/container/devector.hpp b/include/boost/container/devector.hpp index 27e11f0..1020c5d 100644 --- a/include/boost/container/devector.hpp +++ b/include/boost/container/devector.hpp @@ -512,20 +512,21 @@ class devector const devector &x = rhs; if (this == &x) { return *this; } // skip self - BOOST_IF_CONSTEXPR(allocator_traits_type::propagate_on_container_copy_assignment::value) + const bool do_propagate = allocator_traits_type::propagate_on_container_copy_assignment::value; + BOOST_IF_CONSTEXPR(do_propagate) { - allocator_type &this_alloc = this->get_allocator_ref(); - const allocator_type &other_alloc = x.get_allocator_ref(); - if (this_alloc != other_alloc) - { - // new allocator cannot free existing storage - this->clear(); - this->deallocate_buffer(); - m_.capacity = 0u; - m_.buffer = pointer(); - } - - this_alloc = other_alloc; + allocator_type &this_alloc = this->get_allocator_ref(); + const allocator_type &other_alloc = x.get_allocator_ref(); + if (this_alloc != other_alloc) + { + // new allocator cannot free existing storage + this->clear(); + this->deallocate_buffer(); + m_.capacity = 0u; + m_.buffer = pointer(); + } + dtl::bool_ flag; + dtl::assign_alloc(this_alloc, other_alloc, flag); } size_type n = x.size(); @@ -565,53 +566,16 @@ class devector BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) { - BOOST_CONSTEXPR_OR_CONST bool copy_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; - - BOOST_IF_CONSTEXPR (copy_alloc || get_allocator_ref() == x.get_allocator_ref()) - { - this->clear(); - this->deallocate_buffer(); - - if (copy_alloc) - { - this->get_allocator_ref() = boost::move(x.get_allocator_ref()); - } - - m_.capacity = x.m_.capacity; - m_.buffer = x.m_.buffer; - m_.front_idx = x.m_.front_idx; - m_.back_idx = x.m_.back_idx; - - // leave x in valid state - x.m_.capacity = 0u; - x.m_.buffer = pointer(); - x.m_.back_idx = x.m_.front_idx = 0; + if (BOOST_LIKELY(this != &x)) { + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } - else - { - // if the allocator shouldn't be copied and they do not compare equal - // we can't steal memory. - - move_iterator xbegin = boost::make_move_iterator(x.begin()); - move_iterator xend = boost::make_move_iterator(x.end()); - - if (copy_alloc) - { - get_allocator_ref() = boost::move(x.get_allocator_ref()); - } - - if (m_.capacity >= x.size()) - { - overwrite_buffer(xbegin, xend); - } - else - { - allocate_and_copy_range(xbegin, xend); - } - } - BOOST_ASSERT(invariants_ok()); - return *this; } @@ -1309,6 +1273,78 @@ class devector return m_.buffer[m_.front_idx + n]; } + //! Requires: size() >= n. + //! + //! Effects: Returns an iterator to the nth element + //! from the beginning of the container. Returns end() + //! if n == size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline + iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(n <= size()); + return iterator(m_.buffer + (m_.front_idx + n)); + } + + //! Requires: size() >= n. + //! + //! Effects: Returns a const_iterator to the nth element + //! from the beginning of the container. Returns end() + //! if n == size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline + const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(n <= size()); + return const_iterator(m_.buffer + (m_.front_idx + n)); + } + + //! Requires: begin() <= p <= end(). + //! + //! Effects: Returns the index of the element pointed by p + //! and size() if p == end(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline + size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(p >= begin()); + BOOST_ASSERT(p <= end()); + return static_cast(p - this->begin()); + } + + //! Requires: begin() <= p <= end(). + //! + //! Effects: Returns the index of the element pointed by p + //! and size() if p == end(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline + size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(p >= cbegin()); + BOOST_ASSERT(p <= cend()); + return static_cast(p - this->cbegin()); + } + /** * **Returns**: A reference to the `n`th element in the devector. * @@ -2136,6 +2172,53 @@ class devector private: + void priv_move_assign(BOOST_RV_REF(devector) x, dtl::bool_ /*steal_resources*/) + { + this->clear(); + this->deallocate_buffer(); + + //Move allocator if needed + dtl::bool_ flag; + dtl::move_alloc(this->get_allocator_ref(), x.get_allocator_ref(), flag); + + m_.capacity = x.m_.capacity; + m_.buffer = x.m_.buffer; + m_.front_idx = x.m_.front_idx; + m_.back_idx = x.m_.back_idx; + + // leave x in valid state + x.m_.capacity = 0u; + x.m_.buffer = pointer(); + x.m_.back_idx = x.m_.front_idx = 0; + } + + void priv_move_assign(BOOST_RV_REF(devector) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (get_allocator_ref() == x.get_allocator_ref()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + // We can't steal memory. + move_iterator xbegin = boost::make_move_iterator(x.begin()); + move_iterator xend = boost::make_move_iterator(x.end()); + + //Move allocator if needed + dtl::bool_ flag; + dtl::move_alloc(this->get_allocator_ref(), x.get_allocator_ref(), flag); + + if (m_.capacity >= x.size()) { + overwrite_buffer(xbegin, xend); + } + else { + allocate_and_copy_range(xbegin, xend); + } + } + } + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline size_type pos_to_index(const_iterator i) const { diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index 117e275..6dbd71b 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -343,26 +343,13 @@ class list || allocator_traits_type::is_always_equal::value) { if (BOOST_LIKELY(this != &x)) { - NodeAlloc &this_alloc = this->node_alloc(); - NodeAlloc &x_alloc = x.node_alloc(); - const bool propagate_alloc = allocator_traits_type:: - propagate_on_container_move_assignment::value; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - //Destroy - this->clear(); - //Move allocator if needed - this->AllocHolder::move_assign_alloc(x); - //Obtain resources - this->icont() = boost::move(x.icont()); - } - //Else do a one by one move - else{ - this->assign( boost::make_move_iterator(x.begin()) - , boost::make_move_iterator(x.end())); - } + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -1391,6 +1378,28 @@ class list #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + void priv_move_assign(BOOST_RV_REF(list) x, dtl::bool_ /*steal_resources*/) + { + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(x); + //Obtain resources + this->icont() = boost::move(x.icont()); + } + + void priv_move_assign(BOOST_RV_REF(list) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->node_alloc() == x.node_alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); + } + } + static bool priv_is_linked(const_iterator const position) { const_iterator cur(position); diff --git a/include/boost/container/node_allocator.hpp b/include/boost/container/node_allocator.hpp index d6076f4..ff24959 100644 --- a/include/boost/container/node_allocator.hpp +++ b/include/boost/container/node_allocator.hpp @@ -8,8 +8,8 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP -#define BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP +#ifndef BOOST_CONTAINER_NODE_ALLOCATOR_HPP +#define BOOST_CONTAINER_NODE_ALLOCATOR_HPP #ifndef BOOST_CONFIG_HPP # include @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -225,7 +226,10 @@ class node_allocator typedef dtl::singleton_default singleton_t; typename shared_pool_t::multiallocation_chain ch; singleton_t::instance().allocate_nodes(num_elements, ch); - chain.incorporate_after(chain.before_begin(), (T*)&*ch.begin(), (T*)&*ch.last(), ch.size()); + chain.incorporate_after(chain.before_begin() + , (T*)boost::movelib::iterator_to_raw_pointer(ch.begin()) + , (T*)boost::movelib::iterator_to_raw_pointer(ch.last()) + , ch.size()); } //!Deallocates memory previously allocated with allocate_one(). @@ -246,7 +250,10 @@ class node_allocator typedef dtl::shared_node_pool shared_pool_t; typedef dtl::singleton_default singleton_t; - typename shared_pool_t::multiallocation_chain ch(&*chain.begin(), &*chain.last(), chain.size()); + typename shared_pool_t::multiallocation_chain ch + ( boost::movelib::iterator_to_raw_pointer(chain.begin()) + , boost::movelib::iterator_to_raw_pointer(chain.last()) + , chain.size()); singleton_t::instance().deallocate_nodes(ch); } @@ -285,8 +292,8 @@ class node_allocator void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_CONTAINER_STATIC_ASSERT(( Version > 1 )); - void *first = &*chain.begin(); - void *last = &*chain.last(); + void *first = boost::movelib::iterator_to_raw_pointer(chain.begin()); + void *last = boost::movelib::iterator_to_raw_pointer(chain.last()); size_t num = chain.size(); dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, first, last, num); @@ -337,4 +344,4 @@ class node_allocator #include -#endif //#ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP +#endif //#ifndef BOOST_CONTAINER_NODE_ALLOCATOR_HPP diff --git a/include/boost/container/node_handle.hpp b/include/boost/container/node_handle.hpp index 4b6e021..5179022 100644 --- a/include/boost/container/node_handle.hpp +++ b/include/boost/container/node_handle.hpp @@ -232,7 +232,7 @@ class node_handle if(was_nh_non_null){ if(was_this_non_null){ this->destroy_deallocate_node(); - if(nator_traits::propagate_on_container_move_assignment::value){ + BOOST_IF_CONSTEXPR(nator_traits::propagate_on_container_move_assignment::value){ this->node_alloc() = ::boost::move(nh.node_alloc()); } } @@ -336,7 +336,7 @@ class node_handle if(was_nh_non_null){ if(was_this_non_null){ - if(nator_traits::propagate_on_container_swap::value){ + BOOST_IF_CONSTEXPR(nator_traits::propagate_on_container_swap::value){ ::boost::adl_move_swap(this->node_alloc(), nh.node_alloc()); } } diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index a863d1a..0d96927 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -368,28 +368,14 @@ class slist BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) { - slist & sr = x; - if (BOOST_LIKELY(this != &sr)) { - NodeAlloc &this_alloc = this->node_alloc(); - NodeAlloc &x_alloc = sr.node_alloc(); - const bool propagate_alloc = allocator_traits_type:: - propagate_on_container_move_assignment::value; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - //Destroy - this->clear(); - //Move allocator if needed - this->AllocHolder::move_assign_alloc(sr); - //Obtain resources - this->icont() = boost::move(sr.icont()); - } - //Else do a one by one move - else{ - this->assign( boost::make_move_iterator(sr.begin()) - , boost::make_move_iterator(sr.end())); - } + if (BOOST_LIKELY(this != &x)) { + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -1579,6 +1565,27 @@ class slist #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + void priv_move_assign(BOOST_RV_REF(slist) x, dtl::bool_ /*steal_resources*/) + { + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(x); + //Obtain resources + this->icont() = boost::move(x.icont()); + } + + void priv_move_assign(BOOST_RV_REF(slist) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->node_alloc() == x.node_alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); + } + } template void priv_push_front(BOOST_FWD_REF(U) x) diff --git a/include/boost/container/small_vector.hpp b/include/boost/container/small_vector.hpp index 086b30a..860840e 100644 --- a/include/boost/container/small_vector.hpp +++ b/include/boost/container/small_vector.hpp @@ -346,9 +346,10 @@ class small_vector_base public: //Make it public as it will be inherited by small_vector and container //must have this public member - typedef typename real_allocator::type allocator_type; - typedef typename allocator_traits:: - template portable_rebind_alloc::type void_allocator_t; + typedef typename real_allocator::type underlying_allocator_t; + typedef typename allocator_traits:: + template portable_rebind_alloc::type void_underlying_allocator_t; + typedef small_vector_allocatorallocator_type; typedef typename dtl::get_small_vector_opt::type options_t; typedef typename dtl::vector_for_small_vector ::type base_type; @@ -356,12 +357,12 @@ class small_vector_base typedef typename allocator_traits::const_pointer const_pointer; typedef typename allocator_traits::void_pointer void_pointer; typedef typename allocator_traits::const_void_pointer const_void_pointer; - typedef small_vector_allocator small_allocator_type; + private: BOOST_COPYABLE_AND_MOVABLE(small_vector_base) - friend class small_vector_allocator; + friend class small_vector_allocator; inline const_pointer internal_storage() const BOOST_NOEXCEPT_OR_NOTHROW diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index 6718122..b4fbae9 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -872,31 +872,14 @@ class stable_vector BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) { - //for move constructor, no aliasing (&x != this) is assumed. if (BOOST_LIKELY(this != &x)) { - node_allocator_type &this_alloc = this->priv_node_alloc(); - node_allocator_type &x_alloc = x.priv_node_alloc(); - const bool propagate_alloc = allocator_traits_type:: - propagate_on_container_move_assignment::value; - dtl::bool_ flag; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - dtl::move_alloc(this_alloc, x_alloc, flag); - //Take resources - this->index.swap(x.index); - this->priv_swap_members(x); - } - //Else do a one by one move - else{ - this->assign( boost::make_move_iterator(x.begin()) - , boost::make_move_iterator(x.end())); - } + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -1852,6 +1835,35 @@ class stable_vector #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + void priv_move_assign(BOOST_RV_REF(stable_vector) x, dtl::bool_ /*steal_resources*/) + { + //Resources can be transferred if both allocators are + //going to be equal after this function (either propagated or already equal) + BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + dtl::bool_ flag; + dtl::move_alloc(this->priv_node_alloc(), x.priv_node_alloc(), flag); + + //Take resources + this->index = boost::move(x.index); //this also moves the vector's allocator if needed + this->priv_swap_members(x); + } + + void priv_move_assign(BOOST_RV_REF(stable_vector) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->priv_node_alloc() == x.priv_node_alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); + } + } + bool priv_in_range(const_iterator pos) const { return (this->begin() <= pos) && (pos < this->end()); diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index e7cfc23..c78da98 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -913,26 +913,13 @@ class basic_string || allocator_traits_type::is_always_equal::value) { if (BOOST_LIKELY(this != &x)) { - allocator_type &this_alloc = this->alloc(); - allocator_type &x_alloc = x.alloc(); - const bool propagate_alloc = allocator_traits_type:: - propagate_on_container_move_assignment::value; - dtl::bool_ flag; - const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(propagate_alloc || allocators_equal){ - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - dtl::move_alloc(this_alloc, x_alloc, flag); - //Nothrow swap - this->swap_data(x); - } - //Else do a one by one move - else{ - this->assign( x.begin(), x.end()); - } + //We know resources can be transferred at comiple time if both allocators are + //always equal or the allocator is going to be propagated + const bool can_steal_resources_alloc + = allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value; + dtl::bool_ flag; + this->priv_move_assign(boost::move(x), flag); } return *this; } @@ -2908,6 +2895,30 @@ class basic_string #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + void priv_move_assign(BOOST_RV_REF(basic_string) x, dtl::bool_ /*steal_resources*/) + { + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + dtl::bool_ flag; + dtl::move_alloc(this->alloc(), x.alloc(), flag); + //Nothrow swap + this->swap_data(x); + } + + void priv_move_assign(BOOST_RV_REF(basic_string) x, dtl::bool_ /*steal_resources*/) + { + //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime + //Resources can be transferred if both allocators are equal + if (this->alloc() == x.alloc()) { + this->priv_move_assign(boost::move(x), dtl::true_()); + } + else { + this->assign(x.begin(), x.end()); + } + } + bool priv_reserve_no_null_end(size_type res_arg) { if (res_arg > this->max_size()){ diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 038b8b4..5046be9 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -2531,6 +2531,38 @@ private: x.clear(); } + template + void priv_move_assign_steal_or_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x, dtl::true_type /*data_can_be_always_stolen*/) + { + this->clear(); + if (BOOST_LIKELY(!!this->m_holder.m_start)) + this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity); + this->m_holder.steal_resources(x.m_holder); + } + + template + void priv_move_assign_steal_or_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x, dtl::false_type /*data_can_be_always_stolen*/) + { + const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; + allocator_type& this_alloc = this->m_holder.alloc(); + allocator_type& x_alloc = x.m_holder.alloc(); + + //In this allocator move constructor the allocator might will be propagated, but to support small_vector-like + //types, we need to check the currently owned buffers to know if they are propagable. + const bool is_buffer_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc); + + if (is_buffer_propagable_from_x) { + this->priv_move_assign_steal_or_assign(boost::move(x), dtl::true_type()); + } + //Else do a one by one move. Also, clear the source as users find confusing + //elements are still alive in the source container. + else { + this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin())) + , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end())) ); + x.clear(); + } + } + template void priv_move_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x , typename dtl::disable_if_or @@ -2542,30 +2574,16 @@ private: //for move assignment, no aliasing (&x != this) is assumed. //x.size() == 0 is allowed for buggy std libraries. BOOST_ASSERT(this != &x || x.size() == 0); - allocator_type &this_alloc = this->m_holder.alloc(); - allocator_type &x_alloc = x.m_holder.alloc(); + const bool alloc_is_always_equal = allocator_traits_type::is_always_equal::value; const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; + const bool partially_propagable_alloc = allocator_traits_type::is_partially_propagable::value; + const bool data_can_be_always_be_stolen = alloc_is_always_equal || (propagate_alloc && !partially_propagable_alloc); - //In this allocator move constructor the allocator maybe will be propagated -----------------------v - const bool is_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc); + this->priv_move_assign_steal_or_assign(boost::move(x), dtl::bool_()); - //Resources can be transferred if both allocators are - //going to be equal after this function (either propagated or already equal) - if(is_propagable_from_x){ - this->clear(); - if(BOOST_LIKELY(!!this->m_holder.m_start)) - this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity); - this->m_holder.steal_resources(x.m_holder); - } - //Else do a one by one move. Also, clear the source as users find confusing - //elements are still alive in the source container. - else{ - this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin())) - , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end() )) - ); - x.clear(); - } //Move allocator if needed + allocator_type& this_alloc = this->m_holder.alloc(); + allocator_type& x_alloc = x.m_holder.alloc(); dtl::move_alloc(this_alloc, x_alloc, dtl::bool_()); } diff --git a/test/deque_test.cpp b/test/deque_test.cpp index f81069c..849699e 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -307,14 +307,17 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) + return 1; + if (test::vector_test()) return 1; return 0; } diff --git a/test/devector_test.cpp b/test/devector_test.cpp index b637c85..23327d4 100644 --- a/test/devector_test.cpp +++ b/test/devector_test.cpp @@ -3903,7 +3903,7 @@ struct GetAllocatorCont template struct apply { - typedef vector< ValueType + typedef devector< ValueType , typename allocator_traits ::template portable_rebind_alloc::type > type; @@ -3962,14 +3962,19 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) + return 1; + if (test::vector_test()) + return 1; + if (test::vector_test()) return 1; return 0; } diff --git a/test/list_test.cpp b/test/list_test.cpp index c371df8..3a7f004 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "dummy_test_allocator.hpp" #include @@ -78,9 +79,9 @@ struct GetAllocatorCont struct apply { typedef list< ValueType - , typename allocator_traits + , typename allocator_traits ::template portable_rebind_alloc::type - > type; + > type; }; }; @@ -91,9 +92,11 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; if(test::list_test()) return 1; + if(test::list_test()) return 1; if(test::list_test()) @@ -102,6 +105,8 @@ int test_cont_variants() return 1; if(test::list_test()) return 1; + if (test::list_test()) + return 1; return 0; } @@ -171,20 +176,27 @@ int main () //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// - // int variants - if (test::list_test >, true>()) + if (test_cont_variants< new_allocator >()) { + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; return 1; - if (test::list_test, true>()) + } + + if (test_cont_variants< std::allocator >()) { + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; return 1; + } if (test::list_test >, true>()) return 1; - if (test::list_test, true>()) - return 1; - if (test::list_test, true>()) - return 1; - if (test::list_test, true>()) - return 1; + if (test::list_test >, false>()) + return 1; +/* + // boost::container::allocator + if (test_cont_variants< allocator >()) { + std::cerr << "test_cont_variants< allocator > failed" << std::endl; + return 1; + } +*/ //////////////////////////////////// // Emplace testing //////////////////////////////////// diff --git a/test/list_test.hpp b/test/list_test.hpp index e07b4cc..404c5b1 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -166,6 +166,61 @@ struct list_pop_back_function } }; +template +int list_move_assignable_only(boost::container::dtl::false_type) +{ + return 0; +} + +//Function to check if both sets are equal +template < class MyBoostList + , bool DoublyLinked > +int list_move_assignable_only(boost::container::dtl::true_type) +{ + typedef std::list MyStdList; + typedef typename MyBoostList::value_type IntType; + const std::size_t max = 100u; + typedef list_push_data_function push_data_t; + + { + ::boost::movelib::unique_ptr const stdlistp = ::boost::movelib::make_unique(100u); + ::boost::movelib::unique_ptr const boostlistp = ::boost::movelib::make_unique(100u); + MyBoostList& boostlist = *boostlistp; + MyStdList& stdlist = *stdlistp; + + if (push_data_t::execute(max, boostlist, stdlist)) { + return 1; + } + + IntType aux_vect[50]; + for (int i = 0; i < 50; ++i) { + aux_vect[i] = -1; + } + int aux_vect2[50]; + for (int i = 0; i < 50; ++i) { + aux_vect2[i] = -1; + } + boostlist.assign(boost::make_move_iterator(&aux_vect[0]) + , boost::make_move_iterator(&aux_vect[50])); + stdlist.assign(&aux_vect2[0], &aux_vect2[50]); + if (!CheckEqualContainers(boostlist, stdlist)) return 1; + + for (int i = 0; i < 50; ++i) { + aux_vect[i] = -1; + } + + for (int i = 0; i < 50; ++i) { + aux_vect2[i] = -1; + } + boostlist.assign(boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) + , boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); + stdlist.assign(&aux_vect2[0], &aux_vect2[50]); + if (!CheckEqualContainers(boostlist, stdlist)) return 1; + } + return 0; +} + template int list_test (bool copied_allocators_equal = true) @@ -203,9 +258,10 @@ int list_test (bool copied_allocators_equal = true) ::boost::movelib::unique_ptr const boostlistp = ::boost::movelib::make_unique(100u); ::boost::movelib::unique_ptr const boostlistp2 = ::boost::movelib::make_unique(); *boostlistp2 = ::boost::move(*boostlistp); - if(!test::CheckEqualContainers(*boostlistp2, *stdlistp)) return 1; + if (!test::CheckEqualContainers(*boostlistp2, *stdlistp)) return 1; } + ::boost::movelib::unique_ptr const pboostlist = ::boost::movelib::make_unique(); ::boost::movelib::unique_ptr const pstdlist = ::boost::movelib::make_unique(); @@ -228,35 +284,9 @@ int list_test (bool copied_allocators_equal = true) stdlist.pop_front(); if(!CheckEqualContainers(boostlist, stdlist)) return 1; - { - IntType aux_vect[50]; - for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); - } - int aux_vect2[50]; - for(int i = 0; i < 50; ++i){ - aux_vect2[i] = -1; - } - boostlist.assign(boost::make_move_iterator(&aux_vect[0]) - ,boost::make_move_iterator(&aux_vect[50])); - stdlist.assign(&aux_vect2[0], &aux_vect2[50]); - if(!CheckEqualContainers(boostlist, stdlist)) return 1; - - for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); - } - - for(int i = 0; i < 50; ++i){ - aux_vect2[i] = -1; - } - boostlist.assign(boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) - ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); - stdlist.assign(&aux_vect2[0], &aux_vect2[50]); - if(!CheckEqualContainers(boostlist, stdlist)) return 1; - } - + if (0 != list_move_assignable_only(dtl::bool_::value>())) + return 1; + if(copied_allocators_equal){ boostlist.sort(); stdlist.sort(); @@ -274,8 +304,7 @@ int list_test (bool copied_allocators_equal = true) { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = -1; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -294,8 +323,7 @@ int list_test (bool copied_allocators_equal = true) return 1; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = -1; } for(int i = 0; i < 50; ++i){ diff --git a/test/map_test.cpp b/test/map_test.cpp index 9d3a145..a0c1fbe 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -557,6 +557,15 @@ int main () std::cout << "Error in map_test, red_black_tree>" << std::endl; return 1; } + + if (0 != test::map_test + < GetAllocatorMap, red_black_tree>::apply::map_type + , MyStdMap + , GetAllocatorMap, red_black_tree>::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, red_black_tree>" << std::endl; + return 1; + } } //////////////////////////////////// diff --git a/test/map_test.hpp b/test/map_test.hpp index 1922526..5cbfa6b 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -54,6 +54,78 @@ void map_test_rebalanceable(C &c, boost::container::dtl::true_type) c.rebalance(); } +template +int map_move_assignable_only(boost::container::dtl::false_type) +{ + return 0; +} + +//Function to check if both sets are equal +template +int map_move_assignable_only(boost::container::dtl::true_type) +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[(std::size_t)MaxElem]; + for (int i = 0; i < MaxElem; ++i) { + IntType i1(i / 2); + IntType i2(i / 2); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + typedef typename MyStdMap::value_type StdValueType; + typedef typename MyStdMap::key_type StdKeyType; + typedef typename MyStdMap::mapped_type StdMappedType; + StdValueType aux_vect2[(std::size_t)MaxElem]; + for (int i = 0; i < MaxElem; ++i) { + new(&aux_vect2[i])StdValueType(StdKeyType(i / 2), StdMappedType(i / 2)); + } + + IntPairType aux_vect3[(std::size_t)MaxElem]; + for (int i = 0; i < MaxElem; ++i) { + IntType i1(i / 2); + IntType i2(i / 2); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + ::boost::movelib::unique_ptr const pboostmap2 = ::boost::movelib::make_unique + (boost::make_move_iterator(&aux_vect[0]) + , boost::make_move_iterator(&aux_vect[0] + MaxElem)); + ::boost::movelib::unique_ptr const pstdmap2 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem); + ::boost::movelib::unique_ptr const pboostmultimap2 = ::boost::movelib::make_unique + (boost::make_move_iterator(&aux_vect3[0]) + , boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + ::boost::movelib::unique_ptr const pstdmultimap2 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem); + MyBoostMap& boostmap2 = *pboostmap2; + MyStdMap& stdmap2 = *pstdmap2; + + /* fix assignable */ + { + IntType i0(0); + IntType i1(1); + boostmap2[::boost::move(i0)] = ::boost::move(i1); + } + { + IntType i1(1); + boostmap2[IntType(0)] = ::boost::move(i1); + } + stdmap2[0] = 1; + if (!CheckEqualContainers(boostmap2, stdmap2)) return 1; + + + return 0; +} + template int map_test_copyable(boost::container::dtl::true_type) { - typedef typename MyBoostMap::key_type IntType; - typedef dtl::pair IntPairType; + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; typedef typename MyStdMap::value_type StdPairType; ::boost::movelib::unique_ptr const pboostmap = ::boost::movelib::make_unique(); @@ -366,6 +438,9 @@ int map_test_step(MyBoostMap &, MyStdMap &, MyBoostMultiMap &, MyStdMultiMap &) return 1; } + if (0 != map_move_assignable_only(dtl::bool_::value>())) + return 1; + { IntType i0(0); boostmap2.erase(i0); @@ -373,17 +448,6 @@ int map_test_step(MyBoostMap &, MyStdMap &, MyBoostMultiMap &, MyStdMultiMap &) stdmap2.erase(0); stdmultimap2.erase(0); } - { - IntType i0(0); - IntType i1(1); - boostmap2[::boost::move(i0)] = ::boost::move(i1); - } - { - IntType i1(1); - boostmap2[IntType(0)] = ::boost::move(i1); - } - stdmap2[0] = 1; - if(!CheckEqualContainers(boostmap2, stdmap2)) return 1; } return 0; } @@ -819,12 +883,12 @@ int map_test_indexing(MyBoostMap &boostmap, MyStdMap &stdmap, MyBoostMultiMap &b IntType i2(i); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - +/* for(int i = 0; i < MaxElem; ++i){ boostmap[boost::move(aux_vect[i].first)] = boost::move(aux_vect[i].second); stdmap[i] = i; } - +*/ if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; } @@ -934,14 +998,20 @@ int map_test_insert_or_assign_impl() return 0; } +template< class MyBoostMap, class StdMap, class Copyable> +int map_test_insert_or_assign(dtl::bool_, Copyable)//noncopyable +{ + return 0; +} + template< class MyBoostMap, class StdMap> -int map_test_insert_or_assign(dtl::bool_ )//noncopyable +int map_test_insert_or_assign(dtl::bool_, dtl::bool_ )//noncopyable { return map_test_insert_or_assign_impl(); } template< class MyBoostMap, class StdMap> -int map_test_insert_or_assign(dtl::bool_ )//copyable +int map_test_insert_or_assign(dtl::bool_, dtl::bool_ )//copyable { int r = map_test_insert_or_assign_impl(); if (r) @@ -1165,6 +1235,7 @@ int map_test() MyBoostMultiMap &boostmultimap = *pboostmultimap; MyStdMultiMap &stdmultimap = *pstdmultimap; typedef dtl::bool_::value> copyable_t; + typedef dtl::bool_::value> move_assignable_t; if (map_test_step(boostmap, stdmap, boostmultimap, stdmultimap)) return 1; @@ -1190,7 +1261,7 @@ int map_test() if (map_test_merge(boostmap, stdmap, boostmultimap, stdmultimap)) return 1; - if (map_test_insert_or_assign(copyable_t())) + if (map_test_insert_or_assign(move_assignable_t(), copyable_t())) return 1; if(map_test_copyable(copyable_t())) diff --git a/test/movable_int.hpp b/test/movable_int.hpp index beab5b3..58cdf89 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -37,6 +37,11 @@ struct is_move_assignable static const bool value = true; }; +template +struct is_move_constructible +{ + static const bool value = true; +}; ///////////////////////// @@ -594,6 +599,13 @@ struct life_count< non_copymovable_int > { return c == non_copymovable_int::count; } }; +template<> +struct is_move_constructible +{ + static const bool value = false; +}; + + } //namespace test { } //namespace container { } //namespace boost { diff --git a/test/set_test.cpp b/test/set_test.cpp index 3999ace..756138a 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -544,6 +544,15 @@ int main () std::cout << "Error in set_test, red_black_tree>" << std::endl; return 1; } + + if (0 != test::set_test + < GetAllocatorSet, red_black_tree>::apply::set_type + , MyStdSet + , GetAllocatorSet, red_black_tree>::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test, red_black_tree>" << std::endl; + return 1; + } } //////////////////////////////////// diff --git a/test/set_test.hpp b/test/set_test.hpp index 9395640..5846748 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -161,8 +161,7 @@ int set_test () { //Set(beg, end, compare) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = i/2; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -170,8 +169,7 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = i/2; } ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique (boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0]+50), typename MyBoostSet::key_compare()); @@ -185,8 +183,7 @@ int set_test () { //Set(beg, end, alloc) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = i/2; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -194,8 +191,7 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = i/2; } ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique (boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0]+50), typename MyBoostSet::allocator_type()); @@ -209,8 +205,7 @@ int set_test () { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = i/2; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -218,8 +213,7 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(i/2); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = i/2; } ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique @@ -249,8 +243,7 @@ int set_test () //ordered range insertion for(int i = 0; i < 50; ++i){ - IntType move_me(i); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = i; } for(int i = 0; i < 50; ++i){ @@ -258,8 +251,7 @@ int set_test () } for(int i = 0; i < 50; ++i){ - IntType move_me(i); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = i; } //some comparison operators @@ -410,8 +402,7 @@ int set_test () { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = -1; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -419,8 +410,7 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = -1; } boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50)); @@ -455,8 +445,7 @@ int set_test () { IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); + aux_vect[i] = -1; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -464,20 +453,17 @@ int set_test () } IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect3[i] = boost::move(move_me); + aux_vect3[i] = -1; } IntType aux_vect4[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect4[i] = boost::move(move_me); + aux_vect4[i] = -1; } IntType aux_vect5[50]; for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect5[i] = boost::move(move_me); + aux_vect5[i] = -1; } boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50)); diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 932c65c..ab648a2 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -9,6 +9,7 @@ ////////////////////////////////////////////////////////////////////////////// #include #include +#include #include #include "dummy_test_allocator.hpp" @@ -54,6 +55,32 @@ struct GetAllocatorCont }; }; +template +int test_cont_variants() +{ + typedef typename GetAllocatorCont::template apply::type MyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; + + if(test::list_test()) + return 1; + + if(test::list_test()) + return 1; + if(test::list_test()) + return 1; + if(test::list_test()) + return 1; + if(test::list_test()) + return 1; + if (test::list_test()) + return 1; + + return 0; +} + bool test_support_for_initializer_list() { #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -168,18 +195,18 @@ int main () //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// - if (test::list_test >, false>()) + if (test_cont_variants< new_allocator >()) { + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; return 1; - if (test::list_test, false>()) + } + if (test_cont_variants< std::allocator >()) { + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; + return 1; + } + if (test::list_test >, false>()) return 1; if (test::list_test >, false>()) return 1; - if (test::list_test, false>()) - return 1; - if (test::list_test, false>()) - return 1; - if (test::list_test, false>()) - return 1; //////////////////////////////////// // Emplace testing diff --git a/test/small_vector_test.cpp b/test/small_vector_test.cpp index 8d1aaf5..2b32e5a 100644 --- a/test/small_vector_test.cpp +++ b/test/small_vector_test.cpp @@ -193,10 +193,10 @@ int main() if(!test_swap()) return 1; - if(test::vector_test< small_vector >()) + if (test::vector_test< small_vector >()) return 1; - if(test::vector_test< small_vector >()) + if (test::vector_test< small_vector >()) return 1; if (test_cont_variants< new_allocator >()) diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp index 0d64628..bdbe4cb 100644 --- a/test/stable_vector_test.cpp +++ b/test/stable_vector_test.cpp @@ -72,14 +72,17 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) + return 1; + if (test::vector_test()) return 1; return 0; diff --git a/test/vector_test.cpp b/test/vector_test.cpp index d896bdf..ed367af 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include "check_equal_containers.hpp" @@ -129,13 +131,13 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyCopyCont; typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; - if(test::vector_test()) + if (test::vector_test()) return 1; if (test::vector_test()) return 1; diff --git a/test/vector_test.hpp b/test/vector_test.hpp index 9ebe4a0..8b54380 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -269,6 +269,8 @@ bool vector_copyable_only(MyBoostVector &boostvector, MyStdVector &stdvector, bo return true; } + + template int vector_move_assignable_only(boost::container::dtl::false_type) { @@ -345,9 +347,7 @@ int vector_move_assignable_only(boost::container::dtl::true_type) //Initialize values IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType new_int(-1); - BOOST_CONTAINER_STATIC_ASSERT((boost::container::test::is_copyable::value == false)); - aux_vect[i] = boost::move(new_int); + aux_vect[i] = -1; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -374,8 +374,7 @@ int vector_move_assignable_only(boost::container::dtl::true_type) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ - IntType new_int(-i); - aux_vect[i] = boost::move(new_int); + aux_vect[i] = -i; } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -391,8 +390,7 @@ int vector_move_assignable_only(boost::container::dtl::true_type) if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; for(int i = 0; i < 50; ++i){ - IntType new_int(-i); - aux_vect[i] = boost::move(new_int); + aux_vect[i] = -i; } for(int i = 0; i < 50; ++i){ @@ -511,6 +509,30 @@ int vector_move_assignable_only(boost::container::dtl::true_type) return 0; } +template +int vector_test_fully_propagable(dtl::true_ /* fully_propagable */) +{ + typedef std::vector MyStdVector; + { + //operator=(Vector &&) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100u); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100u); + ::boost::movelib::unique_ptr const boostvectorp2 = + ::boost::movelib::make_unique(); + *boostvectorp2 = ::boost::move(*boostvectorp); + if (!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; + } + return 0; +} + +template +int vector_test_fully_propagable(dtl::false_ /* fully_propagable */) +{ + return 0; +} + template int vector_test() { @@ -551,7 +573,10 @@ int vector_test() if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; } - if (0 != vector_move_assignable_only< MyBoostVector>(dtl::bool_::value>())) + if (0 != vector_test_fully_propagable + ( dtl::bool_< !allocator_traits::is_partially_propagable::value >() )) return 1; + + if (0 != vector_move_assignable_only< MyBoostVector>(dtl::bool_::value>())) return 1; std::cout << std::endl << "Test OK!" << std::endl; From 918372911932d34f6b158764d82031d6dea30209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 23 May 2024 23:35:10 +0200 Subject: [PATCH 8/9] Update changelog with #277 and #280 --- doc/container.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/container.qbk b/doc/container.qbk index 2efe886..379533b 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1413,6 +1413,7 @@ use [*Boost.Container]? There are several reasons for that: * Fixed bugs/issues: * [@https://github.com/boostorg/container/issues/280 GitHub #280: ['"Several containers don't support non-movable types when move assigning"]]. + * [@https://github.com/boostorg/container/issues/277 GitHub #277: ['"Remove dep on boost::static_assert"]]. [endsect] From 2ed37446bca75f9a5c77e425532580d10d992939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 23 May 2024 23:55:34 +0200 Subject: [PATCH 9/9] Update changelog with #273 and #269 --- doc/container.qbk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/container.qbk b/doc/container.qbk index 379533b..fa68d54 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1414,6 +1414,8 @@ use [*Boost.Container]? There are several reasons for that: * Fixed bugs/issues: * [@https://github.com/boostorg/container/issues/280 GitHub #280: ['"Several containers don't support non-movable types when move assigning"]]. * [@https://github.com/boostorg/container/issues/277 GitHub #277: ['"Remove dep on boost::static_assert"]]. + * [@https://github.com/boostorg/container/issues/273 GitHub #273: ['"flat_map/vector crashes on appends (memory corruption)"]]. + * [@https://github.com/boostorg/container/issues/269 GitHub #269: ['"flat_multimap::emplace not sorting elements under GCC"]]. [endsect]