90be9ebe22
Extracted meta utilities used only by unique_ptr and friends to its own "unique_ptr_meta_utils.hpp" header.
518 lines
15 KiB
C++
518 lines
15 KiB
C++
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// (C) Copyright Howard Hinnant 2009
|
|
// (C) Copyright Ion Gaztanaga 2014-2014.
|
|
//
|
|
// 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/move for documentation.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
#include <boost/move/utility_core.hpp>
|
|
#include <boost/move/unique_ptr.hpp>
|
|
#include <boost/static_assert.hpp>
|
|
#include <boost/core/lightweight_test.hpp>
|
|
|
|
//////////////////////////////////////////////
|
|
//
|
|
// The initial implementation of these tests
|
|
// was written by Howard Hinnant.
|
|
//
|
|
// These test were later refactored grouping
|
|
// and porting them to Boost.Move.
|
|
//
|
|
// Many thanks to Howard for releasing his C++03
|
|
// unique_ptr implementation with such detailed
|
|
// test cases.
|
|
//
|
|
//////////////////////////////////////////////
|
|
|
|
#include "unique_ptr_test_utils_beg.hpp"
|
|
|
|
namespace bml = ::boost::movelib;
|
|
namespace bmupmu = ::boost::move_upmu;
|
|
|
|
////////////////////////////////
|
|
// unique_ptr_ctor_move_defdel
|
|
////////////////////////////////
|
|
|
|
namespace unique_ptr_ctor_move_defdel{
|
|
|
|
// test converting move ctor. Should only require a MoveConstructible deleter, or if
|
|
// deleter is a reference, not even that.
|
|
|
|
void test()
|
|
{
|
|
//Single unique_ptr
|
|
reset_counters();
|
|
{
|
|
bml::unique_ptr<A> s(new A);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 1);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
//Unbounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
bml::unique_ptr<A[]> s(new A[2]);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A[]> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
//Bounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
bml::unique_ptr<A[2]> s(new A[2]);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A[2]> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
}
|
|
|
|
} //namespace unique_ptr_ctor_move_defdel{
|
|
|
|
////////////////////////////////
|
|
// unique_ptr_ctor_move_movedel
|
|
////////////////////////////////
|
|
|
|
namespace unique_ptr_ctor_move_movedel{
|
|
|
|
// test converting move ctor. Should only require a MoveConstructible deleter, or if
|
|
// deleter is a reference, not even that.
|
|
|
|
void test()
|
|
{
|
|
//Single unique_ptr
|
|
reset_counters();
|
|
{
|
|
bml::unique_ptr<A, move_constr_deleter<A> > s(new A);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A, move_constr_deleter<A> > s2 = boost::move(s);
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 1);
|
|
BOOST_TEST(s2.get_deleter().state() == 5);
|
|
BOOST_TEST(s.get_deleter().state() == 0);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
//Unbounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
bml::unique_ptr<A[], move_constr_deleter<A[]> > s(new A[2]);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A[], move_constr_deleter<A[]> > s2 = boost::move(s);
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
BOOST_TEST(s2.get_deleter().state() == 5);
|
|
BOOST_TEST(s.get_deleter().state() == 0);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
//Bounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
bml::unique_ptr<A[2]> s(new A[2]);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A[2]> s2 = boost::move(s);
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
}
|
|
|
|
} //namespace unique_ptr_ctor_move_movedel{
|
|
|
|
////////////////////////////////
|
|
// unique_ptr_ctor_move_dfctrdelref
|
|
////////////////////////////////
|
|
|
|
namespace unique_ptr_ctor_move_dfctrdelref{
|
|
|
|
// test converting move ctor. Should only require a MoveConstructible deleter, or if
|
|
// deleter is a reference, not even that.
|
|
|
|
void test()
|
|
{
|
|
//Single unique_ptr
|
|
reset_counters();
|
|
{
|
|
def_constr_deleter<A> d;
|
|
bml::unique_ptr<A, def_constr_deleter<A>&> s(new A, d);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A, def_constr_deleter<A>&> s2 = boost::move(s);
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 1);
|
|
d.set_state(6);
|
|
BOOST_TEST(s2.get_deleter().state() == d.state());
|
|
BOOST_TEST(s.get_deleter().state() == d.state());
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
//Unbounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
def_constr_deleter<A[]> d;
|
|
bml::unique_ptr<A[], def_constr_deleter<A[]>&> s(new A[2], d);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A[], def_constr_deleter<A[]>&> s2 = boost::move(s);
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
d.set_state(6);
|
|
BOOST_TEST(s2.get_deleter().state() == d.state());
|
|
BOOST_TEST(s.get_deleter().state() == d.state());
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
//Bounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
def_constr_deleter<A[2]> d;
|
|
bml::unique_ptr<A[2], def_constr_deleter<A[2]>&> s(new A[2], d);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A[2], def_constr_deleter<A[2]>&> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
d.set_state(6);
|
|
BOOST_TEST(s2.get_deleter().state() == d.state());
|
|
BOOST_TEST(s.get_deleter().state() == d.state());
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
}
|
|
|
|
} //namespace unique_ptr_ctor_move_dfctrdelref{
|
|
|
|
////////////////////////////////
|
|
// unique_ptr_ctor_move_convert_defdel
|
|
////////////////////////////////
|
|
|
|
namespace unique_ptr_ctor_move_convert_defdel{
|
|
|
|
// test converting move ctor. Should only require a MoveConstructible deleter, or if
|
|
// deleter is a reference, not even that.
|
|
|
|
void test()
|
|
{
|
|
//Single unique_ptr
|
|
reset_counters();
|
|
{
|
|
bml::unique_ptr<B> s(new B);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 1);
|
|
BOOST_TEST(B::count == 1);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
BOOST_TEST(B::count == 0);
|
|
//Unbounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
bml::unique_ptr<A[]> s(new A[2]);
|
|
A* p = s.get();
|
|
bml::unique_ptr<const volatile A[]> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
|
|
//Bounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
bml::unique_ptr<A[2]> s(new A[2]);
|
|
A* p = s.get();
|
|
bml::unique_ptr<const volatile A[2]> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
{
|
|
bml::unique_ptr<A[2]> s(new A[2]);
|
|
A* p = s.get();
|
|
bml::unique_ptr<const volatile A[]> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
}
|
|
|
|
} //namespace unique_ptr_ctor_move_convert_defdel{
|
|
|
|
////////////////////////////////
|
|
// unique_ptr_ctor_move_convert_movedel
|
|
////////////////////////////////
|
|
|
|
namespace unique_ptr_ctor_move_convert_movedel{
|
|
|
|
// test converting move ctor. Should only require a MoveConstructible deleter, or if
|
|
// deleter is a reference, not even that.
|
|
|
|
void test()
|
|
{
|
|
//Single unique_ptr
|
|
reset_counters();
|
|
BOOST_STATIC_ASSERT((bmupmu::is_convertible<B, A>::value));
|
|
{
|
|
bml::unique_ptr<B, move_constr_deleter<B> > s(new B);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A, move_constr_deleter<A> > s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 1);
|
|
BOOST_TEST(B::count == 1);
|
|
BOOST_TEST(s2.get_deleter().state() == 5);
|
|
BOOST_TEST(s.get_deleter().state() == 0);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
BOOST_TEST(B::count == 0);
|
|
//Unbounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
bml::unique_ptr<const A[], move_constr_deleter<const A[]> > s(new const A[2]);
|
|
const A* p = s.get();
|
|
bml::unique_ptr<const volatile A[], move_constr_deleter<const volatile A[]> > s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
BOOST_TEST(s2.get_deleter().state() == 5);
|
|
BOOST_TEST(s.get_deleter().state() == 0);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
BOOST_TEST(B::count == 0);
|
|
//Bounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
bml::unique_ptr<const A[2], move_constr_deleter<const A[2]> > s(new const A[2]);
|
|
const A* p = s.get();
|
|
bml::unique_ptr<const volatile A[2], move_constr_deleter<const volatile A[2]> > s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
BOOST_TEST(s2.get_deleter().state() == 5);
|
|
BOOST_TEST(s.get_deleter().state() == 0);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
BOOST_TEST(B::count == 0);
|
|
{
|
|
bml::unique_ptr<const A[2], move_constr_deleter<const A[2]> > s(new const A[2]);
|
|
const A* p = s.get();
|
|
bml::unique_ptr<const volatile A[], move_constr_deleter<const volatile A[]> > s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
BOOST_TEST(s2.get_deleter().state() == 5);
|
|
BOOST_TEST(s.get_deleter().state() == 0);
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
BOOST_TEST(B::count == 0);
|
|
}
|
|
|
|
} //namespace unique_ptr_ctor_move_convert_movedel{
|
|
|
|
////////////////////////////////
|
|
// unique_ptr_ctor_move_convert_dfctrdelref
|
|
////////////////////////////////
|
|
|
|
namespace unique_ptr_ctor_move_convert_dfctrdelref{
|
|
|
|
// test converting move ctor. Should only require a MoveConstructible deleter, or if
|
|
// deleter is a reference, not even that.
|
|
|
|
void test()
|
|
{
|
|
//Single unique_ptr
|
|
reset_counters();
|
|
{
|
|
def_constr_deleter<A> d;
|
|
bml::unique_ptr<B, def_constr_deleter<A>&> s(new B, d);
|
|
A* p = s.get();
|
|
bml::unique_ptr<A, def_constr_deleter<A>&> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 1);
|
|
BOOST_TEST(B::count == 1);
|
|
d.set_state(6);
|
|
BOOST_TEST(s2.get_deleter().state() == d.state());
|
|
BOOST_TEST(s.get_deleter().state() == d.state());
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
BOOST_TEST(B::count == 0);
|
|
//Unbounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
def_constr_deleter<volatile A[]> d;
|
|
bml::unique_ptr<A[], def_constr_deleter<volatile A[]>&> s(new A[2], d);
|
|
A* p = s.get();
|
|
bml::unique_ptr<volatile A[], def_constr_deleter<volatile A[]>&> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
d.set_state(6);
|
|
BOOST_TEST(s2.get_deleter().state() == d.state());
|
|
BOOST_TEST(s.get_deleter().state() == d.state());
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
//Bounded array unique_ptr
|
|
reset_counters();
|
|
{
|
|
def_constr_deleter<volatile A[2]> d;
|
|
bml::unique_ptr<A[2], def_constr_deleter<volatile A[2]>&> s(new A[2], d);
|
|
A* p = s.get();
|
|
bml::unique_ptr<volatile A[2], def_constr_deleter<volatile A[2]>&> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
d.set_state(6);
|
|
BOOST_TEST(s2.get_deleter().state() == d.state());
|
|
BOOST_TEST(s.get_deleter().state() == d.state());
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
{
|
|
def_constr_deleter<volatile A[]> d;
|
|
bml::unique_ptr<A[2], def_constr_deleter<volatile A[]>&> s(new A[2], d);
|
|
A* p = s.get();
|
|
bml::unique_ptr<volatile A[], def_constr_deleter<volatile A[]>&> s2(boost::move(s));
|
|
BOOST_TEST(s2.get() == p);
|
|
BOOST_TEST(s.get() == 0);
|
|
BOOST_TEST(A::count == 2);
|
|
d.set_state(6);
|
|
BOOST_TEST(s2.get_deleter().state() == d.state());
|
|
BOOST_TEST(s.get_deleter().state() == d.state());
|
|
}
|
|
BOOST_TEST(A::count == 0);
|
|
}
|
|
|
|
} //namespace unique_ptr_ctor_move_convert_dfctrdelref{
|
|
|
|
////////////////////////////////
|
|
// unique_ptr_ctor_move_sourcesink
|
|
////////////////////////////////
|
|
|
|
namespace unique_ptr_ctor_move_sourcesink{
|
|
|
|
// test move ctor. Should only require a MoveConstructible deleter, or if
|
|
// deleter is a reference, not even that.
|
|
|
|
bml::unique_ptr<A> source1()
|
|
{ return bml::unique_ptr<A>(new A); }
|
|
|
|
bml::unique_ptr<A[]> source1_unbounded_array()
|
|
{ return bml::unique_ptr<A[]> (new A[2]); }
|
|
|
|
bml::unique_ptr<A[2]> source1_bounded_array()
|
|
{ return bml::unique_ptr<A[2]> (new A[2]); }
|
|
|
|
void sink1(bml::unique_ptr<A>)
|
|
{}
|
|
|
|
void sink1_unbounded_array(bml::unique_ptr<A[]>)
|
|
{}
|
|
|
|
void sink1_bounded_array(bml::unique_ptr<A[2]>)
|
|
{}
|
|
|
|
bml::unique_ptr<A, move_constr_deleter<A> > source2()
|
|
{ return bml::unique_ptr<A, move_constr_deleter<A> > (new A); }
|
|
|
|
bml::unique_ptr<A[], move_constr_deleter<A[]> > source2_unbounded_array()
|
|
{ return bml::unique_ptr<A[], move_constr_deleter<A[]> >(new A[2]); }
|
|
|
|
bml::unique_ptr<A[2], move_constr_deleter<A[2]> > source2_bounded_array()
|
|
{ return bml::unique_ptr<A[2], move_constr_deleter<A[2]> >(new A[2]); }
|
|
|
|
void sink2(bml::unique_ptr<A, move_constr_deleter<A> >)
|
|
{}
|
|
|
|
void sink2_unbounded_array(bml::unique_ptr<A[], move_constr_deleter<A[]> >)
|
|
{}
|
|
|
|
void sink2_bounded_array(bml::unique_ptr<A[2], move_constr_deleter<A[2]> >)
|
|
{}
|
|
|
|
bml::unique_ptr<A, def_constr_deleter<A>&> source3()
|
|
{
|
|
static def_constr_deleter<A> d;
|
|
return bml::unique_ptr<A, def_constr_deleter<A>&>(new A, d);
|
|
}
|
|
|
|
bml::unique_ptr<A[], def_constr_deleter<A[]>&> source3_unbounded_array()
|
|
{
|
|
static def_constr_deleter<A[]> d;
|
|
return bml::unique_ptr<A[], def_constr_deleter<A[]>&>(new A[2], d);
|
|
}
|
|
|
|
bml::unique_ptr<A[2], def_constr_deleter<A[2]>&> source3_bounded_array()
|
|
{
|
|
static def_constr_deleter<A[2]> d;
|
|
return bml::unique_ptr<A[2], def_constr_deleter<A[2]>&>(new A[2], d);
|
|
}
|
|
|
|
void sink3(bml::unique_ptr<A, def_constr_deleter<A>&> )
|
|
{}
|
|
|
|
void sink3_unbounded_array(bml::unique_ptr<A[], def_constr_deleter<A[]>&> )
|
|
{}
|
|
|
|
void sink3_bounded_array(bml::unique_ptr<A[2], def_constr_deleter<A[2]>&> )
|
|
{}
|
|
|
|
void test()
|
|
{
|
|
//Single unique_ptr
|
|
reset_counters();
|
|
sink1(source1());
|
|
sink2(source2());
|
|
sink3(source3());
|
|
BOOST_TEST(A::count == 0);
|
|
//Unbounded array unique_ptr
|
|
reset_counters();
|
|
sink1_unbounded_array(source1_unbounded_array());
|
|
sink2_unbounded_array(source2_unbounded_array());
|
|
sink3_unbounded_array(source3_unbounded_array());
|
|
BOOST_TEST(A::count == 0);
|
|
//Bbounded array unique_ptr
|
|
reset_counters();
|
|
sink1_bounded_array(source1_bounded_array());
|
|
sink2_bounded_array(source2_bounded_array());
|
|
sink3_bounded_array(source3_bounded_array());
|
|
BOOST_TEST(A::count == 0);
|
|
}
|
|
|
|
} //namespace unique_ptr_ctor_move_sourcesink{
|
|
|
|
////////////////////////////////
|
|
// main
|
|
////////////////////////////////
|
|
int main()
|
|
{
|
|
//Move Constructor
|
|
unique_ptr_ctor_move_defdel::test();
|
|
unique_ptr_ctor_move_movedel::test();
|
|
unique_ptr_ctor_move_dfctrdelref::test();
|
|
unique_ptr_ctor_move_convert_defdel::test();
|
|
unique_ptr_ctor_move_convert_movedel::test();
|
|
unique_ptr_ctor_move_convert_dfctrdelref::test();
|
|
unique_ptr_ctor_move_sourcesink::test();
|
|
|
|
//Test results
|
|
return boost::report_errors();
|
|
}
|
|
|
|
#include "unique_ptr_test_utils_end.hpp"
|