Fixes #233 ("Can't std::move small_vector with move-only type")

This commit is contained in:
Ion Gaztañaga
2023-03-13 10:06:53 +01:00
parent db96d2ad47
commit 5cc9617487
6 changed files with 410 additions and 111 deletions
+173 -21
View File
@@ -31,7 +31,19 @@ struct is_copyable<int>
static const bool value = true;
};
template<class T>
struct is_move_assignable
{
static const bool value = true;
};
/////////////////////////
//
// movable_int
//
/////////////////////////
class movable_int
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(movable_int)
@@ -122,13 +134,8 @@ inline movable_int produce_movable_int()
{ return movable_int(); }
template<class E, class T>
std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, movable_int const & p)
{
os << p.get_int();
return os;
}
std::basic_ostream<E, T> & operator<<(std::basic_ostream<E, T> & os, movable_int const & p)
{ os << p.get_int(); return os; }
template<>
struct is_copyable<movable_int>
@@ -136,6 +143,150 @@ struct is_copyable<movable_int>
static const bool value = false;
};
/////////////////////////
//
// moveconstruct_int
//
/////////////////////////
class moveconstruct_int
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(moveconstruct_int)
moveconstruct_int& operator= (BOOST_RV_REF(moveconstruct_int) mmi);
public:
static unsigned int count;
moveconstruct_int()
: m_int(0)
{
++count;
}
explicit moveconstruct_int(int a)
: m_int(a)
{
//Disallow INT_MIN
BOOST_ASSERT(this->m_int != INT_MIN);
++count;
}
moveconstruct_int(BOOST_RV_REF(moveconstruct_int) mmi)
: m_int(mmi.m_int)
{
BOOST_ASSERT(&mmi != this);
mmi.m_int = 0; ++count;
}
moveconstruct_int& operator= (int i)
{
this->m_int = i; BOOST_ASSERT(this->m_int != INT_MIN); return *this;
}
~moveconstruct_int()
{
//Double destructor called
BOOST_ASSERT(this->m_int != INT_MIN);
this->m_int = INT_MIN;
--count;
}
friend bool operator ==(const moveconstruct_int& l, const moveconstruct_int& r)
{
return l.m_int == r.m_int;
}
friend bool operator !=(const moveconstruct_int& l, const moveconstruct_int& r)
{
return l.m_int != r.m_int;
}
friend bool operator <(const moveconstruct_int& l, const moveconstruct_int& r)
{
return l.m_int < r.m_int;
}
friend bool operator <=(const moveconstruct_int& l, const moveconstruct_int& r)
{
return l.m_int <= r.m_int;
}
friend bool operator >=(const moveconstruct_int& l, const moveconstruct_int& r)
{
return l.m_int >= r.m_int;
}
friend bool operator >(const moveconstruct_int& l, const moveconstruct_int& r)
{
return l.m_int > r.m_int;
}
int get_int() const
{
return m_int;
}
friend bool operator==(const moveconstruct_int& l, int r)
{
return l.get_int() == r;
}
friend bool operator==(int l, const moveconstruct_int& r)
{
return l == r.get_int();
}
friend bool operator<(const moveconstruct_int& l, int r)
{
return l.get_int() < r;
}
friend bool operator<(int l, const moveconstruct_int& r)
{
return l < r.get_int();
}
friend std::size_t hash_value(const moveconstruct_int& v)
{
return (std::size_t)v.get_int();
}
private:
int m_int;
};
unsigned int moveconstruct_int::count = 0;
inline moveconstruct_int produce_movableconstruct_int()
{
return moveconstruct_int();
}
template<class E, class T>
std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& os, moveconstruct_int const& p)
{
os << p.get_int(); return os;
}
template<>
struct is_copyable<moveconstruct_int>
{
static const bool value = false;
};
template<>
struct is_move_assignable<moveconstruct_int>
{
static const bool value = false;
};
/////////////////////////
//
// movable_and_copyable_int
//
/////////////////////////
class movable_and_copyable_int
{
BOOST_COPYABLE_AND_MOVABLE(movable_and_copyable_int)
@@ -236,13 +387,8 @@ inline movable_and_copyable_int produce_movable_and_copyable_int()
{ return movable_and_copyable_int(); }
template<class E, class T>
std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, movable_and_copyable_int const & p)
{
os << p.get_int();
return os;
}
std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, movable_and_copyable_int const & p)
{ os << p.get_int(); return os; }
template<>
struct is_copyable<movable_and_copyable_int>
@@ -250,6 +396,12 @@ struct is_copyable<movable_and_copyable_int>
static const bool value = true;
};
/////////////////////////
//
// copyable_int
//
/////////////////////////
class copyable_int
{
public:
@@ -332,13 +484,8 @@ inline copyable_int produce_copyable_int()
{ return copyable_int(); }
template<class E, class T>
std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, copyable_int const & p)
{
os << p.get_int();
return os;
}
std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, copyable_int const & p)
{ os << p.get_int(); return os; }
template<>
struct is_copyable<copyable_int>
@@ -346,6 +493,11 @@ struct is_copyable<copyable_int>
static const bool value = true;
};
/////////////////////////
//
// non_copymovable_int
//
/////////////////////////
class non_copymovable_int
{
non_copymovable_int(const non_copymovable_int& mmi);
+41
View File
@@ -15,6 +15,7 @@
#include "../../intrusive/test/iterator_test.hpp"
#include <boost/container/allocator.hpp>
#include <boost/container/allocator_traits.hpp>
#include <iostream>
@@ -149,6 +150,43 @@ bool test_swap()
return true;
}
template<class VoidAllocator>
struct GetAllocatorCont
{
template<class ValueType>
struct apply
{
typedef boost::container::small_vector< ValueType, 10
, typename boost::container::allocator_traits<VoidAllocator>
::template portable_rebind_alloc<ValueType>::type
> type;
};
};
template<class VoidAllocator>
int test_cont_variants()
{
using namespace boost::container;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<int>::type MyCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::movable_int>::type MyMoveCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::movable_and_copyable_int>::type MyCopyMoveCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::copyable_int>::type MyCopyCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::moveconstruct_int>::type MyMoveConstructCont;
if (test::vector_test<MyCont>())
return 1;
if (test::vector_test<MyMoveCont>())
return 1;
if (test::vector_test<MyCopyMoveCont>())
return 1;
if (test::vector_test<MyCopyCont>())
return 1;
if (test::vector_test<MyMoveConstructCont>())
return 1;
return 0;
}
int main()
{
using namespace boost::container;
@@ -162,6 +200,9 @@ int main()
if(test::vector_test< small_vector<int, 2000> >())
return 1;
if (test_cont_variants< new_allocator<void> >())
return 1;
////////////////////////////////////
// Default init test
////////////////////////////////////
+3
View File
@@ -127,6 +127,7 @@ int test_cont_variants()
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::movable_int>::type MyMoveCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::movable_and_copyable_int>::type MyCopyMoveCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::copyable_int>::type MyCopyCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::moveconstruct_int>::type MyMoveConstructCont;
if(test::vector_test<MyCont>())
return 1;
@@ -136,6 +137,8 @@ int test_cont_variants()
return 1;
if(test::vector_test<MyCopyCont>())
return 1;
if (test::vector_test<MyMoveConstructCont>())
return 1;
return 0;
}
+57 -38
View File
@@ -271,49 +271,23 @@ bool vector_copyable_only(MyBoostVector &boostvector, MyStdVector &stdvector, bo
}
template<class MyBoostVector>
int vector_test()
int vector_move_assignable_only(boost::container::dtl::false_type)
{
return 0;
}
//Function to check if both sets are equal
template<class MyBoostVector>
int vector_move_assignable_only(boost::container::dtl::true_type)
{
const int max = 100;
typedef std::vector<int> MyStdVector;
typedef typename MyBoostVector::value_type IntType;
typedef typename MyBoostVector::difference_type difference_type;
const int max = 100;
if(!test_range_insertion<MyBoostVector>()){
return 1;
}
{ //Vector(n)
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp =
::boost::movelib::make_unique<MyBoostVector>(100u);
::boost::movelib::unique_ptr<MyStdVector> const stdvectorp =
::boost::movelib::make_unique<MyStdVector>(100u);
if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1;
}
{ //Vector(n, alloc)
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp =
::boost::movelib::make_unique<MyBoostVector>(100u, typename MyBoostVector::allocator_type());
::boost::movelib::unique_ptr<MyStdVector> const stdvectorp =
::boost::movelib::make_unique<MyStdVector>(100u);
if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1;
}
{ //Vector(Vector &&)
::boost::movelib::unique_ptr<MyStdVector> const stdvectorp =
::boost::movelib::make_unique<MyStdVector>(100u);
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp =
::boost::movelib::make_unique<MyBoostVector>(100u);
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp2 =
::boost::movelib::make_unique<MyBoostVector>(::boost::move(*boostvectorp));
if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1;
}
{ //Vector(Vector &&, alloc)
::boost::movelib::unique_ptr<MyStdVector> const stdvectorp =
::boost::movelib::make_unique<MyStdVector>(100u);
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp =
::boost::movelib::make_unique<MyBoostVector>(100u);
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp2 =
::boost::movelib::make_unique<MyBoostVector>
(::boost::move(*boostvectorp), typename MyBoostVector::allocator_type());
if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1;
}
{ //Vector operator=(Vector &&)
::boost::movelib::unique_ptr<MyStdVector> const stdvectorp =
::boost::movelib::make_unique<MyStdVector>(100u);
@@ -521,7 +495,7 @@ int vector_test()
stdvector.assign(l.begin(), l.end());
if(!test::CheckEqualContainers(boostvector, stdvector)) return 1;
}
if(!vector_capacity_test(boostvector, stdvector, dtl::bool_<vector_has_function_capacity<MyBoostVector>::value>()))
return 1;
@@ -534,8 +508,53 @@ int vector_test()
boostvector.resize(100u);
if(!test_nth_index_of(boostvector))
return 1;
}
return 0;
}
template<class MyBoostVector>
int vector_test()
{
typedef std::vector<int> MyStdVector;
typedef typename MyBoostVector::value_type IntType;
{ //Vector(n)
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp =
::boost::movelib::make_unique<MyBoostVector>(100u);
::boost::movelib::unique_ptr<MyStdVector> const stdvectorp =
::boost::movelib::make_unique<MyStdVector>(100u);
if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1;
}
{ //Vector(n, alloc)
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp =
::boost::movelib::make_unique<MyBoostVector>(100u, typename MyBoostVector::allocator_type());
::boost::movelib::unique_ptr<MyStdVector> const stdvectorp =
::boost::movelib::make_unique<MyStdVector>(100u);
if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1;
}
{ //Vector(Vector &&)
::boost::movelib::unique_ptr<MyStdVector> const stdvectorp =
::boost::movelib::make_unique<MyStdVector>(100u);
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp =
::boost::movelib::make_unique<MyBoostVector>(100u);
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp2 =
::boost::movelib::make_unique<MyBoostVector>(::boost::move(*boostvectorp));
if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1;
}
{ //Vector(Vector &&, alloc)
::boost::movelib::unique_ptr<MyStdVector> const stdvectorp =
::boost::movelib::make_unique<MyStdVector>(100u);
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp =
::boost::movelib::make_unique<MyBoostVector>(100u);
::boost::movelib::unique_ptr<MyBoostVector> const boostvectorp2 =
::boost::movelib::make_unique<MyBoostVector>
(::boost::move(*boostvectorp), typename MyBoostVector::allocator_type());
if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1;
}
if (0 != vector_move_assignable_only< MyBoostVector>(dtl::bool_<boost::container::test::is_copyable<IntType>::value>()))
return 1;
std::cout << std::endl << "Test OK!" << std::endl;
return 0;
}