////////////////////////////////////////////////////////////////////////////// // // \(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 #include 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 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(*this) = rhs; return *this; } regular_elem &operator=(BOOST_RV_REF(regular_elem) rhs) { regular_elem &r = rhs; static_cast(*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(*this) = rhs; return *this; } noex_move &operator=(BOOST_RV_REF(noex_move) rhs) BOOST_NOEXCEPT { noex_move & r = rhs; static_cast(*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(*this) = rhs; return *this; } noex_copy &operator=(BOOST_RV_REF(noex_copy) rhs) { noex_copy &r = rhs; static_cast(*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(*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(*this) = boost::move(rhs); return *this; } no_default_ctor &operator=(BOOST_COPY_ASSIGN_REF(no_default_ctor) rhs) { static_cast(*this) = rhs; return *this; } }; }} #endif //BOOST_CONTAINER_TEST_TEST_ELEM_HPP