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