From 01d7c71ea80a5cc956d9fe9cf9f12c9401cea1ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 2 Apr 2017 00:20:38 +0200 Subject: [PATCH 1/8] Fix node_handle bugs: -> Bad allocator destruction in swap -> Wrong assertion in operator= -> Make dangerous functions private Added full testsuite. --- .../detail/pair_key_mapped_of_value.hpp | 55 ++ include/boost/container/detail/tree.hpp | 4 +- include/boost/container/map.hpp | 38 +- include/boost/container/node_handle.hpp | 186 ++++-- test/map_test.cpp | 7 - test/node_handle_test.cpp | 617 +++++++++++++++++- test/set_test.cpp | 2 +- 7 files changed, 793 insertions(+), 116 deletions(-) create mode 100644 include/boost/container/detail/pair_key_mapped_of_value.hpp diff --git a/include/boost/container/detail/pair_key_mapped_of_value.hpp b/include/boost/container/detail/pair_key_mapped_of_value.hpp new file mode 100644 index 0000000..6112b87 --- /dev/null +++ b/include/boost/container/detail/pair_key_mapped_of_value.hpp @@ -0,0 +1,55 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_PAIR_KEY_MAPPED_OF_VALUE_HPP +#define BOOST_CONTAINER_PAIR_KEY_MAPPED_OF_VALUE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { + +template +struct pair_key_mapped_of_value +{ + typedef Key key_type; + typedef Mapped mapped_type; + + template + const key_type & key_of_value(const Pair &p) const + { return p.first; } + + template + const mapped_type & mapped_of_value(const Pair &p) const + { return p.second; } + + template + key_type & key_of_value(Pair &p) const + { return const_cast(p.first); } + + template + mapped_type & mapped_of_value(Pair &p) const + { return p.second; } + +}; + +}} + +#include + +#endif // BOOST_CONTAINER_PAIR_KEY_MAPPED_OF_VALUE_HPP diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 853d0ad..7b29467 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -493,7 +493,7 @@ class tree typedef boost::container::reverse_iterator const_reverse_iterator; typedef node_handle - < Node, value_type, allocator_type, void> node_type; + < NodeAlloc, void> node_type; typedef insert_return_type_base insert_return_type; @@ -1142,7 +1142,7 @@ class tree this->insert_unique_check(hint, KeyOfValue()(nh.value()), data); if(ret.second){ irt.inserted = true; - irt.position = iterator(this->icont().insert_unique_commit(*nh.get_node_pointer(), data)); + irt.position = iterator(this->icont().insert_unique_commit(*nh.get(), data)); nh.release(); } else{ diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index 5520fb4..56aefa4 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -31,6 +31,8 @@ #include #include #include +#include + // move #include #include @@ -53,34 +55,6 @@ namespace boost { namespace container { -///@cond - -template -struct pair_key_mapped_of_value -{ - typedef Key key_type; - typedef Mapped mapped_type; - - template - const key_type & key_of_value(const Pair &p) const - { return p.first; } - - template - const mapped_type & mapped_of_value(const Pair &p) const - { return p.second; } - - template - key_type & key_of_value(Pair &p) const - { return const_cast(p.first); } - - template - mapped_type & mapped_of_value(Pair &p) const - { return p.second; } - -}; - -///@endcond - #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED //! A map is a kind of associative container that supports unique keys (contains at @@ -150,9 +124,7 @@ class map typedef std::pair nonconst_value_type; typedef BOOST_CONTAINER_IMPDEF(movable_value_type_impl) movable_value_type; typedef BOOST_CONTAINER_IMPDEF(node_handle< - typename base_t::node_type::container_node_type - BOOST_MOVE_I value_type - BOOST_MOVE_I allocator_type + typename base_t::stored_allocator_type BOOST_MOVE_I pair_key_mapped_of_value >) node_type; typedef BOOST_CONTAINER_IMPDEF @@ -1243,9 +1215,7 @@ class multimap typedef std::pair nonconst_value_type; typedef BOOST_CONTAINER_IMPDEF(movable_value_type_impl) movable_value_type; typedef BOOST_CONTAINER_IMPDEF(node_handle< - typename base_t::node_type::container_node_type - BOOST_MOVE_I value_type - BOOST_MOVE_I allocator_type + typename base_t::stored_allocator_type BOOST_MOVE_I pair_key_mapped_of_value >) node_type; diff --git a/include/boost/container/node_handle.hpp b/include/boost/container/node_handle.hpp index c46313c..3a969b7 100644 --- a/include/boost/container/node_handle.hpp +++ b/include/boost/container/node_handle.hpp @@ -40,20 +40,34 @@ namespace container { ///@cond -template::value> +template struct node_handle_keymapped_traits +{ + typedef typename KeyMapped::key_type key_type; + typedef typename KeyMapped::mapped_type mapped_type; +}; + +template +struct node_handle_keymapped_traits { typedef Value key_type; typedef Value mapped_type; }; -template -struct node_handle_keymapped_traits +class node_handle_friend { - typedef typename KeyMapped::key_type key_type; - typedef typename KeyMapped::mapped_type mapped_type; + public: + + template + BOOST_CONTAINER_FORCEINLINE static void destroy_alloc(NH &nh) BOOST_NOEXCEPT + { nh.destroy_alloc(); } + + template + BOOST_CONTAINER_FORCEINLINE static typename NH::node_pointer &get_node_pointer(NH &nh) BOOST_NOEXCEPT + { return nh.get_node_pointer(); } }; + ///@endcond //! A node_handle is an object that accepts ownership of a single element from an associative container. @@ -73,76 +87,63 @@ struct node_handle_keymapped_traits //! //! If a node handle is not empty, then it contains an allocator that is equal to the allocator of the container //! when the element was extracted. If a node handle is empty, it contains no allocator. -template +template class node_handle { - typedef node_handle_keymapped_traits keymapped_t; + typedef NodeAllocator nallocator_type; + typedef allocator_traits nator_traits; + typedef typename nator_traits::value_type priv_node_t; + typedef typename priv_node_t::value_type priv_value_t; + typedef node_handle_keymapped_traits keymapped_t; public: - typedef Value value_type; + typedef priv_value_t value_type; typedef typename keymapped_t::key_type key_type; typedef typename keymapped_t::mapped_type mapped_type; - typedef Allocator allocator_type; - typedef NodeType container_node_type; + typedef typename nator_traits::template portable_rebind_alloc + ::type allocator_type; + + typedef priv_node_t container_node_type; + friend class node_handle_friend; ///@cond private: BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle) - typedef allocator_traits ator_traits; - typedef typename ator_traits::template portable_rebind_alloc - ::type nallocator_type; - typedef allocator_traits node_ator_traits; - typedef typename node_ator_traits::pointer node_pointer; + typedef typename nator_traits::pointer node_pointer; typedef ::boost::aligned_storage - ::value> nalloc_storage_t; + < sizeof(nallocator_type) + , boost::alignment_of::value> nalloc_storage_t; node_pointer m_ptr; nalloc_storage_t m_nalloc_storage; void move_construct_alloc(nallocator_type &al) - { ::new(m_nalloc_storage.address(), boost_container_new_t()) allocator_type(::boost::move(al)); } + { ::new(m_nalloc_storage.address(), boost_container_new_t()) nallocator_type(::boost::move(al)); } - void destroy_node() + void destroy_deallocate_node() { - node_ator_traits::destroy(this->node_alloc(), container_detail::to_raw_pointer(m_ptr)); - node_ator_traits::deallocate(this->node_alloc(), m_ptr, 1u); + nator_traits::destroy(this->node_alloc(), container_detail::to_raw_pointer(m_ptr)); + nator_traits::deallocate(this->node_alloc(), m_ptr, 1u); } template void move_construct_end(OtherNodeHandle &nh) { if(m_ptr){ - ::new (m_nalloc_storage.address(), boost_container_new_t()) allocator_type(::boost::move(nh.node_alloc())); - nh.destroy_alloc(); - nh.get_node_pointer() = node_pointer(); + ::new (m_nalloc_storage.address(), boost_container_new_t()) nallocator_type(::boost::move(nh.node_alloc())); + node_handle_friend::destroy_alloc(nh); + node_handle_friend::get_node_pointer(nh) = node_pointer(); } BOOST_ASSERT(nh.empty()); } - public: + void destroy_alloc() BOOST_NOEXCEPT + { static_cast(m_nalloc_storage.address())->~nallocator_type(); } - void destroy_alloc() - { static_cast(m_nalloc_storage.address())->~allocator_type(); } - - node_pointer &get_node_pointer() + node_pointer &get_node_pointer() BOOST_NOEXCEPT { return m_ptr; } - nallocator_type &node_alloc() - { return *static_cast(m_nalloc_storage.address()); } - - const nallocator_type &node_alloc() const - { return *static_cast(m_nalloc_storage.address()); } - - node_pointer release() - { - node_pointer p(m_ptr); - m_ptr = node_pointer(); - if(p) - this->destroy_alloc(); - return p; - } - ///@endcond public: @@ -150,13 +151,13 @@ class node_handle //! //! Postcondition: this->empty() BOOST_CXX14_CONSTEXPR node_handle() BOOST_NOEXCEPT - : m_ptr(), m_nalloc_storage() - { BOOST_ASSERT(this->empty()); } + : m_ptr() + { } //! Effects: Constructs a node_handle object initializing internal pointer with p. - //! If p != nullptr copy constructs internal allocator al. + //! If p != nullptr copy constructs internal allocator from al. node_handle(node_pointer p, const nallocator_type &al) BOOST_NOEXCEPT - : m_ptr(p), m_nalloc_storage() + : m_ptr(p) { if(m_ptr){ ::new (m_nalloc_storage.address(), boost_container_new_t()) nallocator_type(al); @@ -172,12 +173,12 @@ class node_handle //! Note: Two node_handle's are related if only one of KeyMapped template parameter //! of a node handle is void. template - node_handle( BOOST_RV_REF_BEG node_handle BOOST_RV_REF_END nh + node_handle( BOOST_RV_REF_BEG node_handle BOOST_RV_REF_END nh , typename container_detail::enable_if_c < ((unsigned)container_detail::is_same::value + (unsigned)container_detail::is_same::value) == 1u - >::type* = 0) - : m_ptr(nh.get_node_pointer()), m_nalloc_storage() + >::type* = 0) BOOST_NOEXCEPT + : m_ptr(nh.get()) { this->move_construct_end(nh); } //! Effects: Constructs a node_handle object initializing internal pointer with nh's internal pointer @@ -186,43 +187,44 @@ class node_handle //! //! Postcondition: nh.empty() node_handle (BOOST_RV_REF(node_handle) nh) BOOST_NOEXCEPT - : m_ptr(nh.m_ptr), m_nalloc_storage() + : m_ptr(nh.m_ptr) { this->move_construct_end(nh); } //! Effects: If !this->empty(), destroys the value_type subobject in the container_node_type object //! pointed to by c by calling allocator_traits::destroy, then deallocates m_ptr by calling - //! ator_traits::rebind_traits::deallocate. - ~node_handle () BOOST_NOEXCEPT + //! nator_traits::rebind_traits::deallocate. + ~node_handle() BOOST_NOEXCEPT { if(!this->empty()){ - this->destroy_node(); + this->destroy_deallocate_node(); this->destroy_alloc(); } } - //! Requires: Either this->empty(), or ator_traits::propagate_on_container_move_assignment is true, or + //! Requires: Either this->empty(), or nator_traits::propagate_on_container_move_assignment is true, or //! node_alloc() == nh.node_alloc(). //! //! Effects: If m_ptr != nullptr, destroys the value_type subobject in the container_node_type object - //! pointed to by m_ptr by calling ator_traits::destroy, then deallocates m_ptr by calling ator_- - //! traits::rebind_traits::deallocate. Assigns nh.m_ptr to m_ptr. If this->empty() - //! or ator_traits::propagate_on_container_move_assignment is true, move assigns nh.node_alloc() to + //! pointed to by m_ptr by calling nator_traits::destroy, then deallocates m_ptr by calling + //! nator_traits::deallocate. Assigns nh.m_ptr to m_ptr. If this->empty() + //! or nator_traits::propagate_on_container_move_assignment is true, move assigns nh.node_alloc() to //! node_alloc(). Assigns nullptr to nh.m_ptr and assigns nullopt to nh.node_alloc(). + //! //! Returns: *this. //! //! Throws: Nothing. - node_handle & operator=(BOOST_RV_REF(node_handle) nh) + node_handle & operator=(BOOST_RV_REF(node_handle) nh) BOOST_NOEXCEPT { - BOOST_ASSERT(this->empty() || nh.empty() || ator_traits::propagate_on_container_move_assignment::value - || ator_traits::equal(node_alloc(), nh.node_alloc())); + BOOST_ASSERT(this->empty() || nator_traits::propagate_on_container_move_assignment::value + || nator_traits::equal(node_alloc(), nh.node_alloc())); bool const was_this_non_null = !this->empty(); bool const was_nh_non_null = !nh.empty(); if(was_nh_non_null){ if(was_this_non_null){ - this->destroy_node(); - if(ator_traits::propagate_on_container_move_assignment::value){ + this->destroy_deallocate_node(); + if(nator_traits::propagate_on_container_move_assignment::value){ this->node_alloc() = ::boost::move(nh.node_alloc()); } } @@ -234,7 +236,7 @@ class node_handle nh.destroy_alloc(); } else if(was_this_non_null){ - this->destroy_node(); + this->destroy_deallocate_node(); this->destroy_alloc(); m_ptr = node_pointer(); } @@ -310,23 +312,23 @@ class node_handle return !this->m_ptr; } - //! Requires: this->empty(), or nh.empty(), or ator_traits::propagate_on_container_swap is true, or + //! Requires: this->empty(), or nh.empty(), or nator_traits::propagate_on_container_swap is true, or //! node_alloc() == nh.node_alloc(). //! - //! Effects: Calls swap(m_ptr, nh.m_ptr). If this->empty(), or nh.empty(), or ator_traits::propagate_on_- + //! Effects: Calls swap(m_ptr, nh.m_ptr). If this->empty(), or nh.empty(), or nator_traits::propagate_on_- //! container_swap is true calls swap(node_alloc(), nh.node_alloc()). void swap(node_handle &nh) - BOOST_NOEXCEPT_IF(ator_traits::propagate_on_container_swap::value || ator_traits::is_always_equal::value) + BOOST_NOEXCEPT_IF(nator_traits::propagate_on_container_swap::value || nator_traits::is_always_equal::value) { - BOOST_ASSERT(this->empty() || nh.empty() || ator_traits::propagate_on_container_swap::value - || ator_traits::equal(node_alloc(), nh.node_alloc())); + BOOST_ASSERT(this->empty() || nh.empty() || nator_traits::propagate_on_container_swap::value + || nator_traits::equal(node_alloc(), nh.node_alloc())); bool const was_this_non_null = !this->empty(); bool const was_nh_non_null = !nh.empty(); if(was_nh_non_null){ if(was_this_non_null){ - if(ator_traits::propagate_on_container_swap::value){ + if(nator_traits::propagate_on_container_swap::value){ ::boost::adl_move_swap(this->node_alloc(), nh.node_alloc()); } } @@ -337,11 +339,53 @@ class node_handle } else if(was_this_non_null){ nh.move_construct_alloc(this->node_alloc()); - nh.destroy_alloc(); + this->destroy_alloc(); } ::boost::adl_move_swap(m_ptr, nh.m_ptr); } + //! Effects: If this->empty() returns nullptr, otherwise returns m_ptr + //! resets m_ptr to nullptr and destroys the internal allocator. + //! + //! Postcondition: this->empty() + //! + //! Note: Non-standard extensions + node_pointer release() BOOST_NOEXCEPT + { + node_pointer p(m_ptr); + m_ptr = node_pointer(); + if(p) + this->destroy_alloc(); + return p; + } + + //! Effects: Returns m_ptr. + //! + //! Note: Non-standard extensions + node_pointer get() const BOOST_NOEXCEPT + { + return m_ptr; + } + + //! Effects: Returns a reference to the internal node allocator. + //! + //! Note: Non-standard extensions + nallocator_type &node_alloc() BOOST_NOEXCEPT + { + BOOST_ASSERT(!empty()); + return *static_cast(m_nalloc_storage.address()); + } + + + //! Effects: Returns a reference to the internal node allocator. + //! + //! Note: Non-standard extensions + const nallocator_type &node_alloc() const BOOST_NOEXCEPT + { + BOOST_ASSERT(!empty()); + return *static_cast(m_nalloc_storage.address()); + } + //! Effects: x.swap(y). //! friend void swap(node_handle & x, node_handle & y) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) diff --git a/test/map_test.cpp b/test/map_test.cpp index 121abb2..9d8839b 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -38,13 +38,6 @@ template class map , test::simple_allocator< pair_t > >; -template class map - < test::movable_and_copyable_int - , test::movable_and_copyable_int - , std::less - , std::allocator< pair_t > - >; - template class map < test::movable_and_copyable_int , test::movable_and_copyable_int diff --git a/test/node_handle_test.cpp b/test/node_handle_test.cpp index c516913..94ce2ed 100644 --- a/test/node_handle_test.cpp +++ b/test/node_handle_test.cpp @@ -8,11 +8,626 @@ // ////////////////////////////////////////////////////////////////////////////// #include +#include #include +#include +#include +#include +#include using namespace ::boost::container; -int main () +enum EAllocState { + DefaultConstructed, + MoveConstructed, + MoveAssigned, + CopyConstructed, + CopyAssigned, + Swapped, + Destructed +}; + +template +class trace_allocator + : public new_allocator +{ + BOOST_COPYABLE_AND_MOVABLE(trace_allocator) + + typedef new_allocator base_t; + + public: + + struct propagate_on_container_move_assignment + { + static const bool value = true; + }; + + struct propagate_on_container_swap + { + static const bool value = true; + }; + + //!Obtains an new_allocator that allocates + //!objects of type T2 + template + struct rebind + { + typedef trace_allocator other; + }; + + explicit trace_allocator(unsigned value = 999) + : m_state(DefaultConstructed), m_value(value) + { + ++count; + } + + trace_allocator(BOOST_RV_REF(trace_allocator) other) + : base_t(boost::move(BOOST_MOVE_BASE(base_t, other))), m_state(MoveConstructed), m_value(other.m_value) + { + ++count; + } + + trace_allocator(const trace_allocator &other) + : base_t(other), m_state(CopyConstructed), m_value(other.m_value) + { + ++count; + } + + trace_allocator & operator=(BOOST_RV_REF(trace_allocator) other) + { + m_value = other.m_value; + m_state = MoveAssigned; + return *this; + } + + template + trace_allocator(const trace_allocator &other) + : m_state(CopyConstructed), m_value(other.m_value) + { + ++count; + } + + template + trace_allocator & operator=(BOOST_COPY_ASSIGN_REF(trace_allocator) other) + { + m_value = other.m_value; + m_state = CopyAssigned; + return *this; + } + + ~trace_allocator() + { + m_value = 0u-1u; + m_state = Destructed; + --count; + } + + void swap(trace_allocator &other) + { + boost::adl_move_swap(m_value, other.m_value); + m_state = other.m_state = Swapped; + } + + friend void swap(trace_allocator &left, trace_allocator &right) + { + left.swap(right); + } + + EAllocState m_state; + unsigned m_value; + + static unsigned int count; + + static void reset_count() + { count = 0; } +}; + +template +unsigned int trace_allocator::count = 0; + +template +struct node +{ + typedef T value_type; + value_type value; + + value_type &get_data() { return value; } + const value_type &get_data() const { return value; } + + node() + { + ++count; + } + + ~node() + { + --count; + } + + static unsigned int count; + + static void reset_count() + { count = 0; } +}; + +template +struct value +{ + T1 first; + T2 second; +}; + +template +unsigned int node::count = 0; + + +//Common types +typedef value test_pair; +typedef pair_key_mapped_of_value key_mapped_t; +typedef node node_t; +typedef trace_allocator< node_t > node_alloc_t; +typedef node_handle node_handle_set_t; +typedef node_handle node_handle_map_t; +typedef allocator_traits::portable_rebind_alloc::type value_allocator_type; + +void test_types() +{ + //set + BOOST_STATIC_ASSERT(( container_detail::is_same::value )); + BOOST_STATIC_ASSERT(( container_detail::is_same::value )); + BOOST_STATIC_ASSERT(( container_detail::is_same::value )); + BOOST_STATIC_ASSERT(( container_detail::is_same::value )); + + //map + BOOST_STATIC_ASSERT(( container_detail::is_same::value )); + BOOST_STATIC_ASSERT(( container_detail::is_same::value )); + BOOST_STATIC_ASSERT(( container_detail::is_same::value )); + BOOST_STATIC_ASSERT(( container_detail::is_same::value )); +} + +void test_default_constructor() +{ + node_alloc_t::reset_count(); + { + node_handle_set_t nh; + BOOST_TEST(node_alloc_t::count == 0); + } + BOOST_TEST(node_alloc_t::count == 0); +} + +void test_arg_constructor() +{ + //With non-null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_handle_set_t nh(new node_t, al); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 2); + } + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + //With null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_handle_set_t nh(0, al); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_alloc_t::count == 1); + BOOST_TEST(node_t::count == 0); + } + BOOST_TEST(node_alloc_t::count == 0); +} + +void test_move_constructor() +{ + //With non-null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_t *const from_ptr = new node_t; + node_handle_set_t nh(from_ptr, al); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 2); + { + node_handle_set_t nh2(boost::move(nh)); + BOOST_TEST(nh.empty()); + BOOST_TEST(!nh2.empty()); + BOOST_TEST(nh2.get() == from_ptr); + BOOST_TEST(nh2.node_alloc().m_state == MoveConstructed); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 2); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + //With null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_handle_set_t nh; + { + node_handle_set_t nh2(boost::move(nh)); + BOOST_TEST(nh.empty()); + BOOST_TEST(nh2.empty()); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); +} + +void test_related_constructor() +{ + //With non-null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_t *const from_ptr = new node_t; + node_handle_map_t nh(from_ptr, al); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 2); + { + node_handle_set_t nh2(boost::move(nh)); + BOOST_TEST(nh.empty()); + BOOST_TEST(!nh2.empty()); + BOOST_TEST(nh2.get() == from_ptr); + BOOST_TEST(nh2.node_alloc().m_state == MoveConstructed); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 2); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + //With null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_handle_set_t nh; + { + node_handle_map_t nh2(boost::move(nh)); + BOOST_TEST(nh.empty()); + BOOST_TEST(nh2.empty()); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); +} + +void test_move_assignment() +{ + //empty = full + { + node_alloc_t::reset_count(); + node_t::reset_count(); + node_t *const from_ptr = new node_t; + node_handle_set_t nh_from(from_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + node_handle_set_t nh_to; + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + nh_to = boost::move(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(!nh_to.empty()); + BOOST_TEST(nh_to.get() == from_ptr); + BOOST_TEST(nh_to.node_alloc().m_state == MoveConstructed); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + } + + //empty = empty + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_handle_set_t nh_from; + BOOST_TEST(nh_from.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + node_handle_set_t nh_to; + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + nh_to = boost::move(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + } + + //full = empty + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_handle_set_t nh_from; + BOOST_TEST(nh_from.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + node_handle_set_t nh_to(new node_t, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + nh_to = boost::move(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + } + + //full = full + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_t *const from_ptr = new node_t; + node_handle_set_t nh_from(from_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + node_handle_set_t nh_to(new node_t, node_alloc_t()); + BOOST_TEST(node_t::count == 2); + BOOST_TEST(node_alloc_t::count == 2); + + nh_to = boost::move(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(!nh_to.empty()); + BOOST_TEST(nh_to.get() == from_ptr); + BOOST_TEST(nh_to.node_alloc().m_state == MoveAssigned); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + } +} + +void test_value_key_mapped() +{ + //value() + { + node_t *from_ptr = new node_t; + const node_handle_set_t nh_from(from_ptr, node_alloc_t()); + from_ptr->value.first = -99; + from_ptr->value.second = 99; + BOOST_TEST(nh_from.value().first == -99); + BOOST_TEST(nh_from.value().second == 99); + } + //key()/mapped() + { + node_t *from_ptr = new node_t; + const node_handle_map_t nh_from(from_ptr, node_alloc_t()); + from_ptr->value.first = -98; + from_ptr->value.second = 98; + BOOST_TEST(nh_from.key() == -98); + BOOST_TEST(nh_from.mapped() == 98); + } +} + +void test_get_allocator() +{ + const node_handle_set_t nh(new node_t, node_alloc_t(888)); + allocator_traits::portable_rebind_alloc::type a = nh.get_allocator(); + BOOST_TEST(a.m_value == 888); +} + +void test_bool_conversion_empty() +{ + const node_handle_set_t nh(new node_t, node_alloc_t(777)); + const node_handle_set_t nh_null; + BOOST_TEST(nh && !nh_null); + BOOST_TEST(!(!nh || nh_null)); + BOOST_TEST(!nh.empty() && nh_null.empty()); + BOOST_TEST(!(nh.empty() || !nh_null.empty())); +} + +void test_swap() +{ + //empty.swap(full) + { + node_alloc_t::reset_count(); + node_t::reset_count(); + node_t *const from_ptr = new node_t; + node_handle_set_t nh_from(from_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + node_handle_set_t nh_to; + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + nh_to.swap(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(!nh_to.empty()); + BOOST_TEST(nh_to.get() == from_ptr); + BOOST_TEST(nh_to.node_alloc().m_state == MoveConstructed); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + } + + //empty.swap(empty) + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_handle_set_t nh_from; + BOOST_TEST(nh_from.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + node_handle_set_t nh_to; + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + nh_to.swap(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + } + + //full.swap(empty) + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_handle_set_t nh_from; + BOOST_TEST(nh_from.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + node_t *const to_ptr = new node_t; + node_handle_set_t nh_to(to_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + nh_to.swap(nh_from); + + BOOST_TEST(!nh_from.empty()); + BOOST_TEST(nh_from.node_alloc().m_state == MoveConstructed); + BOOST_TEST(nh_from.get() == to_ptr); + BOOST_TEST(nh_to.empty()); + + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + } + + //full.swap(full) + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_t *const from_ptr = new node_t; + node_handle_set_t nh_from(from_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + node_t *const to_ptr = new node_t; + node_handle_set_t nh_to(to_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 2); + BOOST_TEST(node_alloc_t::count == 2); + + nh_to.swap(nh_from); + + BOOST_TEST(!nh_from.empty()); + BOOST_TEST(nh_from.get() == to_ptr); + BOOST_TEST(nh_from.node_alloc().m_state == Swapped); + + BOOST_TEST(!nh_to.empty()); + BOOST_TEST(nh_to.get() == from_ptr); + BOOST_TEST(nh_to.node_alloc().m_state == Swapped); + + BOOST_TEST(node_t::count == 2); + BOOST_TEST(node_alloc_t::count == 2); + } +} + +void test_get_release() +{ + //get() + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_t *const ptr = new node_t; + const node_handle_set_t nh(ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + BOOST_TEST(nh.get() == ptr); + BOOST_TEST(!nh.empty()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + //release() + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_t *const ptr = new node_t; + node_handle_set_t nh(ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + BOOST_TEST(nh.release() == ptr); + BOOST_TEST(nh.empty()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 0); + delete ptr; + } + BOOST_TEST(node_t::count == 0); +} + +int main() +{ + test_types(); + test_default_constructor(); + test_arg_constructor(); + test_move_constructor(); + test_related_constructor(); + test_move_assignment(); + test_value_key_mapped(); + test_get_allocator(); + test_bool_conversion_empty(); + test_swap(); + test_get_release(); return ::boost::report_errors(); } diff --git a/test/set_test.cpp b/test/set_test.cpp index c2ce696..b3b8309 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -37,7 +37,7 @@ template class set template class set < test::movable_and_copyable_int , std::less - , adaptive_pool + , new_allocator >; //multiset From cdb022fda2b72b47171dd743b823a8ef31258b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 5 Apr 2017 16:04:53 +0200 Subject: [PATCH 2/8] Fix ambiguous constructor calls for piecewise_construct and Boost vs std tuples --- include/boost/container/detail/pair.hpp | 61 +++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/include/boost/container/detail/pair.hpp b/include/boost/container/detail/pair.hpp index 4abff4b..4755e56 100644 --- a/include/boost/container/detail/pair.hpp +++ b/include/boost/container/detail/pair.hpp @@ -35,16 +35,62 @@ #include //pair #include -#include +#include namespace boost { namespace tuples { struct null_type; +template < + class T0, class T1, class T2, + class T3, class T4, class T5, + class T6, class T7, class T8, + class T9> +class tuple; + } //namespace tuples { } //namespace boost { +namespace boost { +namespace container { +namespace pair_impl { + +template +struct is_boost_tuple +{ + static const bool value = false; +}; + +template < + class T0, class T1, class T2, + class T3, class T4, class T5, + class T6, class T7, class T8, + class T9> +struct is_boost_tuple< boost::tuples::tuple > +{ + static const bool value = true; +}; + +template +struct disable_if_boost_tuple + : boost::container::container_detail::disable_if< is_boost_tuple > +{}; + +template +struct is_tuple_null +{ + static const bool value = false; +}; + +template<> +struct is_tuple_null +{ + static const bool value = true; +}; + +}}} + #if defined(BOOST_MSVC) && (_CPPLIB_VER == 520) //MSVC 2010 tuple marker namespace std { namespace tr1 { struct _Nil; }} @@ -236,7 +282,12 @@ struct pair BOOST_MOVE_I_IF(BOOST_MOVE_OR(N,M)) BOOST_MOVE_CLASS##N BOOST_MOVE_I_IF(BOOST_MOVE_AND(N,M)) BOOST_MOVE_CLASSQ##M > \ pair( piecewise_construct_t\ , BoostTuple p\ - , BoostTuple q)\ + , BoostTuple q\ + , typename container_detail::enable_if_c\ + < pair_impl::is_boost_tuple< BoostTuple >::value &&\ + !(pair_impl::is_tuple_null::value || pair_impl::is_tuple_null::value) \ + >::type* = 0\ + )\ : first(BOOST_MOVE_TMPL_GET##N), second(BOOST_MOVE_TMPL_GETQ##M)\ { (void)p; (void)q; }\ // @@ -254,7 +305,8 @@ struct pair { (void) t1; (void)t2; } public: - template class Tuple, class... Args1, class... Args2> + template< template class Tuple, class... Args1, class... Args2 + , class = typename pair_impl::disable_if_boost_tuple< Tuple >::type> pair(piecewise_construct_t, Tuple t1, Tuple t2) : pair(t1, t2, typename build_number_seq::type(), typename build_number_seq::type()) {} @@ -270,7 +322,8 @@ struct pair { (void)t; return T(::boost::forward(get(t))...); } public: - template class Tuple, class... Args1, class... Args2> + template< template class Tuple, class... Args1, class... Args2 + , class = typename pair_impl::disable_if_boost_tuple< Tuple >::type> pair(piecewise_construct_t, Tuple t1, Tuple t2) : first (build_from_args (::boost::move(t1))) , second (build_from_args(::boost::move(t2))) From d6749960fc896c451cb23633f1f6f3144cdf4017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 5 Apr 2017 16:06:31 +0200 Subject: [PATCH 3/8] Implement `extract_sequence` and `adopt_sequence` for flat ordered associative containers --- doc/container.qbk | 5 + include/boost/container/detail/flat_tree.hpp | 197 ++++++++++++------- include/boost/container/flat_map.hpp | 70 +++++++ include/boost/container/flat_set.hpp | 61 ++++++ test/flat_map_test.cpp | 117 +++++++++++ test/flat_set_test.cpp | 117 +++++++++++ 6 files changed, 498 insertions(+), 69 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 1bf1598..0749045 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1213,6 +1213,11 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] +[section:release_notes_boost_1_65_00 Boost 1.65 Release] + +* Implemented `extract_sequence`, `adopt_sequence` functions for flat_[multi]map/set associative containers. + +[endsect] [section:release_notes_boost_1_64_00 Boost 1.64 Release] diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 93984d1..16d2991 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -28,25 +28,30 @@ #include #include +#include + #include #include #include //algo_equal(), algo_lexicographical_compare #include #include -#include +#include +#include + #ifdef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER #include #endif -#include -#include +#include //pair + #include +#include #include +#include + #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include #endif -#include //pair -#include namespace boost { namespace container { @@ -105,14 +110,17 @@ template class flat_tree { - typedef boost::container::vector vector_t; + public: + typedef boost::container::vector sequence_type; + + private: typedef Allocator allocator_t; typedef allocator_traits allocator_traits_type; public: typedef flat_tree_value_compare value_compare; - private: + private: struct Data //Inherit from value_compare to do EBO : public value_compare @@ -121,48 +129,48 @@ class flat_tree public: Data() - : value_compare(), m_vect() + : value_compare(), m_seq() {} explicit Data(const Data &d) - : value_compare(static_cast(d)), m_vect(d.m_vect) + : value_compare(static_cast(d)), m_seq(d.m_seq) {} Data(BOOST_RV_REF(Data) d) - : value_compare(boost::move(static_cast(d))), m_vect(boost::move(d.m_vect)) + : value_compare(boost::move(static_cast(d))), m_seq(boost::move(d.m_seq)) {} Data(const Data &d, const Allocator &a) - : value_compare(static_cast(d)), m_vect(d.m_vect, a) + : value_compare(static_cast(d)), m_seq(d.m_seq, a) {} Data(BOOST_RV_REF(Data) d, const Allocator &a) - : value_compare(boost::move(static_cast(d))), m_vect(boost::move(d.m_vect), a) + : value_compare(boost::move(static_cast(d))), m_seq(boost::move(d.m_seq), a) {} explicit Data(const Compare &comp) - : value_compare(comp), m_vect() + : value_compare(comp), m_seq() {} Data(const Compare &comp, const allocator_t &alloc) - : value_compare(comp), m_vect(alloc) + : value_compare(comp), m_seq(alloc) {} explicit Data(const allocator_t &alloc) - : value_compare(), m_vect(alloc) + : value_compare(), m_seq(alloc) {} Data& operator=(BOOST_COPY_ASSIGN_REF(Data) d) { this->value_compare::operator=(d); - m_vect = d.m_vect; + m_seq = d.m_seq; return *this; } Data& operator=(BOOST_RV_REF(Data) d) { this->value_compare::operator=(boost::move(static_cast(d))); - m_vect = boost::move(d.m_vect); + m_seq = boost::move(d.m_seq); return *this; } @@ -170,10 +178,10 @@ class flat_tree { value_compare& mycomp = *this, & othercomp = d; boost::adl_move_swap(mycomp, othercomp); - this->m_vect.swap(d.m_vect); + this->m_seq.swap(d.m_seq); } - vector_t m_vect; + sequence_type m_seq; }; Data m_data; @@ -181,23 +189,23 @@ class flat_tree public: - typedef typename vector_t::value_type value_type; - typedef typename vector_t::pointer pointer; - typedef typename vector_t::const_pointer const_pointer; - typedef typename vector_t::reference reference; - typedef typename vector_t::const_reference const_reference; - typedef typename KeyOfValue::type key_type; - typedef Compare key_compare; - typedef typename vector_t::allocator_type allocator_type; - typedef typename vector_t::size_type size_type; - typedef typename vector_t::difference_type difference_type; - typedef typename vector_t::iterator iterator; - typedef typename vector_t::const_iterator const_iterator; - typedef typename vector_t::reverse_iterator reverse_iterator; - typedef typename vector_t::const_reverse_iterator const_reverse_iterator; + typedef typename sequence_type::value_type value_type; + typedef typename sequence_type::pointer pointer; + typedef typename sequence_type::const_pointer const_pointer; + typedef typename sequence_type::reference reference; + typedef typename sequence_type::const_reference const_reference; + typedef typename KeyOfValue::type key_type; + typedef Compare key_compare; + typedef typename sequence_type::allocator_type allocator_type; + typedef typename sequence_type::size_type size_type; + typedef typename sequence_type::difference_type difference_type; + typedef typename sequence_type::iterator iterator; + typedef typename sequence_type::const_iterator const_iterator; + typedef typename sequence_type::reverse_iterator reverse_iterator; + typedef typename sequence_type::const_reverse_iterator const_reverse_iterator; //!Standard extension - typedef allocator_type stored_allocator_type; + typedef allocator_type stored_allocator_type; private: typedef allocator_traits stored_allocator_traits; @@ -242,8 +250,8 @@ class flat_tree , const allocator_type& a = allocator_type()) : m_data(comp, a) { - this->m_data.m_vect.insert(this->m_data.m_vect.end(), first, last); - BOOST_ASSERT((is_sorted)(this->m_data.m_vect.cbegin(), this->m_data.m_vect.cend(), this->priv_value_comp())); + this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last); + BOOST_ASSERT((is_sorted)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp())); } template @@ -252,8 +260,8 @@ class flat_tree , const allocator_type& a = allocator_type()) : m_data(comp, a) { - this->m_data.m_vect.insert(this->m_data.m_vect.end(), first, last); - BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_vect.cbegin(), this->m_data.m_vect.cend(), this->priv_value_comp())); + this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last); + BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp())); } template @@ -312,31 +320,31 @@ class flat_tree { return this->m_data; } BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const - { return this->m_data.m_vect.get_allocator(); } + { return this->m_data.m_seq.get_allocator(); } BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const - { return this->m_data.m_vect.get_stored_allocator(); } + { return this->m_data.m_seq.get_stored_allocator(); } BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator() - { return this->m_data.m_vect.get_stored_allocator(); } + { return this->m_data.m_seq.get_stored_allocator(); } BOOST_CONTAINER_FORCEINLINE iterator begin() - { return this->m_data.m_vect.begin(); } + { return this->m_data.m_seq.begin(); } BOOST_CONTAINER_FORCEINLINE const_iterator begin() const { return this->cbegin(); } BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const - { return this->m_data.m_vect.begin(); } + { return this->m_data.m_seq.begin(); } BOOST_CONTAINER_FORCEINLINE iterator end() - { return this->m_data.m_vect.end(); } + { return this->m_data.m_seq.end(); } BOOST_CONTAINER_FORCEINLINE const_iterator end() const { return this->cend(); } BOOST_CONTAINER_FORCEINLINE const_iterator cend() const - { return this->m_data.m_vect.end(); } + { return this->m_data.m_seq.end(); } BOOST_CONTAINER_FORCEINLINE reverse_iterator rbegin() { return reverse_iterator(this->end()); } @@ -357,13 +365,13 @@ class flat_tree { return const_reverse_iterator(this->cbegin()); } BOOST_CONTAINER_FORCEINLINE bool empty() const - { return this->m_data.m_vect.empty(); } + { return this->m_data.m_seq.empty(); } BOOST_CONTAINER_FORCEINLINE size_type size() const - { return this->m_data.m_vect.size(); } + { return this->m_data.m_seq.size(); } BOOST_CONTAINER_FORCEINLINE size_type max_size() const - { return this->m_data.m_vect.max_size(); } + { return this->m_data.m_seq.max_size(); } BOOST_CONTAINER_FORCEINLINE void swap(flat_tree& other) BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value @@ -395,14 +403,14 @@ class flat_tree iterator insert_equal(const value_type& val) { iterator i = this->upper_bound(KeyOfValue()(val)); - i = this->m_data.m_vect.insert(i, val); + i = this->m_data.m_seq.insert(i, val); return i; } iterator insert_equal(BOOST_RV_REF(value_type) mval) { iterator i = this->upper_bound(KeyOfValue()(mval)); - i = this->m_data.m_vect.insert(i, boost::move(mval)); + i = this->m_data.m_seq.insert(i, boost::move(mval)); return i; } @@ -509,7 +517,7 @@ class flat_tree >::type * = 0 #endif ) - { this->m_data.m_vect.merge(first, last, static_cast(this->m_data)); } + { this->m_data.m_seq.merge(first, last, static_cast(this->m_data)); } template void insert_unique(ordered_unique_range_t, InIt first, InIt last @@ -538,7 +546,7 @@ class flat_tree >::type * = 0 #endif ) - { this->m_data.m_vect.merge_unique(first, last, static_cast(this->m_data)); } + { this->m_data.m_seq.merge_unique(first, last, static_cast(this->m_data)); } #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -606,7 +614,7 @@ class flat_tree typedef typename emplace_functor_type::type func_t; typedef emplace_iterator it_t; func_t func(try_emplace_t(), ::boost::forward(key), ::boost::forward(args)...); - ret.first = this->m_data.m_vect.insert(data.position, it_t(func), it_t()); + ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t()); } return ret; } @@ -675,7 +683,7 @@ class flat_tree typedef typename emplace_functor_type::type func_t;\ typedef emplace_iterator it_t;\ func_t func(try_emplace_t(), ::boost::forward(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - ret.first = this->m_data.m_vect.insert(data.position, it_t(func), it_t());\ + ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t());\ }\ return ret;\ }\ @@ -702,29 +710,29 @@ class flat_tree typedef typename emplace_functor_type::type func_t; typedef emplace_iterator it_t; func_t func(boost::forward(key), boost::forward(obj)); - ret.first = this->m_data.m_vect.insert(data.position, it_t(func), it_t()); + ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t()); } return ret; } BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator position) - { return this->m_data.m_vect.erase(position); } + { return this->m_data.m_seq.erase(position); } size_type erase(const key_type& k) { std::pair itp = this->equal_range(k); size_type ret = static_cast(itp.second-itp.first); if (ret){ - this->m_data.m_vect.erase(itp.first, itp.second); + this->m_data.m_seq.erase(itp.first, itp.second); } return ret; } BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator first, const_iterator last) - { return this->m_data.m_vect.erase(first, last); } + { return this->m_data.m_seq.erase(first, last); } BOOST_CONTAINER_FORCEINLINE void clear() - { this->m_data.m_vect.clear(); } + { this->m_data.m_seq.clear(); } //! Effects: Tries to deallocate the excess of memory created // with previous allocations. The size of the vector is unchanged @@ -733,19 +741,19 @@ class flat_tree //! //! Complexity: Linear to size(). BOOST_CONTAINER_FORCEINLINE void shrink_to_fit() - { this->m_data.m_vect.shrink_to_fit(); } + { this->m_data.m_seq.shrink_to_fit(); } BOOST_CONTAINER_FORCEINLINE iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_data.m_vect.nth(n); } + { return this->m_data.m_seq.nth(n); } BOOST_CONTAINER_FORCEINLINE const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_data.m_vect.nth(n); } + { return this->m_data.m_seq.nth(n); } BOOST_CONTAINER_FORCEINLINE size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_data.m_vect.index_of(p); } + { return this->m_data.m_seq.index_of(p); } BOOST_CONTAINER_FORCEINLINE size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_data.m_vect.index_of(p); } + { return this->m_data.m_seq.index_of(p); } // set operations: iterator find(const key_type& k) @@ -793,7 +801,7 @@ class flat_tree void merge_unique(flat_tree& source) { - this->m_data.m_vect.merge_unique + this->m_data.m_seq.merge_unique ( boost::make_move_iterator(source.begin()) , boost::make_move_iterator(source.end()) , static_cast(this->m_data)); @@ -801,7 +809,7 @@ class flat_tree void merge_equal(flat_tree& source) { - this->m_data.m_vect.merge + this->m_data.m_seq.merge ( boost::make_move_iterator(source.begin()) , boost::make_move_iterator(source.end()) , static_cast(this->m_data)); @@ -832,10 +840,61 @@ class flat_tree { return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); } BOOST_CONTAINER_FORCEINLINE size_type capacity() const - { return this->m_data.m_vect.capacity(); } + { return this->m_data.m_seq.capacity(); } BOOST_CONTAINER_FORCEINLINE void reserve(size_type cnt) - { this->m_data.m_vect.reserve(cnt); } + { this->m_data.m_seq.reserve(cnt); } + + BOOST_CONTAINER_FORCEINLINE sequence_type extract_sequence() + { + return boost::move(m_data.m_seq); + } + + BOOST_CONTAINER_FORCEINLINE sequence_type &get_sequence_ref() + { + return m_data.m_seq; + } + + void adopt_sequence_equal(BOOST_RV_REF(sequence_type) seq) + { + sequence_type &tseq = m_data.m_seq; + boost::movelib::adaptive_sort + ( container_detail::iterator_to_raw_pointer(seq.begin()) + , container_detail::iterator_to_raw_pointer(seq.end()) + , this->priv_value_comp() + , container_detail::iterator_to_raw_pointer(tseq.begin() + tseq.size()) + , tseq.capacity() - tseq.size()); + tseq = boost::move(seq); + } + + void adopt_sequence_equal(ordered_range_t, BOOST_RV_REF(sequence_type) seq) + { + BOOST_ASSERT((is_sorted)(seq.cbegin(), seq.cend(), this->priv_value_comp())); + sequence_type &tseq = m_data.m_seq; + tseq = boost::move(seq); + } + + void adopt_sequence_unique(BOOST_RV_REF(sequence_type) seq) + { + sequence_type &tseq = m_data.m_seq; + boost::movelib::adaptive_sort + ( container_detail::iterator_to_raw_pointer(seq.begin()) + , container_detail::iterator_to_raw_pointer(seq.end()) + , this->priv_value_comp() + , container_detail::iterator_to_raw_pointer(tseq.begin() + tseq.size()) + , tseq.capacity() - tseq.size()); + seq.erase( boost::movelib::unique + (seq.begin(), seq.end(), boost::movelib::negate(this->m_data.get_comp())) + , seq.cend()); + tseq = boost::move(seq); + } + + void adopt_sequence_unique(ordered_unique_range_t, BOOST_RV_REF(sequence_type) seq) + { + BOOST_ASSERT((is_sorted_and_unique)(seq.cbegin(), seq.cend(), this->priv_value_comp())); + sequence_type &tseq = m_data.m_seq; + tseq = boost::move(seq); + } BOOST_CONTAINER_FORCEINLINE friend bool operator==(const flat_tree& x, const flat_tree& y) { @@ -963,7 +1022,7 @@ class flat_tree BOOST_CONTAINER_FORCEINLINE iterator priv_insert_commit (insert_commit_data &commit_data, BOOST_FWD_REF(Convertible) convertible) { - return this->m_data.m_vect.insert + return this->m_data.m_seq.insert ( commit_data.position , boost::forward(convertible)); } diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index b842101..c5d6e03 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -144,8 +144,10 @@ class flat_map ::pointer>::reverse_iterator reverse_iterator_impl; typedef typename container_detail::get_flat_tree_iterators ::pointer>::const_reverse_iterator const_reverse_iterator_impl; + public: typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type; + typedef typename impl_tree_t::sequence_type impl_sequence_type; impl_tree_t &tree() { return m_flat_tree; } @@ -182,6 +184,7 @@ class flat_map typedef BOOST_CONTAINER_IMPDEF(reverse_iterator_impl) reverse_iterator; typedef BOOST_CONTAINER_IMPDEF(const_reverse_iterator_impl) const_reverse_iterator; typedef BOOST_CONTAINER_IMPDEF(impl_value_type) movable_value_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::sequence_type) sequence_type; public: ////////////////////////////////////////////// @@ -1243,6 +1246,39 @@ class flat_map std::pair equal_range(const key_type& x) const { return container_detail::force_copy >(m_flat_tree.lower_bound_range(x)); } + //! Effects: Extracts the internal sequence container. + //! + //! Complexity: Same as the move constructor of sequence_type, usually constant. + //! + //! Postcondition: this->empty() + //! + //! Throws: If secuence_type's move constructor throws + sequence_type extract_sequence() + { + return boost::move(container_detail::force(m_flat_tree.get_sequence_ref())); + } + + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. Erases non-unique elements. + //! + //! Complexity: Assuming O(1) move assignmet, O(NlogN) with N = seq.size() + //! + //! Throws: If the comparison or the move constructor throws + void adopt_sequence(BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_unique(boost::move(container_detail::force(seq))); } + + //! Requires: seq shall be ordered according to this->compare() + //! and shall contain unique elements. + //! + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignment, O(1) + //! + //! Throws: If the move constructor throws + void adopt_sequence(ordered_unique_range_t, BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_unique(ordered_unique_range_t(), boost::move(container_detail::force(seq))); } + //! Effects: Returns true if x and y are equal //! //! Complexity: Linear to the number of elements in the container. @@ -1401,6 +1437,7 @@ class flat_multimap ::pointer>::const_reverse_iterator const_reverse_iterator_impl; public: typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type; + typedef typename impl_tree_t::sequence_type impl_sequence_type; impl_tree_t &tree() { return m_flat_tree; } @@ -1437,6 +1474,7 @@ class flat_multimap typedef BOOST_CONTAINER_IMPDEF(reverse_iterator_impl) reverse_iterator; typedef BOOST_CONTAINER_IMPDEF(const_reverse_iterator_impl) const_reverse_iterator; typedef BOOST_CONTAINER_IMPDEF(impl_value_type) movable_value_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::sequence_type) sequence_type; ////////////////////////////////////////////// // @@ -2219,6 +2257,38 @@ class flat_multimap std::pair equal_range(const key_type& x) const { return container_detail::force_copy >(m_flat_tree.equal_range(x)); } + //! Effects: Extracts the internal sequence container. + //! + //! Complexity: Same as the move constructor of sequence_type, usually constant. + //! + //! Postcondition: this->empty() + //! + //! Throws: If secuence_type's move constructor throws + sequence_type extract_sequence() + { + return boost::move(container_detail::force(m_flat_tree.get_sequence_ref())); + } + + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignmet, O(NlogN) with N = seq.size() + //! + //! Throws: If the comparison or the move constructor throws + void adopt_sequence(BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_equal(boost::move(container_detail::force(seq))); } + + //! Requires: seq shall be ordered according to this->compare(). + //! + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignment, O(1) + //! + //! Throws: If the move constructor throws + void adopt_sequence(ordered_range_t, BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_equal(ordered_range_t(), boost::move(container_detail::force(seq))); } + //! Effects: Returns true if x and y are equal //! //! Complexity: Linear to the number of elements in the container. diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index fa27006..5dc6be5 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -114,6 +114,7 @@ class flat_set typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_iterator) const_iterator; typedef typename BOOST_CONTAINER_IMPDEF(base_t::reverse_iterator) reverse_iterator; typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_reverse_iterator) const_reverse_iterator; + typedef typename BOOST_CONTAINER_IMPDEF(base_t::sequence_type) sequence_type; public: ////////////////////////////////////////////// @@ -844,8 +845,38 @@ class flat_set //! Complexity: Constant. friend void swap(flat_set& x, flat_set& y); + //! Effects: Extracts the internal sequence container. + //! + //! Complexity: Same as the move constructor of sequence_type, usually constant. + //! + //! Postcondition: this->empty() + //! + //! Throws: If secuence_type's move constructor throws + sequence_type extract_sequence(); + #endif //#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. Erases non-unique elements. + //! + //! Complexity: Assuming O(1) move assignmet, O(NlogN) with N = seq.size() + //! + //! Throws: If the comparison or the move constructor throws + void adopt_sequence(BOOST_RV_REF(sequence_type) seq) + { this->base_t::adopt_sequence_unique(boost::move(seq)); } + + //! Requires: seq shall be ordered according to this->compare() + //! and shall contain unique elements. + //! + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignment, O(1) + //! + //! Throws: If the move constructor throws + void adopt_sequence(ordered_unique_range_t, BOOST_RV_REF(sequence_type) seq) + { this->base_t::adopt_sequence_unique(ordered_unique_range_t(), boost::move(seq)); } + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: template @@ -939,6 +970,7 @@ class flat_multiset typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_iterator) const_iterator; typedef typename BOOST_CONTAINER_IMPDEF(base_t::reverse_iterator) reverse_iterator; typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_reverse_iterator) const_reverse_iterator; + typedef typename BOOST_CONTAINER_IMPDEF(base_t::sequence_type) sequence_type; //! @copydoc ::boost::container::flat_set::flat_set() explicit flat_multiset() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && @@ -1392,8 +1424,37 @@ class flat_multiset //! Complexity: Constant. friend void swap(flat_multiset& x, flat_multiset& y); + //! Effects: Extracts the internal sequence container. + //! + //! Complexity: Same as the move constructor of sequence_type, usually constant. + //! + //! Postcondition: this->empty() + //! + //! Throws: If secuence_type's move constructor throws + sequence_type extract_sequence(); + #endif //#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignmet, O(NlogN) with N = seq.size() + //! + //! Throws: If the comparison or the move constructor throws + void adopt_sequence(BOOST_RV_REF(sequence_type) seq) + { this->base_t::adopt_sequence_equal(boost::move(seq)); } + + //! Requires: seq shall be ordered according to this->compare() + //! + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignment, O(1) + //! + //! Throws: If the move constructor throws + void adopt_sequence(ordered_range_t, BOOST_RV_REF(sequence_type) seq) + { this->base_t::adopt_sequence_equal(ordered_range_t(), boost::move(seq)); } + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: template diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index bd2fb23..b2376dc 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -224,6 +224,116 @@ bool flat_tree_ordered_insertion_test() return true; } +template< class RandomIt > +void random_shuffle( RandomIt first, RandomIt last ) +{ + typedef typename boost::container::iterator_traits::difference_type difference_type; + difference_type n = last - first; + for (difference_type i = n-1; i > 0; --i) { + difference_type j = std::rand() % (i+1); + if(j != i) { + boost::adl_move_swap(first[i], first[j]); + } + } +} + +bool flat_tree_extract_adopt_test() +{ + using namespace boost::container; + const std::size_t NumElements = 100; + + //extract/adopt map + { + //Construction insertion + flat_map fmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_map fmap_copy(fmap); + flat_map::sequence_type seq(fmap.extract_sequence()); + if(!fmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmap_copy)) + return false; + + seq.insert(seq.end(), fmap_copy.begin(), fmap_copy.end()); + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fmap.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fmap, fmap_copy)) + return false; + } + + //extract/adopt map, ordered_unique_range + { + //Construction insertion + flat_map fmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_map fmap_copy(fmap); + flat_map::sequence_type seq(fmap.extract_sequence()); + if(!fmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmap_copy)) + return false; + + fmap.adopt_sequence(ordered_unique_range, boost::move(seq)); + if(!CheckEqualContainers(fmap, fmap_copy)) + return false; + } + + //extract/adopt multimap + { + //Construction insertion + flat_multimap fmmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmmap.emplace(static_cast(i), -static_cast(i)); + fmmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_multimap fmmap_copy(fmmap); + flat_multimap::sequence_type seq(fmmap.extract_sequence()); + if(!fmmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmmap_copy)) + return false; + + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fmmap.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fmmap, fmmap_copy)) + return false; + } + + //extract/adopt multimap, ordered_range + { + //Construction insertion + flat_multimap fmmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmmap.emplace(static_cast(i), -static_cast(i)); + fmmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_multimap fmmap_copy(fmmap); + flat_multimap::sequence_type seq(fmmap.extract_sequence()); + if(!fmmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmmap_copy)) + return false; + + fmmap.adopt_sequence(ordered_range, boost::move(seq)); + if(!CheckEqualContainers(fmmap, fmmap_copy)) + return false; + } + + return true; +} + }}} @@ -385,6 +495,13 @@ int main() return 1; } + //////////////////////////////////// + // Extract/Adopt test + //////////////////////////////////// + if(!flat_tree_extract_adopt_test()){ + return 1; + } + //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index b9e436f..74742ea 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -312,6 +312,116 @@ bool flat_tree_ordered_insertion_test() return true; } +template< class RandomIt > +void random_shuffle( RandomIt first, RandomIt last ) +{ + typedef typename boost::container::iterator_traits::difference_type difference_type; + difference_type n = last - first; + for (difference_type i = n-1; i > 0; --i) { + difference_type j = std::rand() % (i+1); + if(j != i) { + boost::adl_move_swap(first[i], first[j]); + } + } +} + +bool flat_tree_extract_adopt_test() +{ + using namespace boost::container; + const std::size_t NumElements = 100; + + //extract/adopt set + { + //Construction insertion + flat_set fset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fset.insert(static_cast(i)); + } + + flat_set fset_copy(fset); + flat_set::sequence_type seq(fset.extract_sequence()); + if(!fset.empty()) + return false; + if(!CheckEqualContainers(seq, fset_copy)) + return false; + + seq.insert(seq.end(), fset_copy.begin(), fset_copy.end()); + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fset.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fset, fset_copy)) + return false; + } + + //extract/adopt set, ordered_unique_range + { + //Construction insertion + flat_set fset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fset.insert(static_cast(i)); + } + + flat_set fset_copy(fset); + flat_set::sequence_type seq(fset.extract_sequence()); + if(!fset.empty()) + return false; + if(!CheckEqualContainers(seq, fset_copy)) + return false; + + fset.adopt_sequence(ordered_unique_range, boost::move(seq)); + if(!CheckEqualContainers(fset, fset_copy)) + return false; + } + + //extract/adopt multiset + { + //Construction insertion + flat_multiset fmset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmset.insert(static_cast(i)); + fmset.insert(static_cast(i)); + } + + flat_multiset fmset_copy(fmset); + flat_multiset::sequence_type seq(fmset.extract_sequence()); + if(!fmset.empty()) + return false; + if(!CheckEqualContainers(seq, fmset_copy)) + return false; + + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fmset.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fmset, fmset_copy)) + return false; + } + + //extract/adopt multiset, ordered_range + { + //Construction insertion + flat_multiset fmset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmset.insert(static_cast(i)); + fmset.insert(static_cast(i)); + } + + flat_multiset fmset_copy(fmset); + flat_multiset::sequence_type seq(fmset.extract_sequence()); + if(!fmset.empty()) + return false; + if(!CheckEqualContainers(seq, fmset_copy)) + return false; + + fmset.adopt_sequence(ordered_range, boost::move(seq)); + if(!CheckEqualContainers(fmset, fmset_copy)) + return false; + } + + return true; +} + }}} @@ -491,6 +601,13 @@ int main() return 1; } + //////////////////////////////////// + // Extract/Adopt test + //////////////////////////////////// + if(!flat_tree_extract_adopt_test()){ + return 1; + } + //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// From 903b568d13276274528501ad8f5c70d9bd27d8d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 6 Apr 2017 23:34:30 +0200 Subject: [PATCH 4/8] Split set/map tests as some compilers refuse to allocate too many sectios in the object file --- proj/vc7ide/container.sln | 8 +++ proj/vc7ide/tree_test.vcproj | 135 +++++++++++++++++++++++++++++++++++ test/map_test.cpp | 57 +-------------- test/set_test.cpp | 55 +------------- test/tree_test.cpp | 84 ++++++++++++++++++++++ 5 files changed, 233 insertions(+), 106 deletions(-) create mode 100644 proj/vc7ide/tree_test.vcproj create mode 100644 test/tree_test.cpp diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index daec7d5..c7f7a2b 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -311,6 +311,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string_view_compat_test", " ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tree_test", "tree_test.vcproj", "{5CE185C3-2609-4FA5-FE38-792BA0D3A606}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -629,6 +633,10 @@ Global {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.ActiveCfg = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.Build.0 = Release|Win32 + {5CE185C3-2609-4FA5-FE38-792BA0D3A606}.Debug.ActiveCfg = Debug|Win32 + {5CE185C3-2609-4FA5-FE38-792BA0D3A606}.Debug.Build.0 = Debug|Win32 + {5CE185C3-2609-4FA5-FE38-792BA0D3A606}.Release.ActiveCfg = Release|Win32 + {5CE185C3-2609-4FA5-FE38-792BA0D3A606}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/tree_test.vcproj b/proj/vc7ide/tree_test.vcproj new file mode 100644 index 0000000..6f80056 --- /dev/null +++ b/proj/vc7ide/tree_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/map_test.cpp b/test/map_test.cpp index 9d8839b..dcb96f3 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -51,36 +51,6 @@ template class multimap , std::less , std::allocator< pair_t > >; - -namespace container_detail { - -//Instantiate base class as previous instantiations don't instantiate inherited members -template class tree - < pair_t - , select1st - , std::less - , test::simple_allocator - , tree_assoc_defaults - >; - -template class tree - < pair_t - , select1st - , std::less - , std::allocator - , tree_assoc_defaults - >; - -template class tree - < pair_t - , select1st - , std::less - , adaptive_pool - , tree_assoc_defaults - >; - -} //container_detail { - }} //boost::container class recursive_map @@ -275,12 +245,10 @@ int test_map_variants() { typedef typename GetAllocatorMap::template apply::map_type MyMap; typedef typename GetAllocatorMap::template apply::map_type MyMoveMap; - typedef typename GetAllocatorMap::template apply::map_type MyCopyMoveMap; typedef typename GetAllocatorMap::template apply::map_type MyCopyMap; typedef typename GetAllocatorMap::template apply::multimap_type MyMultiMap; typedef typename GetAllocatorMap::template apply::multimap_type MyMoveMultiMap; - typedef typename GetAllocatorMap::template apply::multimap_type MyCopyMoveMultiMap; typedef typename GetAllocatorMap::template apply::multimap_type MyCopyMultiMap; typedef std::map MyStdMap; @@ -304,15 +272,6 @@ int test_map_variants() return 1; } - if (0 != test::map_test< - MyCopyMoveMap - ,MyStdMap - ,MyCopyMoveMultiMap - ,MyStdMultiMap>()){ - std::cout << "Error in map_test" << std::endl; - return 1; - } - if (0 != test::map_test< MyCopyMap ,MyStdMap @@ -483,29 +442,19 @@ int main () // typedef map< int*, int*, std::less, std::allocator< std::pair > , tree_assoc_options< optimize_size, tree_type >::type > rbmap_size_optimized_no; - typedef map< int*, int*, std::less, std::allocator< std::pair > - , tree_assoc_options< optimize_size, tree_type >::type > rbmap_size_optimized_yes; - BOOST_STATIC_ASSERT(sizeof(rbmap_size_optimized_yes) < sizeof(rbmap_size_optimized_no)); - typedef map< int*, int*, std::less, std::allocator< std::pair > - , tree_assoc_options< optimize_size, tree_type >::type > avlmap_size_optimized_no; typedef map< int*, int*, std::less, std::allocator< std::pair > , tree_assoc_options< optimize_size, tree_type >::type > avlmap_size_optimized_yes; - BOOST_STATIC_ASSERT(sizeof(avlmap_size_optimized_yes) < sizeof(avlmap_size_optimized_no)); // // multimap // - typedef multimap< int*, int*, std::less, std::allocator< std::pair > - , tree_assoc_options< optimize_size, tree_type >::type > rbmmap_size_optimized_no; typedef multimap< int*, int*, std::less, std::allocator< std::pair > , tree_assoc_options< optimize_size, tree_type >::type > rbmmap_size_optimized_yes; - BOOST_STATIC_ASSERT(sizeof(rbmmap_size_optimized_yes) < sizeof(rbmmap_size_optimized_no)); - typedef multimap< int*, int*, std::less, std::allocator< std::pair > , tree_assoc_options< optimize_size, tree_type >::type > avlmmap_size_optimized_no; - typedef multimap< int*, int*, std::less, std::allocator< std::pair > - , tree_assoc_options< optimize_size, tree_type >::type > avlmmap_size_optimized_yes; - BOOST_STATIC_ASSERT(sizeof(avlmmap_size_optimized_yes) < sizeof(avlmmap_size_optimized_no)); + BOOST_STATIC_ASSERT(sizeof(rbmmap_size_optimized_yes) < sizeof(rbmap_size_optimized_no)); + BOOST_STATIC_ASSERT(sizeof(avlmap_size_optimized_yes) < sizeof(avlmmap_size_optimized_no)); + return 0; } diff --git a/test/set_test.cpp b/test/set_test.cpp index b3b8309..f805b4f 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -53,35 +53,6 @@ template class multiset , adaptive_pool >; -namespace container_detail { - -//Instantiate base class as previous instantiations don't instantiate inherited members -template class tree - < test::movable_and_copyable_int - , identity - , std::less - , test::simple_allocator - , tree_assoc_defaults - >; - -template class tree - < test::movable_and_copyable_int - , identity - , std::less - , std::allocator - , tree_assoc_defaults - >; - -template class tree - < test::movable_and_copyable_int - , identity - , std::less - , adaptive_pool - , tree_assoc_defaults - >; - -} //container_detail { - }} //boost::container //Test recursive structures @@ -301,12 +272,10 @@ int test_set_variants() { typedef typename GetAllocatorSet::template apply::set_type MySet; typedef typename GetAllocatorSet::template apply::set_type MyMoveSet; - typedef typename GetAllocatorSet::template apply::set_type MyCopyMoveSet; typedef typename GetAllocatorSet::template apply::set_type MyCopySet; typedef typename GetAllocatorSet::template apply::multiset_type MyMultiSet; typedef typename GetAllocatorSet::template apply::multiset_type MyMoveMultiSet; - typedef typename GetAllocatorSet::template apply::multiset_type MyCopyMoveMultiSet; typedef typename GetAllocatorSet::template apply::multiset_type MyCopyMultiSet; typedef std::set MyStdSet; @@ -330,15 +299,6 @@ int test_set_variants() return 1; } - if (0 != test::set_test< - MyCopyMoveSet - ,MyStdSet - ,MyCopyMoveMultiSet - ,MyStdMultiSet>()){ - std::cout << "Error in set_test" << std::endl; - return 1; - } - if (0 != test::set_test< MyCopySet ,MyStdSet @@ -452,29 +412,20 @@ int main () // typedef set< int*, std::less, std::allocator , tree_assoc_options< optimize_size, tree_type >::type > rbset_size_optimized_no; - typedef set< int*, std::less, std::allocator - , tree_assoc_options< optimize_size, tree_type >::type > rbset_size_optimized_yes; - BOOST_STATIC_ASSERT(sizeof(rbset_size_optimized_yes) < sizeof(rbset_size_optimized_no)); - typedef set< int*, std::less, std::allocator - , tree_assoc_options< optimize_size, tree_type >::type > avlset_size_optimized_no; typedef set< int*, std::less, std::allocator , tree_assoc_options< optimize_size, tree_type >::type > avlset_size_optimized_yes; - BOOST_STATIC_ASSERT(sizeof(avlset_size_optimized_yes) < sizeof(avlset_size_optimized_no)); // // multiset // - typedef multiset< int*, std::less, std::allocator - , tree_assoc_options< optimize_size, tree_type >::type > rbmset_size_optimized_no; typedef multiset< int*, std::less, std::allocator , tree_assoc_options< optimize_size, tree_type >::type > rbmset_size_optimized_yes; - BOOST_STATIC_ASSERT(sizeof(rbmset_size_optimized_yes) < sizeof(rbmset_size_optimized_no)); typedef multiset< int*, std::less, std::allocator , tree_assoc_options< optimize_size, tree_type >::type > avlmset_size_optimized_no; - typedef multiset< int*, std::less, std::allocator - , tree_assoc_options< optimize_size, tree_type >::type > avlmset_size_optimized_yes; - BOOST_STATIC_ASSERT(sizeof(avlmset_size_optimized_yes) < sizeof(avlmset_size_optimized_no)); + + BOOST_STATIC_ASSERT(sizeof(rbmset_size_optimized_yes) < sizeof(rbset_size_optimized_no)); + BOOST_STATIC_ASSERT(sizeof(avlset_size_optimized_yes) < sizeof(avlmset_size_optimized_no)); //////////////////////////////////// // Iterator testing diff --git a/test/tree_test.cpp b/test/tree_test.cpp new file mode 100644 index 0000000..6d84cd1 --- /dev/null +++ b/test/tree_test.cpp @@ -0,0 +1,84 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include + +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" + +using namespace boost::container; + +typedef std::pair pair_t; + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors + +namespace container_detail { + +//Instantiate base class as previous instantiations don't instantiate inherited members +template class tree + < pair_t + , select1st + , std::less + , test::simple_allocator + , tree_assoc_defaults + >; + +template class tree + < pair_t + , select1st + , std::less + , std::allocator + , tree_assoc_defaults + >; + +template class tree + < pair_t + , select1st + , std::less + , adaptive_pool + , tree_assoc_defaults + >; + +//Instantiate base class as previous instantiations don't instantiate inherited members +template class tree + < test::movable_and_copyable_int + , identity + , std::less + , test::simple_allocator + , tree_assoc_defaults + >; + +template class tree + < test::movable_and_copyable_int + , identity + , std::less + , std::allocator + , tree_assoc_defaults + >; + +template class tree + < test::movable_and_copyable_int + , identity + , std::less + , adaptive_pool + , tree_assoc_defaults + >; + +} //container_detail { + +}} //boost::container + +int main () +{ + return 0; +} From a7e2bed8f1c7e238f0075a409b12b999f2264789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 6 Apr 2017 23:35:08 +0200 Subject: [PATCH 5/8] Use adaptive_sort for merge operations. --- include/boost/container/vector.hpp | 95 +++++------------------------- 1 file changed, 15 insertions(+), 80 deletions(-) diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 336d616..c52367a 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -54,6 +54,10 @@ #include #endif #include +// move/algo +#include +#include +#include // other #include #include @@ -2240,37 +2244,15 @@ class vector p = this->m_holder.allocation_command(allocate_new, new_size, new_cap, p); this->priv_merge_in_new_buffer(UniqueBool(), first, n, comp, p, new_cap); } - else if(!UniqueBool::value && free_c >= n){ - typedef container_detail::vector_merge_cursor inserter_t; - T* const pbeg = this->priv_raw_begin(); - return this->priv_insert_ordered_at(n, inserter_t(pbeg, pbeg + s, last, comp)); - } - else{ //UniqueBool::value == true and free_c >= n - std::size_t remaining = n; - static const std::size_t PosCount = 64u; - size_type positions[PosCount]; - size_type *indexes = 0; - while(remaining){ - //Query for room to store indexes in the remaining buffer - boost::uintptr_t const szt_align_mask = container_detail::alignment_of::value - 1; - boost::uintptr_t const addr = boost::uintptr_t(this->priv_raw_begin() + s + n); - boost::uintptr_t const capaddr = boost::uintptr_t(this->priv_raw_begin() + c); - boost::uintptr_t const aligned_addr = (addr + szt_align_mask) & ~szt_align_mask; - indexes = reinterpret_cast(aligned_addr); - std::size_t index_capacity = (aligned_addr >= capaddr) ? 0u : (capaddr - aligned_addr)/sizeof(size_type); - - //Capacity is constant, we're not going to change it - if(index_capacity < PosCount){ - indexes = positions; - index_capacity = PosCount; - } - if(index_capacity > remaining) - index_capacity = remaining; - BidirIt limit = first; - boost::container::iterator_advance(limit, index_capacity); - this->priv_insert_ordered_range(UniqueBool(), index_capacity, first, limit, indexes, comp); - first = limit; - remaining -= index_capacity; + else{ + T *raw_pos = container_detail::iterator_to_raw_pointer(this->insert(this->cend(), first, last)); + T *raw_beg = this->priv_raw_begin(); + T *raw_end = this->priv_raw_end(); + boost::movelib::adaptive_merge(raw_beg, raw_pos, raw_end, comp, raw_end, free_c - n); + if(UniqueBool::value){ + size_type const count = + static_cast(raw_end - boost::movelib::unique(raw_beg, raw_end, boost::movelib::negate(comp))); + this->priv_destroy_last_n(count); } } } @@ -2279,53 +2261,6 @@ class vector } } - template - void priv_insert_ordered_range - (UniqueBool, size_type const n, BidirIt first, BidirIt const last, size_type positions[], Compare comp) - { - //Linear: at most N + M -1 comparisons - //Log: MlogN - //Average - //Linear: N + M - 2 - //Log: MlogN - //N+M - 2 - //N - //(N+M)/2 < MlogN - //(N/M+1)/2 <= logN - //bool const linear = !s || !n || (s <= n) || ((s+n)/n/2 < logN); - size_type const s = this->size(); - size_type remaining = n; - T* const pbeg = this->priv_raw_begin(); - T* const pend = pbeg + s; - T* pcur = pbeg; - size_type *position = positions; - size_type added_in_middle = 0; - if(first != last && pcur != pend){ - while(1){ - //maintain stability moving external values only if they are strictly less - if(comp(*first, *pcur)) { - *position = static_cast(pcur - pbeg); - BOOST_ASSERT((position == positions) || (*(position-1) == size_type(-1)) || (*(position-1) <= *position)); - ++position; - ++added_in_middle; - --remaining; - if(++first == last) break; - } - else if(UniqueBool::value && !comp(*pcur, *first)){ - *position = size_type(-1); - ++position; - --remaining; - if(++first == last) break; - } - else{ - if(++pcur == pend) break; - } - } - } - this->insert_ordered_at(added_in_middle, position, first); - this->insert(this->cend(), remaining, first, last); - } - template void priv_merge_in_new_buffer (UniqueBool, FwdIt first, size_type n, Compare comp, pointer new_storage, size_type const new_cap) @@ -2926,10 +2861,10 @@ class vector } private: - T *priv_raw_begin() const + BOOST_CONTAINER_FORCEINLINE T *priv_raw_begin() const { return container_detail::to_raw_pointer(m_holder.start()); } - T* priv_raw_end() const + BOOST_CONTAINER_FORCEINLINE T* priv_raw_end() const { return this->priv_raw_begin() + this->m_holder.m_size; } template From 1d727753e2adf4d732b80b7b5a12d9d30f057b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 7 Apr 2017 16:07:00 +0200 Subject: [PATCH 6/8] Use directly boost::movelib::to_raw_pointer/iterator_to_raw_pointer --- include/boost/container/deque.hpp | 20 +++--- .../detail/adaptive_node_pool_impl.hpp | 16 ++--- .../container/detail/advanced_insert_int.hpp | 10 +-- .../boost/container/detail/copy_move_algo.hpp | 66 ++++++++--------- include/boost/container/detail/destroyers.hpp | 10 +-- include/boost/container/detail/flat_tree.hpp | 12 ++-- .../detail/iterator_to_raw_pointer.hpp | 29 +------- .../detail/multiallocation_chain.hpp | 6 +- .../container/detail/node_alloc_holder.hpp | 16 ++--- .../boost/container/detail/node_pool_impl.hpp | 4 +- include/boost/container/node_handle.hpp | 4 +- include/boost/container/small_vector.hpp | 4 +- include/boost/container/stable_vector.hpp | 6 +- include/boost/container/string.hpp | 70 +++++++++---------- include/boost/container/vector.hpp | 56 +++++++-------- 15 files changed, 152 insertions(+), 177 deletions(-) diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index 255cd93..b838f6e 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -31,11 +31,11 @@ #include #include #include -#include +#include #include #include #include -#include +#include #include // move #include @@ -1649,7 +1649,7 @@ class deque : protected deque_base if (this->members_.m_start.m_cur != this->members_.m_start.m_last - 1) { allocator_traits_type::destroy ( this->alloc() - , container_detail::to_raw_pointer(this->members_.m_start.m_cur) + , boost::movelib::to_raw_pointer(this->members_.m_start.m_cur) ); ++this->members_.m_start.m_cur; } @@ -1669,7 +1669,7 @@ class deque : protected deque_base --this->members_.m_finish.m_cur; allocator_traits_type::destroy ( this->alloc() - , container_detail::to_raw_pointer(this->members_.m_finish.m_cur) + , boost::movelib::to_raw_pointer(this->members_.m_finish.m_cur) ); } else @@ -1916,7 +1916,7 @@ class deque : protected deque_base T *priv_push_back_simple_pos() const { - return container_detail::to_raw_pointer(this->members_.m_finish.m_cur); + return boost::movelib::to_raw_pointer(this->members_.m_finish.m_cur); } void priv_push_back_simple_commit() @@ -1931,7 +1931,7 @@ class deque : protected deque_base } T *priv_push_front_simple_pos() const - { return container_detail::to_raw_pointer(this->members_.m_start.m_cur) - 1; } + { return boost::movelib::to_raw_pointer(this->members_.m_start.m_cur) - 1; } void priv_push_front_simple_commit() { --this->members_.m_start.m_cur; } @@ -1940,7 +1940,7 @@ class deque : protected deque_base { if(!Base::traits_t::trivial_dctr){ for(;p != p2; ++p){ - allocator_traits_type::destroy(this->alloc(), container_detail::iterator_to_raw_pointer(p)); + allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); } } } @@ -1949,7 +1949,7 @@ class deque : protected deque_base { if(!Base::traits_t::trivial_dctr){ for(;p != p2; ++p){ - allocator_traits_type::destroy(this->alloc(), container_detail::iterator_to_raw_pointer(p)); + allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); } } } @@ -2133,7 +2133,7 @@ class deque : protected deque_base this->members_.m_finish.m_cur = this->members_.m_finish.m_last - 1; allocator_traits_type::destroy ( this->alloc() - , container_detail::to_raw_pointer(this->members_.m_finish.m_cur) + , boost::movelib::to_raw_pointer(this->members_.m_finish.m_cur) ); } @@ -2145,7 +2145,7 @@ class deque : protected deque_base { allocator_traits_type::destroy ( this->alloc() - , container_detail::to_raw_pointer(this->members_.m_start.m_cur) + , boost::movelib::to_raw_pointer(this->members_.m_start.m_cur) ); this->priv_deallocate_node(this->members_.m_start.m_first); this->members_.m_start.priv_set_node(this->members_.m_start.m_node + 1); diff --git a/include/boost/container/detail/adaptive_node_pool_impl.hpp b/include/boost/container/detail/adaptive_node_pool_impl.hpp index 24c81dd..54db19d 100644 --- a/include/boost/container/detail/adaptive_node_pool_impl.hpp +++ b/include/boost/container/detail/adaptive_node_pool_impl.hpp @@ -28,10 +28,10 @@ // container/detail #include #include -#include +#include #include #include -#include +#include #include // intrusive #include @@ -378,7 +378,7 @@ class private_adaptive_node_pool_impl //!Returns the segment manager. Never throws segment_manager_base_type* get_segment_manager_base()const - { return container_detail::to_raw_pointer(mp_segment_mngr_base); } + { return boost::movelib::to_raw_pointer(mp_segment_mngr_base); } //!Allocates array of count elements. Can throw void *allocate_node() @@ -390,7 +390,7 @@ class private_adaptive_node_pool_impl free_nodes_t &free_nodes = m_block_container.begin()->free_nodes; BOOST_ASSERT(!free_nodes.empty()); const size_type free_nodes_count = free_nodes.size(); - void *first_node = container_detail::to_raw_pointer(free_nodes.pop_front()); + void *first_node = boost::movelib::to_raw_pointer(free_nodes.pop_front()); if(free_nodes.empty()){ block_container_traits_t::erase_first(m_block_container); } @@ -401,7 +401,7 @@ class private_adaptive_node_pool_impl else{ multiallocation_chain chain; this->priv_append_from_new_blocks(1, chain, IsAlignOnly()); - return container_detail::to_raw_pointer(chain.pop_front()); + return boost::movelib::to_raw_pointer(chain.pop_front()); } } @@ -492,7 +492,7 @@ class private_adaptive_node_pool_impl free_nodes_iterator itf(nodes.begin()), itbf(itbb); size_type splice_node_count = size_type(-1); while(itf != ite){ - void *pElem = container_detail::to_raw_pointer(container_detail::iterator_to_raw_pointer(itf)); + void *pElem = boost::movelib::to_raw_pointer(boost::movelib::iterator_to_raw_pointer(itf)); block_info_t &block_info = *this->priv_block_from_node(pElem); BOOST_ASSERT(block_info.free_nodes.size() < m_real_num_node); ++splice_node_count; @@ -631,7 +631,7 @@ class private_adaptive_node_pool_impl BOOST_ASSERT(to_deallocate->free_nodes.size() == mp_impl->m_real_num_node); BOOST_ASSERT(0 == to_deallocate->hdr_offset); hdr_offset_holder *hdr_off_holder = - mp_impl->priv_first_subblock_from_block(container_detail::to_raw_pointer(to_deallocate)); + mp_impl->priv_first_subblock_from_block(boost::movelib::to_raw_pointer(to_deallocate)); m_chain.push_back(hdr_off_holder); } @@ -763,7 +763,7 @@ class private_adaptive_node_pool_impl //First add all possible nodes to the chain const size_type left = total_elements - chain.size(); const size_type max_chain = (num_node < left) ? num_node : left; - mem_address = static_cast(container_detail::to_raw_pointer + mem_address = static_cast(boost::movelib::to_raw_pointer (chain.incorporate_after(chain.last(), void_pointer(mem_address), m_real_node_size, max_chain))); //Now store remaining nodes in the free list if(const size_type max_free = num_node - max_chain){ diff --git a/include/boost/container/detail/advanced_insert_int.hpp b/include/boost/container/detail/advanced_insert_int.hpp index 1050857..20adb52 100644 --- a/include/boost/container/detail/advanced_insert_int.hpp +++ b/include/boost/container/detail/advanced_insert_int.hpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include #endif @@ -157,7 +157,7 @@ struct insert_copy_proxy void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; - alloc_traits::construct( a, iterator_to_raw_pointer(p), v_); + alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), v_); } void copy_n_and_update(Allocator &, Iterator p, size_type n) const @@ -184,7 +184,7 @@ struct insert_move_proxy void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; - alloc_traits::construct( a, iterator_to_raw_pointer(p), ::boost::move(v_) ); + alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), ::boost::move(v_) ); } void copy_n_and_update(Allocator &, Iterator p, size_type n) const @@ -240,7 +240,7 @@ struct insert_nonmovable_emplace_proxy void priv_uninitialized_copy_some_and_update(Allocator &a, const index_tuple&, Iterator p, size_type n) { BOOST_ASSERT(n == 1); (void)n; - alloc_traits::construct( a, iterator_to_raw_pointer(p), ::boost::forward(get(this->args_))... ); + alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), ::boost::forward(get(this->args_))... ); } protected: @@ -354,7 +354,7 @@ struct insert_nonmovable_emplace_proxy##N\ void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n)\ {\ BOOST_ASSERT(n == 1); (void)n;\ - alloc_traits::construct(a, iterator_to_raw_pointer(p) BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\ + alloc_traits::construct(a, boost::movelib::iterator_to_raw_pointer(p) BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\ }\ \ void copy_n_and_update(Allocator &, Iterator, size_type)\ diff --git a/include/boost/container/detail/copy_move_algo.hpp b/include/boost/container/detail/copy_move_algo.hpp index dda311a..968f4ac 100644 --- a/include/boost/container/detail/copy_move_algo.hpp +++ b/include/boost/container/detail/copy_move_algo.hpp @@ -22,7 +22,7 @@ #include // container/detail #include -#include +#include #include #include #include @@ -178,7 +178,7 @@ inline F memmove(I f, I l, F r) BOOST_NOEXCEPT_OR_NOTHROW typedef typename boost::container::iterator_traits::value_type value_type; typename boost::container::iterator_traits::difference_type n = boost::container::iterator_distance(f, l); if(n){ - std::memmove((iterator_to_raw_pointer)(r), (iterator_to_raw_pointer)(f), sizeof(value_type)*n); + std::memmove(boost::movelib::iterator_to_raw_pointer(r), boost::movelib::iterator_to_raw_pointer(f), sizeof(value_type)*n); boost::container::iterator_advance(r, n); } return r; @@ -192,7 +192,7 @@ F memmove_n(I f, U n, F r) BOOST_NOEXCEPT_OR_NOTHROW { typedef typename boost::container::iterator_traits::value_type value_type; if(n){ - std::memmove((iterator_to_raw_pointer)(r), (iterator_to_raw_pointer)(f), sizeof(value_type)*n); + std::memmove(boost::movelib::iterator_to_raw_pointer(r), boost::movelib::iterator_to_raw_pointer(f), sizeof(value_type)*n); boost::container::iterator_advance(r, n); } return r; @@ -206,7 +206,7 @@ I memmove_n_source(I f, U n, F r) BOOST_NOEXCEPT_OR_NOTHROW { if(n){ typedef typename boost::container::iterator_traits::value_type value_type; - std::memmove((iterator_to_raw_pointer)(r), (iterator_to_raw_pointer)(f), sizeof(value_type)*n); + std::memmove(boost::movelib::iterator_to_raw_pointer(r), boost::movelib::iterator_to_raw_pointer(f), sizeof(value_type)*n); boost::container::iterator_advance(f, n); } return f; @@ -220,7 +220,7 @@ I memmove_n_source_dest(I f, U n, F &r) BOOST_NOEXCEPT_OR_NOTHROW { typedef typename boost::container::iterator_traits::value_type value_type; if(n){ - std::memmove((iterator_to_raw_pointer)(r), (iterator_to_raw_pointer)(f), sizeof(value_type)*n); + std::memmove(boost::movelib::iterator_to_raw_pointer(r), boost::movelib::iterator_to_raw_pointer(f), sizeof(value_type)*n); boost::container::iterator_advance(f, n); boost::container::iterator_advance(r, n); } @@ -295,13 +295,13 @@ inline typename container_detail::disable_if_memtransfer_copy_constructible::construct(a, container_detail::iterator_to_raw_pointer(r), boost::move(*f)); + allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), boost::move(*f)); ++f; ++r; } } BOOST_CATCH(...){ for (; back != r; ++back){ - allocator_traits::destroy(a, container_detail::iterator_to_raw_pointer(back)); + allocator_traits::destroy(a, boost::movelib::iterator_to_raw_pointer(back)); } BOOST_RETHROW; } @@ -340,13 +340,13 @@ inline typename container_detail::disable_if_memtransfer_copy_constructible::construct(a, container_detail::iterator_to_raw_pointer(r), boost::move(*f)); + allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), boost::move(*f)); ++f; ++r; } } BOOST_CATCH(...){ for (; back != r; ++back){ - allocator_traits::destroy(a, container_detail::iterator_to_raw_pointer(back)); + allocator_traits::destroy(a, boost::movelib::iterator_to_raw_pointer(back)); } BOOST_RETHROW; } @@ -385,13 +385,13 @@ inline typename container_detail::disable_if_memtransfer_copy_constructible::construct(a, container_detail::iterator_to_raw_pointer(r), boost::move(*f)); + allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), boost::move(*f)); ++f; ++r; } } BOOST_CATCH(...){ for (; back != r; ++back){ - allocator_traits::destroy(a, container_detail::iterator_to_raw_pointer(back)); + allocator_traits::destroy(a, boost::movelib::iterator_to_raw_pointer(back)); } BOOST_RETHROW; } @@ -430,13 +430,13 @@ inline typename container_detail::disable_if_memtransfer_copy_constructible::construct(a, container_detail::iterator_to_raw_pointer(r), *f); + allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), *f); ++f; ++r; } } BOOST_CATCH(...){ for (; back != r; ++back){ - allocator_traits::destroy(a, container_detail::iterator_to_raw_pointer(back)); + allocator_traits::destroy(a, boost::movelib::iterator_to_raw_pointer(back)); } BOOST_RETHROW; } @@ -475,13 +475,13 @@ inline typename container_detail::disable_if_memtransfer_copy_constructible::construct(a, container_detail::iterator_to_raw_pointer(r), *f); + allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), *f); ++f; ++r; } } BOOST_CATCH(...){ for (; back != r; ++back){ - allocator_traits::destroy(a, container_detail::iterator_to_raw_pointer(back)); + allocator_traits::destroy(a, boost::movelib::iterator_to_raw_pointer(back)); } BOOST_RETHROW; } @@ -520,13 +520,13 @@ inline typename container_detail::disable_if_memtransfer_copy_constructible::destroy(a, container_detail::iterator_to_raw_pointer(back)); + allocator_traits::destroy(a, boost::movelib::iterator_to_raw_pointer(back)); } BOOST_RETHROW; } @@ -564,13 +564,13 @@ inline typename container_detail::disable_if_memzero_initializable::type F back = r; BOOST_TRY{ while (n--) { - allocator_traits::construct(a, container_detail::iterator_to_raw_pointer(r)); + allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r)); ++r; } } BOOST_CATCH(...){ for (; back != r; ++back){ - allocator_traits::destroy(a, container_detail::iterator_to_raw_pointer(back)); + allocator_traits::destroy(a, boost::movelib::iterator_to_raw_pointer(back)); } BOOST_RETHROW; } @@ -585,7 +585,7 @@ inline typename container_detail::enable_if_memzero_initializable::type uninitialized_value_init_alloc_n(Allocator &, typename boost::container::allocator_traits::size_type n, F r) { typedef typename boost::container::iterator_traits::value_type value_type; - std::memset((void*)container_detail::iterator_to_raw_pointer(r), 0, sizeof(value_type)*n); + std::memset((void*)boost::movelib::iterator_to_raw_pointer(r), 0, sizeof(value_type)*n); boost::container::iterator_advance(r, n); return r; } @@ -611,13 +611,13 @@ inline F uninitialized_default_init_alloc_n(Allocator &a, typename boost::contai F back = r; BOOST_TRY{ while (n--) { - allocator_traits::construct(a, container_detail::iterator_to_raw_pointer(r), default_init); + allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), default_init); ++r; } } BOOST_CATCH(...){ for (; back != r; ++back){ - allocator_traits::destroy(a, container_detail::iterator_to_raw_pointer(back)); + allocator_traits::destroy(a, boost::movelib::iterator_to_raw_pointer(back)); } BOOST_RETHROW; } @@ -647,13 +647,13 @@ inline void uninitialized_fill_alloc(Allocator &a, F f, F l, const T &t) F back = f; BOOST_TRY{ while (f != l) { - allocator_traits::construct(a, container_detail::iterator_to_raw_pointer(f), t); + allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(f), t); ++f; } } BOOST_CATCH(...){ for (; back != l; ++back){ - allocator_traits::destroy(a, container_detail::iterator_to_raw_pointer(back)); + allocator_traits::destroy(a, boost::movelib::iterator_to_raw_pointer(back)); } BOOST_RETHROW; } @@ -683,13 +683,13 @@ inline F uninitialized_fill_alloc_n(Allocator &a, const T &v, typename boost::co F back = r; BOOST_TRY{ while (n--) { - allocator_traits::construct(a, container_detail::iterator_to_raw_pointer(r), v); + allocator_traits::construct(a, boost::movelib::iterator_to_raw_pointer(r), v); ++r; } } BOOST_CATCH(...){ for (; back != r; ++back){ - allocator_traits::destroy(a, container_detail::iterator_to_raw_pointer(back)); + allocator_traits::destroy(a, boost::movelib::iterator_to_raw_pointer(back)); } BOOST_RETHROW; } @@ -890,7 +890,7 @@ inline typename container_detail::enable_if_memtransfer_copy_assignable typedef typename boost::container::iterator_traits::value_type value_type; const typename boost::container::iterator_traits::difference_type n = boost::container::iterator_distance(f, l); r -= n; - std::memmove((container_detail::iterator_to_raw_pointer)(r), (container_detail::iterator_to_raw_pointer)(f), sizeof(value_type)*n); + std::memmove((boost::movelib::iterator_to_raw_pointer)(r), (boost::movelib::iterator_to_raw_pointer)(f), sizeof(value_type)*n); return r; } @@ -964,7 +964,7 @@ inline typename container_detail::disable_if_trivially_destructible::ty destroy_alloc_n(Allocator &a, I f, U n) { while(n--){ - allocator_traits::destroy(a, container_detail::iterator_to_raw_pointer(f)); + allocator_traits::destroy(a, boost::movelib::iterator_to_raw_pointer(f)); ++f; } } @@ -1021,9 +1021,9 @@ inline typename container_detail::enable_if_c storage_type storage; const std::size_t n_i_bytes = sizeof(value_type)*n_i; - void *const large_ptr = static_cast(container_detail::iterator_to_raw_pointer(large_range_f)); - void *const short_ptr = static_cast(container_detail::iterator_to_raw_pointer(short_range_f)); - void *const stora_ptr = static_cast(container_detail::iterator_to_raw_pointer(storage)); + void *const large_ptr = static_cast(boost::movelib::iterator_to_raw_pointer(large_range_f)); + void *const short_ptr = static_cast(boost::movelib::iterator_to_raw_pointer(short_range_f)); + void *const stora_ptr = static_cast(boost::movelib::iterator_to_raw_pointer(storage)); std::memcpy(stora_ptr, large_ptr, n_i_bytes); std::memcpy(large_ptr, short_ptr, n_i_bytes); std::memcpy(short_ptr, stora_ptr, n_i_bytes); @@ -1052,8 +1052,8 @@ inline typename container_detail::enable_if_c const std::size_t sizeof_storage = sizeof(storage); std::size_t n_i_bytes = sizeof(value_type)*n_i; - char *large_ptr = static_cast(static_cast(container_detail::iterator_to_raw_pointer(large_range_f))); - char *short_ptr = static_cast(static_cast(container_detail::iterator_to_raw_pointer(short_range_f))); + char *large_ptr = static_cast(static_cast(boost::movelib::iterator_to_raw_pointer(large_range_f))); + char *short_ptr = static_cast(static_cast(boost::movelib::iterator_to_raw_pointer(short_range_f))); char *stora_ptr = static_cast(static_cast(&storage)); std::size_t szt_times = n_i_bytes/sizeof_storage; diff --git a/include/boost/container/detail/destroyers.hpp b/include/boost/container/detail/destroyers.hpp index 52b44c0..b110561 100644 --- a/include/boost/container/detail/destroyers.hpp +++ b/include/boost/container/detail/destroyers.hpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include namespace boost { @@ -152,7 +152,7 @@ struct scoped_destroy_deallocator ~scoped_destroy_deallocator() { if(m_ptr){ - AllocTraits::destroy(m_alloc, container_detail::to_raw_pointer(m_ptr)); + AllocTraits::destroy(m_alloc, boost::movelib::to_raw_pointer(m_ptr)); priv_deallocate(m_ptr, alloc_version()); } } @@ -202,7 +202,7 @@ struct scoped_destructor_n ~scoped_destructor_n() { if(!m_p) return; - value_type *raw_ptr = container_detail::to_raw_pointer(m_p); + value_type *raw_ptr = boost::movelib::to_raw_pointer(m_p); while(m_n--){ AllocTraits::destroy(m_a, raw_ptr++); } @@ -317,7 +317,7 @@ class allocator_destroyer void operator()(const pointer &p) { - AllocTraits::destroy(a_, container_detail::to_raw_pointer(p)); + AllocTraits::destroy(a_, boost::movelib::to_raw_pointer(p)); this->priv_deallocate(p, alloc_version()); } }; @@ -339,7 +339,7 @@ class allocator_destroyer_and_chain_builder void operator()(const typename Allocator::pointer &p) { - allocator_traits::destroy(a_, container_detail::to_raw_pointer(p)); + allocator_traits::destroy(a_, boost::movelib::to_raw_pointer(p)); c_.push_back(p); } }; diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 16d2991..89ff735 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -859,10 +859,10 @@ class flat_tree { sequence_type &tseq = m_data.m_seq; boost::movelib::adaptive_sort - ( container_detail::iterator_to_raw_pointer(seq.begin()) - , container_detail::iterator_to_raw_pointer(seq.end()) + ( boost::movelib::iterator_to_raw_pointer(seq.begin()) + , boost::movelib::iterator_to_raw_pointer(seq.end()) , this->priv_value_comp() - , container_detail::iterator_to_raw_pointer(tseq.begin() + tseq.size()) + , boost::movelib::iterator_to_raw_pointer(tseq.begin() + tseq.size()) , tseq.capacity() - tseq.size()); tseq = boost::move(seq); } @@ -878,10 +878,10 @@ class flat_tree { sequence_type &tseq = m_data.m_seq; boost::movelib::adaptive_sort - ( container_detail::iterator_to_raw_pointer(seq.begin()) - , container_detail::iterator_to_raw_pointer(seq.end()) + ( boost::movelib::iterator_to_raw_pointer(seq.begin()) + , boost::movelib::iterator_to_raw_pointer(seq.end()) , this->priv_value_comp() - , container_detail::iterator_to_raw_pointer(tseq.begin() + tseq.size()) + , boost::movelib::iterator_to_raw_pointer(tseq.begin() + tseq.size()) , tseq.capacity() - tseq.size()); seq.erase( boost::movelib::unique (seq.begin(), seq.end(), boost::movelib::negate(this->m_data.get_comp())) diff --git a/include/boost/container/detail/iterator_to_raw_pointer.hpp b/include/boost/container/detail/iterator_to_raw_pointer.hpp index 83736d8..8c7c880 100644 --- a/include/boost/container/detail/iterator_to_raw_pointer.hpp +++ b/include/boost/container/detail/iterator_to_raw_pointer.hpp @@ -18,38 +18,13 @@ # pragma once #endif -#include -#include -#include +#include namespace boost { namespace container { namespace container_detail { -template -inline T* iterator_to_pointer(T* i) -{ return i; } - -template -inline typename boost::container::iterator_traits::pointer - iterator_to_pointer(const Iterator &i) -{ return i.operator->(); } - -template -struct iterator_to_element_ptr -{ - typedef typename boost::container::iterator_traits::pointer pointer; - typedef typename boost::intrusive::pointer_traits::element_type element_type; - typedef element_type* type; -}; - -template -inline typename iterator_to_element_ptr::type - iterator_to_raw_pointer(const Iterator &i) -{ - return ::boost::intrusive::detail::to_raw_pointer - ( ::boost::container::container_detail::iterator_to_pointer(i) ); -} +using ::boost::movelib::iterator_to_raw_pointer; } //namespace container_detail { } //namespace container { diff --git a/include/boost/container/detail/multiallocation_chain.hpp b/include/boost/container/detail/multiallocation_chain.hpp index 32f87c8..bce1b86 100644 --- a/include/boost/container/detail/multiallocation_chain.hpp +++ b/include/boost/container/detail/multiallocation_chain.hpp @@ -24,7 +24,7 @@ // container #include // container/detail -#include +#include #include #include // intrusive @@ -63,7 +63,7 @@ class basic_multiallocation_chain pointer_traits node_ptr_traits; static node & to_node(const VoidPointer &p) - { return *static_cast(static_cast(container_detail::to_raw_pointer(p))); } + { return *static_cast(static_cast(boost::movelib::to_raw_pointer(p))); } static VoidPointer from_node(node &n) { return node_ptr_traits::pointer_to(n); } @@ -152,7 +152,7 @@ class basic_multiallocation_chain char_ptr prev_elem = elem; elem += unit_bytes; for(size_type i = 0; i != num_units-1; ++i, elem += unit_bytes){ - ::new (container_detail::to_raw_pointer(prev_elem)) void_pointer(elem); + ::new (boost::movelib::to_raw_pointer(prev_elem)) void_pointer(elem); prev_elem = elem; } slist_impl_.incorporate_after(after_this, to_node_ptr(b), to_node_ptr(prev_elem), num_units); diff --git a/include/boost/container/detail/node_alloc_holder.hpp b/include/boost/container/detail/node_alloc_holder.hpp index 7ef5d28..0341ce1 100644 --- a/include/boost/container/detail/node_alloc_holder.hpp +++ b/include/boost/container/detail/node_alloc_holder.hpp @@ -30,10 +30,10 @@ #include #include #include -#include +#include #include #include -#include +#include #include #include // intrusive @@ -171,7 +171,7 @@ struct node_alloc_holder node_deallocator.release(); //This does not throw typedef typename Node::hook_type hook_type; - ::new(static_cast(container_detail::to_raw_pointer(p)), boost_container_new_t()) hook_type; + ::new(static_cast(boost::movelib::to_raw_pointer(p)), boost_container_new_t()) hook_type; return (p); } @@ -189,7 +189,7 @@ struct node_alloc_holder BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ node_deallocator.release();\ typedef typename Node::hook_type hook_type;\ - ::new(static_cast(container_detail::to_raw_pointer(p)), boost_container_new_t()) hook_type;\ + ::new(static_cast(boost::movelib::to_raw_pointer(p)), boost_container_new_t()) hook_type;\ return (p);\ }\ // @@ -207,7 +207,7 @@ struct node_alloc_holder node_deallocator.release(); //This does not throw typedef typename Node::hook_type hook_type; - ::new(static_cast(container_detail::to_raw_pointer(p)), boost_container_new_t()) hook_type; + ::new(static_cast(boost::movelib::to_raw_pointer(p)), boost_container_new_t()) hook_type; return (p); } @@ -230,13 +230,13 @@ struct node_alloc_holder node_deallocator.release(); //This does not throw typedef typename Node::hook_type hook_type; - ::new(static_cast(container_detail::to_raw_pointer(p)), boost_container_new_t()) hook_type; + ::new(static_cast(boost::movelib::to_raw_pointer(p)), boost_container_new_t()) hook_type; return (p); } void destroy_node(const NodePtr &nodep) { - allocator_traits::destroy(this->node_alloc(), container_detail::to_raw_pointer(nodep)); + allocator_traits::destroy(this->node_alloc(), boost::movelib::to_raw_pointer(nodep)); this->deallocate_one(nodep); } @@ -266,7 +266,7 @@ struct node_alloc_holder Deallocator node_deallocator(NodePtr(), nalloc); container_detail::scoped_destructor sdestructor(nalloc, 0); while(n--){ - p = container_detail::iterator_to_raw_pointer(itbeg); + p = boost::movelib::iterator_to_raw_pointer(itbeg); node_deallocator.set(p); ++itbeg; //This can throw diff --git a/include/boost/container/detail/node_pool_impl.hpp b/include/boost/container/detail/node_pool_impl.hpp index 4febf19..024bf30 100644 --- a/include/boost/container/detail/node_pool_impl.hpp +++ b/include/boost/container/detail/node_pool_impl.hpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -92,7 +92,7 @@ class private_node_pool_impl //!Returns the segment manager. Never throws segment_manager_base_type* get_segment_manager_base()const - { return container_detail::to_raw_pointer(mp_segment_mngr_base); } + { return boost::movelib::to_raw_pointer(mp_segment_mngr_base); } void *allocate_node() { return this->priv_alloc_node(); } diff --git a/include/boost/container/node_handle.hpp b/include/boost/container/node_handle.hpp index 3a969b7..594a09c 100644 --- a/include/boost/container/node_handle.hpp +++ b/include/boost/container/node_handle.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -123,7 +123,7 @@ class node_handle void destroy_deallocate_node() { - nator_traits::destroy(this->node_alloc(), container_detail::to_raw_pointer(m_ptr)); + nator_traits::destroy(this->node_alloc(), boost::movelib::to_raw_pointer(m_ptr)); nator_traits::deallocate(this->node_alloc(), m_ptr, 1u); } diff --git a/include/boost/container/small_vector.hpp b/include/boost/container/small_vector.hpp index 1444624..804740c 100644 --- a/include/boost/container/small_vector.hpp +++ b/include/boost/container/small_vector.hpp @@ -387,8 +387,8 @@ class small_vector_base this->steal_resources(x); } else{ - this->assign( boost::make_move_iterator(container_detail::iterator_to_raw_pointer(x.begin())) - , boost::make_move_iterator(container_detail::iterator_to_raw_pointer(x.end ())) + 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 ())) ); } } diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index 5d6dc0f..cf156e0 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include // intrusive #include @@ -1975,7 +1975,7 @@ class stable_vector , container_detail::addressof(p->value) , it); //This does not throw - ::new(static_cast(container_detail::to_raw_pointer(p)), boost_container_new_t()) + ::new(static_cast(boost::movelib::to_raw_pointer(p)), boost_container_new_t()) node_base_type(index_traits_type::ptr_to_node_base_ptr(*up_index)); } @@ -1988,7 +1988,7 @@ class stable_vector , container_detail::addressof(p->value) , ::boost::forward(value_convertible)); //This does not throw - ::new(static_cast(container_detail::to_raw_pointer(p)), boost_container_new_t()) node_base_type; + ::new(static_cast(boost::movelib::to_raw_pointer(p)), boost_container_new_t()) node_base_type; } void priv_swap_members(stable_vector &x) diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index 7b780fd..b49811f 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include @@ -308,14 +308,14 @@ class basic_string_base { allocator_traits_type::construct ( this->alloc() - , container_detail::to_raw_pointer(p) + , boost::movelib::to_raw_pointer(p) , value ); } void destroy(pointer p, size_type n) { - value_type *raw_p = container_detail::to_raw_pointer(p); + value_type *raw_p = boost::movelib::to_raw_pointer(p); for(; n--; ++raw_p){ allocator_traits_type::destroy( this->alloc(), raw_p); } @@ -325,7 +325,7 @@ class basic_string_base { allocator_traits_type::destroy ( this->alloc() - , container_detail::to_raw_pointer(p) + , boost::movelib::to_raw_pointer(p) ); } @@ -1158,8 +1158,8 @@ class basic_string size_type long_storage = this->priv_long_storage(); size_type long_size = this->priv_long_size(); //Shrink from allocated buffer to the internal one, including trailing null - Traits::copy( container_detail::to_raw_pointer(this->priv_short_addr()) - , container_detail::to_raw_pointer(long_addr) + Traits::copy( boost::movelib::to_raw_pointer(this->priv_short_addr()) + , boost::movelib::to_raw_pointer(long_addr) , long_size+1); this->is_short(true); this->alloc().deallocate(long_addr, long_storage); @@ -1492,7 +1492,7 @@ class basic_string { size_type n = static_cast(last - first); this->reserve(n); - CharT* ptr = container_detail::to_raw_pointer(this->priv_addr()); + CharT* ptr = boost::movelib::to_raw_pointer(this->priv_addr()); Traits::copy(ptr, first, n); this->priv_construct_null(ptr + n); this->priv_size(n); @@ -1511,7 +1511,7 @@ class basic_string { size_type cur = 0; const pointer addr = this->priv_addr(); - CharT *ptr = container_detail::to_raw_pointer(addr); + CharT *ptr = boost::movelib::to_raw_pointer(addr); const size_type old_size = this->priv_size(); while (first != last && cur != old_size) { Traits::assign(*ptr, *first); @@ -1570,7 +1570,7 @@ class basic_string size_type len = container_detail::min_value(n, str_size - pos2); if (sz > this->max_size() - len) throw_length_error("basic_string::insert max_size() exceeded"); - const CharT *beg_ptr = container_detail::to_raw_pointer(s.begin()) + pos2; + const CharT *beg_ptr = boost::movelib::to_raw_pointer(s.begin()) + pos2; const CharT *end_ptr = beg_ptr + len; this->insert(this->priv_addr() + pos1, beg_ptr, end_ptr); return *this; @@ -1730,10 +1730,10 @@ class basic_string pointer_past_last, pointer_past_last); this->priv_size(old_size+n); - Traits::move(const_cast(container_detail::to_raw_pointer(p + n)), - container_detail::to_raw_pointer(p), + Traits::move(const_cast(boost::movelib::to_raw_pointer(p + n)), + boost::movelib::to_raw_pointer(p), (elems_after - n) + 1); - this->priv_copy(first, last, const_cast(container_detail::to_raw_pointer(p))); + this->priv_copy(first, last, const_cast(boost::movelib::to_raw_pointer(p))); } else { ForwardIter mid = first; @@ -1746,7 +1746,7 @@ class basic_string (p, const_iterator(old_start + old_length + 1), old_start + newer_size); this->priv_size(newer_size + elems_after); - this->priv_copy(first, mid, const_cast(container_detail::to_raw_pointer(p))); + this->priv_copy(first, mid, const_cast(boost::movelib::to_raw_pointer(p))); } } else{ @@ -1773,9 +1773,9 @@ class basic_string else{ //value_type is POD, so backwards expansion is much easier //than with vector - value_type * const oldbuf = container_detail::to_raw_pointer(old_start); - value_type * const newbuf = container_detail::to_raw_pointer(new_start); - const value_type *const pos = container_detail::to_raw_pointer(p); + value_type * const oldbuf = boost::movelib::to_raw_pointer(old_start); + value_type * const newbuf = boost::movelib::to_raw_pointer(new_start); + const value_type *const pos = boost::movelib::to_raw_pointer(p); const size_type before = pos - oldbuf; //First move old data @@ -1847,10 +1847,10 @@ class basic_string iterator erase(const_iterator p) BOOST_NOEXCEPT_OR_NOTHROW { // The move includes the terminating null. - CharT * const ptr = const_cast(container_detail::to_raw_pointer(p)); + CharT * const ptr = const_cast(boost::movelib::to_raw_pointer(p)); const size_type old_size = this->priv_size(); Traits::move(ptr, - container_detail::to_raw_pointer(p + 1), + boost::movelib::to_raw_pointer(p + 1), old_size - (p - this->priv_addr())); this->priv_size(old_size-1); return iterator(ptr); @@ -1866,12 +1866,12 @@ class basic_string //! the other elements being erased. If no such element exists, end() is returned. iterator erase(const_iterator first, const_iterator last) BOOST_NOEXCEPT_OR_NOTHROW { - CharT * f = const_cast(container_detail::to_raw_pointer(first)); + CharT * f = const_cast(boost::movelib::to_raw_pointer(first)); if (first != last) { // The move includes the terminating null. const size_type num_erased = last - first; const size_type old_size = this->priv_size(); Traits::move(f, - container_detail::to_raw_pointer(last), + boost::movelib::to_raw_pointer(last), (old_size + 1)-(last - this->priv_addr())); const size_type new_length = old_size - num_erased; this->priv_size(new_length); @@ -2059,11 +2059,11 @@ class basic_string { const size_type len = static_cast(i2 - i1); if (len >= n) { - Traits::assign(const_cast(container_detail::to_raw_pointer(i1)), n, c); + Traits::assign(const_cast(boost::movelib::to_raw_pointer(i1)), n, c); erase(i1 + n, i2); } else { - Traits::assign(const_cast(container_detail::to_raw_pointer(i1)), len, c); + Traits::assign(const_cast(boost::movelib::to_raw_pointer(i1)), len, c); insert(i2, n - len, c); } return *this; @@ -2088,7 +2088,7 @@ class basic_string ) { for ( ; i1 != i2 && j1 != j2; ++i1, ++j1){ - Traits::assign(*const_cast(container_detail::to_raw_pointer(i1)), *j1); + Traits::assign(*const_cast(boost::movelib::to_raw_pointer(i1)), *j1); } if (j1 == j2) @@ -2111,13 +2111,13 @@ class basic_string difference_type n = boost::container::iterator_distance(j1, j2); const difference_type len = i2 - i1; if (len >= n) { - this->priv_copy(j1, j2, const_cast(container_detail::to_raw_pointer(i1))); + this->priv_copy(j1, j2, const_cast(boost::movelib::to_raw_pointer(i1))); this->erase(i1 + n, i2); } else { ForwardIter m = j1; boost::container::iterator_advance(m, len); - this->priv_copy(j1, m, const_cast(container_detail::to_raw_pointer(i1))); + this->priv_copy(j1, m, const_cast(boost::movelib::to_raw_pointer(i1))); this->insert(i2, m, j2); } return *this; @@ -2166,7 +2166,7 @@ class basic_string if (pos > this->size()) throw_out_of_range("basic_string::copy out of range position"); const size_type len = container_detail::min_value(n, this->size() - pos); - Traits::copy(s, container_detail::to_raw_pointer(this->priv_addr() + pos), len); + Traits::copy(s, boost::movelib::to_raw_pointer(this->priv_addr() + pos), len); return len; } @@ -2195,7 +2195,7 @@ class basic_string //! //! Complexity: constant time. const CharT* c_str() const BOOST_NOEXCEPT_OR_NOTHROW - { return container_detail::to_raw_pointer(this->priv_addr()); } + { return boost::movelib::to_raw_pointer(this->priv_addr()); } //! Requires: The program shall not alter any of the values stored in the character array. //! @@ -2203,13 +2203,13 @@ class basic_string //! //! Complexity: constant time. const CharT* data() const BOOST_NOEXCEPT_OR_NOTHROW - { return container_detail::to_raw_pointer(this->priv_addr()); } + { return boost::movelib::to_raw_pointer(this->priv_addr()); } //! Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()]. //! //! Complexity: constant time. CharT* data() BOOST_NOEXCEPT_OR_NOTHROW - { return container_detail::to_raw_pointer(this->priv_addr()); } + { return boost::movelib::to_raw_pointer(this->priv_addr()); } #ifndef BOOST_CONTAINER_TEMPLATED_CONVERSION_OPERATOR_BROKEN //! Returns: a string_view to the characters in the string. @@ -2272,8 +2272,8 @@ class basic_string const pointer addr = this->priv_addr(); pointer finish = addr + this->priv_size(); const const_iterator result = - std::search(container_detail::to_raw_pointer(addr + pos), - container_detail::to_raw_pointer(finish), + std::search(boost::movelib::to_raw_pointer(addr + pos), + boost::movelib::to_raw_pointer(finish), s, s + n, Eq_traits()); return result != finish ? result - begin() : npos; } @@ -2804,8 +2804,8 @@ class basic_string { const difference_type n1 = l1 - f1; const difference_type n2 = l2 - f2; - const int cmp = Traits::compare(container_detail::to_raw_pointer(f1), - container_detail::to_raw_pointer(f2), + const int cmp = Traits::compare(boost::movelib::to_raw_pointer(f1), + boost::movelib::to_raw_pointer(f2), container_detail::min_value(n1, n2)); return cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0)); } @@ -2826,8 +2826,8 @@ class basic_string real_cap = long_size+1; const pointer ret = this->allocation_command(allocate_new, long_size+1, real_cap, reuse); //Copy and update - Traits::copy( container_detail::to_raw_pointer(ret) - , container_detail::to_raw_pointer(this->priv_long_addr()) + Traits::copy( boost::movelib::to_raw_pointer(ret) + , boost::movelib::to_raw_pointer(this->priv_long_addr()) , long_size+1); this->priv_long_addr(ret); this->priv_storage(real_cap); diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index c52367a..5ec669b 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -36,10 +36,10 @@ #include #include #include -#include +#include #include #include -#include +#include #include #include // intrusive @@ -613,7 +613,7 @@ struct vector_alloc_holder , m_size(holder.m_size) //Size is initialized here so vector should only call uninitialized_xxx after this { ::boost::container::uninitialized_move_alloc_n - (this->alloc(), container_detail::to_raw_pointer(holder.start()), m_size, container_detail::to_raw_pointer(this->start())); + (this->alloc(), boost::movelib::to_raw_pointer(holder.start()), m_size, boost::movelib::to_raw_pointer(this->start())); } template @@ -625,7 +625,7 @@ struct vector_alloc_holder const size_type n = holder.m_size; this->priv_first_allocation(n); ::boost::container::uninitialized_move_alloc_n - (this->alloc(), container_detail::to_raw_pointer(holder.start()), n, container_detail::to_raw_pointer(this->start())); + (this->alloc(), boost::movelib::to_raw_pointer(holder.start()), n, boost::movelib::to_raw_pointer(this->start())); } BOOST_CONTAINER_FORCEINLINE void priv_first_allocation(size_type cap) @@ -679,8 +679,8 @@ struct vector_alloc_holder void priv_deep_swap(vector_alloc_holder &x) { const size_type MaxTmpStorage = sizeof(value_type)*Allocator::internal_capacity; - value_type *const first_this = container_detail::to_raw_pointer(this->start()); - value_type *const first_x = container_detail::to_raw_pointer(x.start()); + value_type *const first_this = boost::movelib::to_raw_pointer(this->start()); + value_type *const first_x = boost::movelib::to_raw_pointer(x.start()); if(this->m_size < x.m_size){ boost::container::deep_swap_alloc_n(this->alloc(), first_this, this->m_size, first_x, x.m_size); @@ -1190,7 +1190,7 @@ class vector if (first == last){ //There are no more elements in the sequence, erase remaining T* const end_pos = this->priv_raw_end(); - const size_type n = static_cast(end_pos - container_detail::iterator_to_raw_pointer(cur)); + const size_type n = static_cast(end_pos - boost::movelib::iterator_to_raw_pointer(cur)); this->priv_destroy_last_n(n); } else{ @@ -2009,7 +2009,7 @@ class vector { BOOST_ASSERT(this->priv_in_range(position)); const pointer p = vector_iterator_get_ptr(position); - T *const pos_ptr = container_detail::to_raw_pointer(p); + T *const pos_ptr = boost::movelib::to_raw_pointer(p); T *const beg_ptr = this->priv_raw_begin(); T *const new_end_ptr = ::boost::container::move(pos_ptr + 1, beg_ptr + this->m_holder.m_size, pos_ptr); //Move elements forward and destroy last @@ -2029,9 +2029,9 @@ class vector (first < last && this->priv_in_range(first) && this->priv_in_range_or_end(last))); if (first != last){ T* const old_end_ptr = this->priv_raw_end(); - T* const first_ptr = container_detail::to_raw_pointer(vector_iterator_get_ptr(first)); - T* const last_ptr = container_detail::to_raw_pointer(vector_iterator_get_ptr(last)); - T* const ptr = container_detail::to_raw_pointer(boost::container::move(last_ptr, old_end_ptr, first_ptr)); + T* const first_ptr = boost::movelib::to_raw_pointer(vector_iterator_get_ptr(first)); + T* const last_ptr = boost::movelib::to_raw_pointer(vector_iterator_get_ptr(last)); + T* const ptr = boost::movelib::to_raw_pointer(boost::container::move(last_ptr, old_end_ptr, first_ptr)); this->priv_destroy_last_n(old_end_ptr - ptr); } return iterator(vector_iterator_get_ptr(first)); @@ -2245,7 +2245,7 @@ class vector this->priv_merge_in_new_buffer(UniqueBool(), first, n, comp, p, new_cap); } else{ - T *raw_pos = container_detail::iterator_to_raw_pointer(this->insert(this->cend(), first, last)); + T *raw_pos = boost::movelib::iterator_to_raw_pointer(this->insert(this->cend(), first, last)); T *raw_beg = this->priv_raw_begin(); T *raw_end = this->priv_raw_end(); boost::movelib::adaptive_merge(raw_beg, raw_pos, raw_end, comp, raw_end, free_c - n); @@ -2272,7 +2272,7 @@ class vector T* pbeg = this->priv_raw_begin(); size_type const old_size = this->size(); T* const pend = pbeg + old_size; - T* d_first = container_detail::to_raw_pointer(new_storage); + T* d_first = boost::movelib::to_raw_pointer(new_storage); size_type added = n; //Merge in new buffer loop while(1){ @@ -2308,7 +2308,7 @@ class vector //Nothrow operations pointer const old_p = this->m_holder.start(); size_type const old_cap = this->m_holder.capacity(); - boost::container::destroy_alloc_n(a, container_detail::to_raw_pointer(old_p), old_size); + boost::container::destroy_alloc_n(a, boost::movelib::to_raw_pointer(old_p), old_size); a.deallocate(old_p, old_cap); this->m_holder.m_size = old_size + added; this->m_holder.start(new_storage); @@ -2379,8 +2379,8 @@ class vector } //Else do a one by one move else{ - this->assign( boost::make_move_iterator(container_detail::iterator_to_raw_pointer(x.begin())) - , boost::make_move_iterator(container_detail::iterator_to_raw_pointer(x.end() )) + 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() )) ); } //Move allocator if needed @@ -2449,8 +2449,8 @@ class vector } //... and move-insert the remaining range sml.insert( sml.cend() - , boost::make_move_iterator(container_detail::iterator_to_raw_pointer(big.nth(common_elements))) - , boost::make_move_iterator(container_detail::iterator_to_raw_pointer(big.end())) + , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(big.nth(common_elements))) + , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(big.end())) ); //Destroy remaining elements big.erase(big.nth(common_elements), big.cend()); @@ -2475,7 +2475,7 @@ class vector pointer const p = allocator_traits_type::allocate(this->m_holder.alloc(), new_cap, this->m_holder.m_start); //We will reuse insert code, so create a dummy input iterator this->priv_forward_range_insert_new_allocation - ( container_detail::to_raw_pointer(p), new_cap, this->priv_raw_end(), 0, this->priv_dummy_empty_proxy()); + ( boost::movelib::to_raw_pointer(p), new_cap, this->priv_raw_end(), 0, this->priv_dummy_empty_proxy()); } void priv_reserve_no_capacity(size_type new_cap, version_2) @@ -2496,7 +2496,7 @@ class vector this->m_holder.capacity(real_cap); } else{ //If there is no forward expansion, move objects, we will reuse insertion code - T * const new_mem = container_detail::to_raw_pointer(ret); + T * const new_mem = boost::movelib::to_raw_pointer(ret); T * const ins_pos = this->priv_raw_end(); if(reuse){ //Backwards (and possibly forward) expansion #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS @@ -2626,7 +2626,7 @@ class vector ++this->num_alloc; #endif this->priv_forward_range_insert_new_allocation - ( container_detail::to_raw_pointer(p), sz + ( boost::movelib::to_raw_pointer(p), sz , this->priv_raw_begin(), 0, this->priv_dummy_empty_proxy()); } } @@ -2670,11 +2670,11 @@ class vector { //Check if we have enough memory or try to expand current memory const size_type n_pos = pos - this->m_holder.start(); - T *const raw_pos = container_detail::to_raw_pointer(pos); + T *const raw_pos = boost::movelib::to_raw_pointer(pos); const size_type new_cap = this->m_holder.next_capacity(n); //Pass the hint so that allocators can take advantage of this. - T * const new_buf = container_detail::to_raw_pointer + T * const new_buf = boost::movelib::to_raw_pointer (allocator_traits_type::allocate(this->m_holder.alloc(), new_cap, this->m_holder.m_start)); #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_alloc; @@ -2689,7 +2689,7 @@ class vector (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, version_2) { //Check if we have enough memory or try to expand current memory - T *const raw_pos = container_detail::to_raw_pointer(pos); + T *const raw_pos = boost::movelib::to_raw_pointer(pos); const size_type n_pos = raw_pos - this->priv_raw_begin(); //There is not enough memory, allocate a new @@ -2716,7 +2716,7 @@ class vector ++this->num_expand_bwd; #endif this->priv_forward_range_insert_expand_backwards - (container_detail::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy); + (boost::movelib::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy); } } //New buffer @@ -2725,7 +2725,7 @@ class vector ++this->num_alloc; #endif this->priv_forward_range_insert_new_allocation - ( container_detail::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy); + ( boost::movelib::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy); } return iterator(this->m_holder.start() + n_pos); @@ -2745,7 +2745,7 @@ class vector } else{ //Expand forward - T *const raw_pos = container_detail::to_raw_pointer(pos); + T *const raw_pos = boost::movelib::to_raw_pointer(pos); const size_type n_pos = raw_pos - this->priv_raw_begin(); this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); return iterator(this->m_holder.start() + n_pos); @@ -2862,7 +2862,7 @@ class vector private: BOOST_CONTAINER_FORCEINLINE T *priv_raw_begin() const - { return container_detail::to_raw_pointer(m_holder.start()); } + { return boost::movelib::to_raw_pointer(m_holder.start()); } BOOST_CONTAINER_FORCEINLINE T* priv_raw_end() const { return this->priv_raw_begin() + this->m_holder.m_size; } From 3516da36b0e8de22c08aaa2caf69bb52ae9209a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 8 Apr 2017 00:17:23 +0200 Subject: [PATCH 7/8] Doxygen documentation fixes --- include/boost/container/allocator_traits.hpp | 2 +- include/boost/container/flat_map.hpp | 2 +- include/boost/container/flat_set.hpp | 4 ++-- include/boost/container/string.hpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/boost/container/allocator_traits.hpp b/include/boost/container/allocator_traits.hpp index d6621f6..b08f601 100644 --- a/include/boost/container/allocator_traits.hpp +++ b/include/boost/container/allocator_traits.hpp @@ -347,7 +347,7 @@ struct allocator_traits #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: calls a.construct(p, std::forward(args)...) if that call is well-formed; - //! otherwise, invokes ::new (static_cast(p)) T(std::forward(args)...) + //! otherwise, invokes `placement new` (static_cast(p)) T(std::forward(args)...) template BOOST_CONTAINER_FORCEINLINE static void construct(Allocator & a, T* p, BOOST_FWD_REF(Args)... args) { diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index c5d6e03..50e25d8 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -2108,7 +2108,7 @@ class flat_multimap void merge(flat_map& source) { m_flat_tree.merge_equal(source.tree()); } - //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap&) + //! @copydoc ::boost::container::flat_multimap::merge(flat_map&) template void merge(BOOST_RV_REF_BEG flat_map BOOST_RV_REF_END source) { return this->merge(static_cast&>(source)); } diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 5dc6be5..e58ea4f 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -624,7 +624,7 @@ class flat_set BOOST_CONTAINER_FORCEINLINE void merge(flat_set& source) { this->base_t::merge_unique(source.tree()); } - //! @copydoc ::boost::container::flat_map::merge(flat_set&) + //! @copydoc ::boost::container::flat_set::merge(flat_set&) template BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_set BOOST_RV_REF_END source) { return this->merge(static_cast&>(source)); } @@ -634,7 +634,7 @@ class flat_set BOOST_CONTAINER_FORCEINLINE void merge(flat_multiset& source) { this->base_t::merge_unique(source.tree()); } - //! @copydoc ::boost::container::flat_map::merge(flat_multiset&) + //! @copydoc ::boost::container::flat_set::merge(flat_multiset&) template BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multiset BOOST_RV_REF_END source) { return this->merge(static_cast&>(source)); } diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index b49811f..915fb58 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -2128,7 +2128,7 @@ class basic_string //! //! Effects: Calls `replace(i1 - begin(), i2 - i1, sv).`. //! - //! : *this. + //! Returns: *this. template