1 // Copyright Louis Dionne 2013-2017 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 4 5 #ifndef TEST_SUPPORT_TRACKED_HPP 6 #define TEST_SUPPORT_TRACKED_HPP 7 8 // Define this if you want Tracked objects to print information to stderr. 9 // #define TRACKED_PRINT_STUFF 10 11 #include <boost/hana/assert.hpp> 12 13 #ifdef TRACKED_PRINT_STUFF 14 # include <iostream> 15 #endif 16 17 #include <iosfwd> 18 19 20 struct Tracked { 21 enum class State { CONSTRUCTED, MOVED_FROM, DESTROYED }; 22 23 int value; 24 State state; 25 TrackedTracked26 explicit Tracked(int k) : value{k}, state{State::CONSTRUCTED} { 27 #ifdef TRACKED_PRINT_STUFF 28 std::cerr << "constructing " << *this << '\n'; 29 #endif 30 } 31 TrackedTracked32 Tracked(Tracked const& t) : value{t.value}, state{State::CONSTRUCTED} { 33 BOOST_HANA_RUNTIME_CHECK(t.state != State::MOVED_FROM && 34 "copying a moved-from object"); 35 36 BOOST_HANA_RUNTIME_CHECK(t.state != State::DESTROYED && 37 "copying a destroyed object"); 38 39 #ifdef TRACKED_PRINT_STUFF 40 std::cerr << "copying " << *this << '\n'; 41 #endif 42 } 43 TrackedTracked44 Tracked(Tracked&& t) : value{t.value}, state{State::CONSTRUCTED} { 45 BOOST_HANA_RUNTIME_CHECK(t.state != State::MOVED_FROM && 46 "double moving from an object"); 47 48 BOOST_HANA_RUNTIME_CHECK(t.state != State::DESTROYED && 49 "moving from a destroyed object"); 50 51 #ifdef TRACKED_PRINT_STUFF 52 std::cerr << "moving " << t << '\n'; 53 #endif 54 t.state = State::MOVED_FROM; 55 } 56 operator =Tracked57 Tracked& operator=(Tracked const& other) { 58 BOOST_HANA_RUNTIME_CHECK(this->state != State::DESTROYED && 59 "assigning to a destroyed object"); 60 61 BOOST_HANA_RUNTIME_CHECK(other.state != State::MOVED_FROM && 62 "assigning a moved-from object"); 63 64 BOOST_HANA_RUNTIME_CHECK(other.state != State::DESTROYED && 65 "assigning a destroyed object"); 66 67 #ifdef TRACKED_PRINT_STUFF 68 std::cerr << "assigning " << other << " to " << *this << '\n'; 69 #endif 70 this->value = other.value; 71 return *this; 72 } 73 operator =Tracked74 Tracked& operator=(Tracked&& other) { 75 BOOST_HANA_RUNTIME_CHECK(this->state != State::DESTROYED && 76 "assigning to a destroyed object"); 77 78 BOOST_HANA_RUNTIME_CHECK(other.state != State::MOVED_FROM && 79 "double-moving from an object"); 80 81 BOOST_HANA_RUNTIME_CHECK(other.state != State::DESTROYED && 82 "assigning a destroyed object"); 83 84 #ifdef TRACKED_PRINT_STUFF 85 std::cerr << "assigning " << other << " to " << *this << '\n'; 86 #endif 87 this->value = other.value; 88 other.state = State::MOVED_FROM; 89 return *this; 90 } 91 ~TrackedTracked92 ~Tracked() { 93 BOOST_HANA_RUNTIME_CHECK(state != State::DESTROYED && 94 "double-destroying an object"); 95 96 #ifdef TRACKED_PRINT_STUFF 97 std::cerr << "destructing " << *this << '\n'; 98 #endif 99 state = State::DESTROYED; 100 } 101 102 template <typename CharT, typename Traits> 103 friend std::basic_ostream<CharT, Traits>& operator <<(std::basic_ostream<CharT,Traits> & os,Tracked const & t)104 operator<<(std::basic_ostream<CharT, Traits>& os, Tracked const& t) { 105 os << "Tracked{" << t.value << "}"; 106 switch (t.state) { 107 case State::CONSTRUCTED: 108 os << "[ok]"; break; 109 case State::MOVED_FROM: 110 os << "[moved from]"; break; 111 case State::DESTROYED: 112 os << "[destroyed]"; break; 113 default: 114 BOOST_HANA_RUNTIME_CHECK(false && "never reached"); 115 } 116 return os; 117 } 118 }; 119 120 #endif // !TEST_SUPPORT_TRACKED_HPP 121