////////////////////////////////////////////////////////////////////////////// // // (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 #include #include #include #include #include #include using namespace ::boost::container; 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(( dtl::is_same::value )); BOOST_STATIC_ASSERT(( dtl::is_same::value )); BOOST_STATIC_ASSERT(( dtl::is_same::value )); BOOST_STATIC_ASSERT(( dtl::is_same::value )); //map BOOST_STATIC_ASSERT(( dtl::is_same::value )); BOOST_STATIC_ASSERT(( dtl::is_same::value )); BOOST_STATIC_ASSERT(( dtl::is_same::value )); BOOST_STATIC_ASSERT(( dtl::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(); }