blob: 20cb4a88b7f08fe8cf070126b22babf56878814d [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
//
// \(C\) Copyright Benedek Thaler 2015-2016
// \(C\) Copyright Ion Gaztanaga 2019-2020. 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://erenon.hu/double_ended for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINER_TEST_TEST_ELEM_HPP
#define BOOST_CONTAINER_TEST_TEST_ELEM_HPP
#include <boost/utility/compare_pointees.hpp>
#include <cstdlib>
namespace boost {
namespace container {
struct test_exception {};
struct test_elem_throw
{
private:
static int throw_on_ctor_after /*= -1*/;
static int throw_on_copy_after /*= -1*/;
static int throw_on_move_after /*= -1*/;
public:
static void on_ctor_after(int x) { throw_on_ctor_after = x; }
static void on_copy_after(int x) { throw_on_copy_after = x; }
static void on_move_after(int x) { throw_on_move_after = x; }
static void do_not_throw()
{
throw_on_ctor_after = -1;
throw_on_copy_after = -1;
throw_on_move_after = -1;
}
static void in_constructor() { maybe_throw(throw_on_ctor_after); }
static void in_copy() { maybe_throw(throw_on_copy_after); }
static void in_move() { maybe_throw(throw_on_move_after); }
private:
static void maybe_throw(int& counter)
{
if (counter > 0)
{
--counter;
if (counter == 0)
{
--counter;
#ifndef BOOST_NO_EXCEPTIONS
throw test_exception();
#else
std::abort();
#endif
}
}
}
};
int test_elem_throw::throw_on_ctor_after = -1;
int test_elem_throw::throw_on_copy_after = -1;
int test_elem_throw::throw_on_move_after = -1;
struct test_elem_base
{
private:
BOOST_COPYABLE_AND_MOVABLE(test_elem_base)
public:
test_elem_base()
{
test_elem_throw::in_constructor();
_index = new int(0);
++_live_count;
}
test_elem_base(int index)
{
test_elem_throw::in_constructor();
_index = new int(index);
++_live_count;
}
explicit test_elem_base(const test_elem_base& rhs)
{
test_elem_throw::in_copy();
_index = new int(*rhs._index);
++_live_count;
}
test_elem_base(BOOST_RV_REF(test_elem_base) rhs)
{
test_elem_throw::in_move();
_index = rhs._index;
rhs._index = 0;
++_live_count;
}
test_elem_base &operator=(BOOST_COPY_ASSIGN_REF(test_elem_base) rhs)
{
test_elem_throw::in_copy();
if (_index) { delete _index; }
_index = new int(*rhs._index);
return *this;
}
test_elem_base &operator=(BOOST_RV_REF(test_elem_base) rhs)
{
test_elem_throw::in_move();
if (_index) { delete _index; }
_index = rhs._index;
rhs._index = 0;
return *this;
}
~test_elem_base()
{
if (_index) { delete _index; }
--_live_count;
}
friend bool operator==(const test_elem_base& a, const test_elem_base& b)
{
return a._index && b._index && *(a._index) == *(b._index);
}
friend bool operator==(int a, const test_elem_base& b)
{
return b._index != 0 && a == *(b._index);
}
friend bool operator==(const test_elem_base& a, int b)
{
return a._index != 0 && *(a._index) == b;
}
friend bool operator<(const test_elem_base& a, const test_elem_base& b)
{
return boost::less_pointees(a._index, b._index);
}
friend std::ostream& operator<<(std::ostream& out, const test_elem_base& elem)
{
if (elem._index) { out << *elem._index; }
else { out << "null"; }
return out;
}
template <typename Archive>
void serialize(Archive& ar, unsigned /* version */)
{
ar & *_index;
}
static bool no_living_elem()
{
return _live_count == 0;
}
private:
int* _index;
static int _live_count;
};
int test_elem_base::_live_count = 0;
struct regular_elem : test_elem_base
{
private:
BOOST_COPYABLE_AND_MOVABLE(regular_elem)
public:
regular_elem()
{}
regular_elem(int index) : test_elem_base(index) {}
regular_elem(const regular_elem& rhs)
:test_elem_base(rhs)
{}
regular_elem(BOOST_RV_REF(regular_elem) rhs)
:test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs))
{}
regular_elem &operator=(BOOST_COPY_ASSIGN_REF(regular_elem) rhs)
{
static_cast<test_elem_base&>(*this) = rhs;
return *this;
}
regular_elem &operator=(BOOST_RV_REF(regular_elem) rhs)
{
regular_elem &r = rhs;
static_cast<test_elem_base&>(*this) = boost::move(r);
return *this;
}
};
struct noex_move : test_elem_base
{
private:
BOOST_COPYABLE_AND_MOVABLE(noex_move)
public:
noex_move()
{}
noex_move(int index) : test_elem_base(index) {}
noex_move(const noex_move& rhs)
:test_elem_base(rhs)
{}
noex_move(BOOST_RV_REF(noex_move) rhs) BOOST_NOEXCEPT
:test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs))
{}
noex_move &operator=(BOOST_COPY_ASSIGN_REF(noex_move) rhs)
{
static_cast<test_elem_base&>(*this) = rhs;
return *this;
}
noex_move &operator=(BOOST_RV_REF(noex_move) rhs) BOOST_NOEXCEPT
{
noex_move & r = rhs;
static_cast<test_elem_base&>(*this) = boost::move(r);
return *this;
}
};
struct noex_copy : test_elem_base
{
private:
BOOST_COPYABLE_AND_MOVABLE(noex_copy)
public:
noex_copy(){}
noex_copy(int index) : test_elem_base(index) {}
noex_copy(const noex_copy& rhs) BOOST_NOEXCEPT
:test_elem_base(rhs)
{}
noex_copy(BOOST_RV_REF(noex_copy) rhs)
:test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs))
{}
noex_copy &operator=(BOOST_COPY_ASSIGN_REF(noex_copy) rhs) BOOST_NOEXCEPT
{
static_cast<test_elem_base&>(*this) = rhs;
return *this;
}
noex_copy &operator=(BOOST_RV_REF(noex_copy) rhs)
{
noex_copy &r = rhs;
static_cast<test_elem_base&>(*this) = boost::move(r);
return *this;
}
};
struct only_movable : test_elem_base
{
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE(only_movable)
public:
only_movable(){};
only_movable(int index) : test_elem_base(index) {}
only_movable(BOOST_RV_REF(only_movable) rhs)
:test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs))
{}
only_movable &operator=(BOOST_RV_REF(only_movable) rhs)
{
static_cast<test_elem_base&>(*this) = boost::move(rhs);
return *this;
}
};
struct no_default_ctor : test_elem_base
{
private:
BOOST_COPYABLE_AND_MOVABLE(no_default_ctor)
public:
no_default_ctor(int index) : test_elem_base(index) {}
no_default_ctor(const no_default_ctor& rhs)
:test_elem_base(rhs)
{}
no_default_ctor(BOOST_RV_REF(no_default_ctor) rhs)
:test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs))
{}
no_default_ctor &operator=(BOOST_RV_REF(no_default_ctor) rhs)
{
static_cast<test_elem_base&>(*this) = boost::move(rhs);
return *this;
}
no_default_ctor &operator=(BOOST_COPY_ASSIGN_REF(no_default_ctor) rhs)
{
static_cast<test_elem_base&>(*this) = rhs;
return *this;
}
};
}}
#endif //BOOST_CONTAINER_TEST_TEST_ELEM_HPP