1 ////////////////////////////////////////////////////////////////////////////// 2 // 3 // \(C\) Copyright Benedek Thaler 2015-2016 4 // \(C\) Copyright Ion Gaztanaga 2019-2020. Distributed under the Boost 5 // Software License, Version 1.0. (See accompanying file 6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 // 8 // See http://erenon.hu/double_ended for documentation. 9 // 10 ////////////////////////////////////////////////////////////////////////////// 11 12 #ifndef BOOST_CONTAINER_TEST_TEST_ELEM_HPP 13 #define BOOST_CONTAINER_TEST_TEST_ELEM_HPP 14 15 #include <boost/utility/compare_pointees.hpp> 16 #include <cstdlib> 17 18 namespace boost { 19 namespace container { 20 21 struct test_exception {}; 22 23 struct test_elem_throw 24 { 25 private: 26 static int throw_on_ctor_after /*= -1*/; 27 static int throw_on_copy_after /*= -1*/; 28 static int throw_on_move_after /*= -1*/; 29 30 public: on_ctor_afterboost::container::test_elem_throw31 static void on_ctor_after(int x) { throw_on_ctor_after = x; } on_copy_afterboost::container::test_elem_throw32 static void on_copy_after(int x) { throw_on_copy_after = x; } on_move_afterboost::container::test_elem_throw33 static void on_move_after(int x) { throw_on_move_after = x; } 34 do_not_throwboost::container::test_elem_throw35 static void do_not_throw() 36 { 37 throw_on_ctor_after = -1; 38 throw_on_copy_after = -1; 39 throw_on_move_after = -1; 40 } 41 in_constructorboost::container::test_elem_throw42 static void in_constructor() { maybe_throw(throw_on_ctor_after); } in_copyboost::container::test_elem_throw43 static void in_copy() { maybe_throw(throw_on_copy_after); } in_moveboost::container::test_elem_throw44 static void in_move() { maybe_throw(throw_on_move_after); } 45 46 private: maybe_throwboost::container::test_elem_throw47 static void maybe_throw(int& counter) 48 { 49 if (counter > 0) 50 { 51 --counter; 52 if (counter == 0) 53 { 54 --counter; 55 #ifndef BOOST_NO_EXCEPTIONS 56 throw test_exception(); 57 #else 58 std::abort(); 59 #endif 60 } 61 } 62 } 63 }; 64 65 int test_elem_throw::throw_on_ctor_after = -1; 66 int test_elem_throw::throw_on_copy_after = -1; 67 int test_elem_throw::throw_on_move_after = -1; 68 69 struct test_elem_base 70 { 71 private: 72 BOOST_COPYABLE_AND_MOVABLE(test_elem_base) 73 74 public: test_elem_baseboost::container::test_elem_base75 test_elem_base() 76 { 77 test_elem_throw::in_constructor(); 78 _index = new int(0); 79 ++_live_count; 80 } 81 test_elem_baseboost::container::test_elem_base82 test_elem_base(int index) 83 { 84 test_elem_throw::in_constructor(); 85 _index = new int(index); 86 ++_live_count; 87 } 88 test_elem_baseboost::container::test_elem_base89 explicit test_elem_base(const test_elem_base& rhs) 90 { 91 test_elem_throw::in_copy(); 92 _index = new int(*rhs._index); 93 ++_live_count; 94 } 95 test_elem_baseboost::container::test_elem_base96 test_elem_base(BOOST_RV_REF(test_elem_base) rhs) 97 { 98 test_elem_throw::in_move(); 99 _index = rhs._index; 100 rhs._index = 0; 101 ++_live_count; 102 } 103 operator =boost::container::test_elem_base104 test_elem_base &operator=(BOOST_COPY_ASSIGN_REF(test_elem_base) rhs) 105 { 106 test_elem_throw::in_copy(); 107 if (_index) { delete _index; } 108 _index = new int(*rhs._index); 109 return *this; 110 } 111 operator =boost::container::test_elem_base112 test_elem_base &operator=(BOOST_RV_REF(test_elem_base) rhs) 113 { 114 test_elem_throw::in_move(); 115 if (_index) { delete _index; } 116 _index = rhs._index; 117 rhs._index = 0; 118 return *this; 119 } 120 ~test_elem_baseboost::container::test_elem_base121 ~test_elem_base() 122 { 123 if (_index) { delete _index; } 124 --_live_count; 125 } 126 operator ==(const test_elem_base & a,const test_elem_base & b)127 friend bool operator==(const test_elem_base& a, const test_elem_base& b) 128 { 129 return a._index && b._index && *(a._index) == *(b._index); 130 } 131 operator ==(int a,const test_elem_base & b)132 friend bool operator==(int a, const test_elem_base& b) 133 { 134 return b._index != 0 && a == *(b._index); 135 } 136 operator ==(const test_elem_base & a,int b)137 friend bool operator==(const test_elem_base& a, int b) 138 { 139 return a._index != 0 && *(a._index) == b; 140 } 141 operator <(const test_elem_base & a,const test_elem_base & b)142 friend bool operator<(const test_elem_base& a, const test_elem_base& b) 143 { 144 return boost::less_pointees(a._index, b._index); 145 } 146 operator <<(std::ostream & out,const test_elem_base & elem)147 friend std::ostream& operator<<(std::ostream& out, const test_elem_base& elem) 148 { 149 if (elem._index) { out << *elem._index; } 150 else { out << "null"; } 151 return out; 152 } 153 154 template <typename Archive> serializeboost::container::test_elem_base155 void serialize(Archive& ar, unsigned /* version */) 156 { 157 ar & *_index; 158 } 159 no_living_elemboost::container::test_elem_base160 static bool no_living_elem() 161 { 162 return _live_count == 0; 163 } 164 165 private: 166 int* _index; 167 168 static int _live_count; 169 }; 170 171 int test_elem_base::_live_count = 0; 172 173 struct regular_elem : test_elem_base 174 { 175 private: 176 BOOST_COPYABLE_AND_MOVABLE(regular_elem) 177 178 public: regular_elemboost::container::regular_elem179 regular_elem() 180 {} 181 regular_elemboost::container::regular_elem182 regular_elem(int index) : test_elem_base(index) {} 183 regular_elemboost::container::regular_elem184 regular_elem(const regular_elem& rhs) 185 :test_elem_base(rhs) 186 {} 187 regular_elemboost::container::regular_elem188 regular_elem(BOOST_RV_REF(regular_elem) rhs) 189 :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) 190 {} 191 operator =boost::container::regular_elem192 regular_elem &operator=(BOOST_COPY_ASSIGN_REF(regular_elem) rhs) 193 { 194 static_cast<test_elem_base&>(*this) = rhs; 195 return *this; 196 } 197 operator =boost::container::regular_elem198 regular_elem &operator=(BOOST_RV_REF(regular_elem) rhs) 199 { 200 regular_elem &r = rhs; 201 static_cast<test_elem_base&>(*this) = boost::move(r); 202 return *this; 203 } 204 }; 205 206 struct noex_move : test_elem_base 207 { 208 private: 209 BOOST_COPYABLE_AND_MOVABLE(noex_move) 210 211 public: noex_moveboost::container::noex_move212 noex_move() 213 {} 214 noex_moveboost::container::noex_move215 noex_move(int index) : test_elem_base(index) {} 216 noex_moveboost::container::noex_move217 noex_move(const noex_move& rhs) 218 :test_elem_base(rhs) 219 {} 220 noex_moveboost::container::noex_move221 noex_move(BOOST_RV_REF(noex_move) rhs) BOOST_NOEXCEPT 222 :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) 223 {} 224 operator =boost::container::noex_move225 noex_move &operator=(BOOST_COPY_ASSIGN_REF(noex_move) rhs) 226 { 227 static_cast<test_elem_base&>(*this) = rhs; 228 return *this; 229 } 230 operator =boost::container::noex_move231 noex_move &operator=(BOOST_RV_REF(noex_move) rhs) BOOST_NOEXCEPT 232 { 233 noex_move & r = rhs; 234 static_cast<test_elem_base&>(*this) = boost::move(r); 235 return *this; 236 } 237 }; 238 239 struct noex_copy : test_elem_base 240 { 241 private: 242 BOOST_COPYABLE_AND_MOVABLE(noex_copy) 243 244 public: noex_copyboost::container::noex_copy245 noex_copy(){} 246 noex_copyboost::container::noex_copy247 noex_copy(int index) : test_elem_base(index) {} 248 noex_copyboost::container::noex_copy249 noex_copy(const noex_copy& rhs) BOOST_NOEXCEPT 250 :test_elem_base(rhs) 251 {} 252 noex_copyboost::container::noex_copy253 noex_copy(BOOST_RV_REF(noex_copy) rhs) 254 :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) 255 {} 256 operator =boost::container::noex_copy257 noex_copy &operator=(BOOST_COPY_ASSIGN_REF(noex_copy) rhs) BOOST_NOEXCEPT 258 { 259 static_cast<test_elem_base&>(*this) = rhs; 260 return *this; 261 } 262 operator =boost::container::noex_copy263 noex_copy &operator=(BOOST_RV_REF(noex_copy) rhs) 264 { 265 noex_copy &r = rhs; 266 static_cast<test_elem_base&>(*this) = boost::move(r); 267 return *this; 268 } 269 }; 270 271 struct only_movable : test_elem_base 272 { 273 private: 274 BOOST_MOVABLE_BUT_NOT_COPYABLE(only_movable) 275 276 public: only_movableboost::container::only_movable277 only_movable(){}; 278 only_movableboost::container::only_movable279 only_movable(int index) : test_elem_base(index) {} 280 only_movableboost::container::only_movable281 only_movable(BOOST_RV_REF(only_movable) rhs) 282 :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) 283 {} 284 operator =boost::container::only_movable285 only_movable &operator=(BOOST_RV_REF(only_movable) rhs) 286 { 287 static_cast<test_elem_base&>(*this) = boost::move(rhs); 288 return *this; 289 } 290 }; 291 292 struct no_default_ctor : test_elem_base 293 { 294 295 private: 296 BOOST_COPYABLE_AND_MOVABLE(no_default_ctor) 297 298 public: no_default_ctorboost::container::no_default_ctor299 no_default_ctor(int index) : test_elem_base(index) {} 300 no_default_ctorboost::container::no_default_ctor301 no_default_ctor(const no_default_ctor& rhs) 302 :test_elem_base(rhs) 303 {} 304 no_default_ctorboost::container::no_default_ctor305 no_default_ctor(BOOST_RV_REF(no_default_ctor) rhs) 306 :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) 307 {} 308 operator =boost::container::no_default_ctor309 no_default_ctor &operator=(BOOST_RV_REF(no_default_ctor) rhs) 310 { 311 static_cast<test_elem_base&>(*this) = boost::move(rhs); 312 return *this; 313 } 314 operator =boost::container::no_default_ctor315 no_default_ctor &operator=(BOOST_COPY_ASSIGN_REF(no_default_ctor) rhs) 316 { 317 static_cast<test_elem_base&>(*this) = rhs; 318 return *this; 319 } 320 }; 321 322 }} 323 324 #endif //BOOST_CONTAINER_TEST_TEST_ELEM_HPP 325