634 lines
16 KiB
C++
634 lines
16 KiB
C++
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// (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();
|
|
}
|