| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // (C) Copyright Ion Gaztanaga 2016-2016. 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 <boost/core/lightweight_test.hpp> |
| #include <boost/static_assert.hpp> |
| #include <boost/container/node_handle.hpp> |
| #include <boost/container/new_allocator.hpp> |
| #include <boost/move/utility_core.hpp> |
| #include <boost/move/adl_move_swap.hpp> |
| #include <boost/container/detail/pair_key_mapped_of_value.hpp> |
| |
| using namespace ::boost::container; |
| |
| enum EAllocState |
| { |
| DefaultConstructed, |
| MoveConstructed, |
| MoveAssigned, |
| CopyConstructed, |
| CopyAssigned, |
| Swapped, |
| Destructed |
| }; |
| |
| template<class Node> |
| class trace_allocator |
| : public new_allocator<Node> |
| { |
| BOOST_COPYABLE_AND_MOVABLE(trace_allocator) |
| |
| typedef new_allocator<Node> 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<class T2> |
| struct rebind |
| { |
| typedef trace_allocator<T2> 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<class OtherNode> |
| trace_allocator(const trace_allocator<OtherNode> &other) |
| : m_state(CopyConstructed), m_value(other.m_value) |
| { |
| ++count; |
| } |
| |
| template<class OtherNode> |
| trace_allocator & operator=(BOOST_COPY_ASSIGN_REF(trace_allocator<OtherNode>) 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<class Node> |
| unsigned int trace_allocator<Node>::count = 0; |
| |
| template<class T> |
| 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<class T1, class T2> |
| struct value |
| { |
| T1 first; |
| T2 second; |
| }; |
| |
| template<class T> |
| unsigned int node<T>::count = 0; |
| |
| |
| //Common types |
| typedef value<int, unsigned> test_pair; |
| typedef pair_key_mapped_of_value<int, unsigned> key_mapped_t; |
| typedef node<test_pair> node_t; |
| typedef trace_allocator< node_t > node_alloc_t; |
| typedef node_handle<node_alloc_t, void> node_handle_set_t; |
| typedef node_handle<node_alloc_t, key_mapped_t> node_handle_map_t; |
| typedef allocator_traits<node_alloc_t>::portable_rebind_alloc<test_pair>::type value_allocator_type; |
| |
| void test_types() |
| { |
| //set |
| BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_set_t::value_type, test_pair>::value )); |
| BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_set_t::key_type, test_pair>::value )); |
| BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_set_t::mapped_type, test_pair>::value )); |
| BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_set_t::allocator_type, value_allocator_type>::value )); |
| |
| //map |
| BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_map_t::value_type, test_pair>::value )); |
| BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_map_t::key_type, int>::value )); |
| BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_map_t::mapped_type, unsigned>::value )); |
| BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_map_t::allocator_type, value_allocator_type>::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<node_alloc_t>::portable_rebind_alloc<test_pair>::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(); |
| } |