Brian Silverman | 1f5d398 | 2018-08-04 23:37:52 -0700 | [diff] [blame^] | 1 | ////////////////////////////////////////////////////////////////////////////// |
| 2 | // |
| 3 | // (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2010-2012. |
| 4 | // Distributed under the Boost Software License, Version 1.0. |
| 5 | // (See accompanying file LICENSE_1_0.txt or copy at |
| 6 | // http://www.boost.org/LICENSE_1_0.txt) |
| 7 | // |
| 8 | // See http://www.boost.org/libs/move for documentation. |
| 9 | // |
| 10 | ////////////////////////////////////////////////////////////////////////////// |
| 11 | #include <boost/move/utility_core.hpp> |
| 12 | #include <boost/move/detail/meta_utils.hpp> |
| 13 | #include <cassert> |
| 14 | #include <new> |
| 15 | #include <boost/move/detail/move_helpers.hpp> |
| 16 | |
| 17 | |
| 18 | enum ConstructionType { Copied, Moved, Other }; |
| 19 | |
| 20 | class conversion_source |
| 21 | { |
| 22 | public: |
| 23 | conversion_source(){} |
| 24 | operator int() const { return 0; } |
| 25 | }; |
| 26 | |
| 27 | class conversion_target |
| 28 | { |
| 29 | ConstructionType c_type_; |
| 30 | public: |
| 31 | conversion_target(conversion_source) |
| 32 | { c_type_ = Other; } |
| 33 | conversion_target() |
| 34 | { c_type_ = Other; } |
| 35 | conversion_target(const conversion_target &) |
| 36 | { c_type_ = Copied; } |
| 37 | ConstructionType construction_type() const |
| 38 | { return c_type_; } |
| 39 | }; |
| 40 | |
| 41 | |
| 42 | class conversion_target_copymovable |
| 43 | { |
| 44 | ConstructionType c_type_; |
| 45 | BOOST_COPYABLE_AND_MOVABLE(conversion_target_copymovable) |
| 46 | public: |
| 47 | conversion_target_copymovable() |
| 48 | { c_type_ = Other; } |
| 49 | conversion_target_copymovable(conversion_source) |
| 50 | { c_type_ = Other; } |
| 51 | conversion_target_copymovable(const conversion_target_copymovable &) |
| 52 | { c_type_ = Copied; } |
| 53 | conversion_target_copymovable(BOOST_RV_REF(conversion_target_copymovable) ) |
| 54 | { c_type_ = Moved; } |
| 55 | conversion_target_copymovable &operator=(BOOST_RV_REF(conversion_target_copymovable) ) |
| 56 | { c_type_ = Moved; return *this; } |
| 57 | conversion_target_copymovable &operator=(BOOST_COPY_ASSIGN_REF(conversion_target_copymovable) ) |
| 58 | { c_type_ = Copied; return *this; } |
| 59 | ConstructionType construction_type() const |
| 60 | { return c_type_; } |
| 61 | }; |
| 62 | |
| 63 | class conversion_target_movable |
| 64 | { |
| 65 | ConstructionType c_type_; |
| 66 | BOOST_MOVABLE_BUT_NOT_COPYABLE(conversion_target_movable) |
| 67 | public: |
| 68 | conversion_target_movable() |
| 69 | { c_type_ = Other; } |
| 70 | conversion_target_movable(conversion_source) |
| 71 | { c_type_ = Other; } |
| 72 | conversion_target_movable(BOOST_RV_REF(conversion_target_movable) ) |
| 73 | { c_type_ = Moved; } |
| 74 | conversion_target_movable &operator=(BOOST_RV_REF(conversion_target_movable) ) |
| 75 | { c_type_ = Moved; return *this; } |
| 76 | ConstructionType construction_type() const |
| 77 | { return c_type_; } |
| 78 | }; |
| 79 | |
| 80 | |
| 81 | template<class T> |
| 82 | class container |
| 83 | { |
| 84 | T *storage_; |
| 85 | public: |
| 86 | struct const_iterator{}; |
| 87 | struct iterator : const_iterator{}; |
| 88 | container() |
| 89 | : storage_(0) |
| 90 | {} |
| 91 | |
| 92 | ~container() |
| 93 | { delete storage_; } |
| 94 | |
| 95 | container(const container &c) |
| 96 | : storage_(c.storage_ ? new T(*c.storage_) : 0) |
| 97 | {} |
| 98 | |
| 99 | container &operator=(const container &c) |
| 100 | { |
| 101 | if(storage_){ |
| 102 | delete storage_; |
| 103 | storage_ = 0; |
| 104 | } |
| 105 | storage_ = c.storage_ ? new T(*c.storage_) : 0; |
| 106 | return *this; |
| 107 | } |
| 108 | |
| 109 | BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) |
| 110 | |
| 111 | BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator, const_iterator) |
| 112 | |
| 113 | template <class Iterator> |
| 114 | iterator insert(Iterator, Iterator){ return iterator(); } |
| 115 | |
| 116 | ConstructionType construction_type() const |
| 117 | { return construction_type_impl |
| 118 | (typename ::boost::move_detail::integral_constant<bool, ::boost::move_detail::is_class_or_union<T>::value>()); |
| 119 | } |
| 120 | |
| 121 | ConstructionType construction_type_impl(::boost::move_detail::true_type) const |
| 122 | { return storage_->construction_type(); } |
| 123 | |
| 124 | ConstructionType construction_type_impl(::boost::move_detail::false_type) const |
| 125 | { return Copied; } |
| 126 | |
| 127 | iterator begin() const { return iterator(); } |
| 128 | |
| 129 | private: |
| 130 | template<class U> |
| 131 | void priv_construct(BOOST_MOVE_CATCH_FWD(U) x) |
| 132 | { |
| 133 | if(storage_){ |
| 134 | delete storage_; |
| 135 | storage_ = 0; |
| 136 | } |
| 137 | storage_ = new T(::boost::forward<U>(x)); |
| 138 | } |
| 139 | |
| 140 | template<class U> |
| 141 | void priv_push_back(BOOST_MOVE_CATCH_FWD(U) x) |
| 142 | { priv_construct(::boost::forward<U>(x)); } |
| 143 | |
| 144 | template<class U> |
| 145 | iterator priv_insert(const_iterator, BOOST_MOVE_CATCH_FWD(U) x) |
| 146 | { priv_construct(::boost::forward<U>(x)); return iterator(); } |
| 147 | }; |
| 148 | |
| 149 | class recursive_container |
| 150 | { |
| 151 | BOOST_COPYABLE_AND_MOVABLE(recursive_container) |
| 152 | public: |
| 153 | recursive_container() |
| 154 | {} |
| 155 | |
| 156 | recursive_container(const recursive_container &c) |
| 157 | : container_(c.container_) |
| 158 | {} |
| 159 | |
| 160 | recursive_container(BOOST_RV_REF(recursive_container) c) |
| 161 | : container_(::boost::move(c.container_)) |
| 162 | {} |
| 163 | |
| 164 | recursive_container & operator =(BOOST_COPY_ASSIGN_REF(recursive_container) c) |
| 165 | { |
| 166 | container_= c.container_; |
| 167 | return *this; |
| 168 | } |
| 169 | |
| 170 | recursive_container & operator =(BOOST_RV_REF(recursive_container) c) |
| 171 | { |
| 172 | container_= ::boost::move(c.container_); |
| 173 | return *this; |
| 174 | } |
| 175 | |
| 176 | container<recursive_container> container_; |
| 177 | friend bool operator< (const recursive_container &a, const recursive_container &b) |
| 178 | { return &a < &b; } |
| 179 | }; |
| 180 | |
| 181 | |
| 182 | int main() |
| 183 | { |
| 184 | conversion_target_movable a; |
| 185 | conversion_target_movable b(::boost::move(a)); |
| 186 | { |
| 187 | container<conversion_target> c; |
| 188 | { |
| 189 | conversion_target x; |
| 190 | c.push_back(x); |
| 191 | assert(c.construction_type() == Copied); |
| 192 | c.insert(c.begin(), x); |
| 193 | assert(c.construction_type() == Copied); |
| 194 | } |
| 195 | { |
| 196 | const conversion_target x; |
| 197 | c.push_back(x); |
| 198 | assert(c.construction_type() == Copied); |
| 199 | c.insert(c.begin(), x); |
| 200 | assert(c.construction_type() == Copied); |
| 201 | } |
| 202 | { |
| 203 | c.push_back(conversion_target()); |
| 204 | assert(c.construction_type() == Copied); |
| 205 | c.insert(c.begin(), conversion_target()); |
| 206 | assert(c.construction_type() == Copied); |
| 207 | } |
| 208 | { |
| 209 | conversion_source x; |
| 210 | c.push_back(x); |
| 211 | assert(c.construction_type() == Copied); |
| 212 | c.insert(c.begin(), x); |
| 213 | assert(c.construction_type() == Copied); |
| 214 | } |
| 215 | { |
| 216 | const conversion_source x; |
| 217 | c.push_back(x); |
| 218 | assert(c.construction_type() == Copied); |
| 219 | c.insert(c.begin(), x); |
| 220 | assert(c.construction_type() == Copied); |
| 221 | } |
| 222 | { |
| 223 | c.push_back(conversion_source()); |
| 224 | assert(c.construction_type() == Copied); |
| 225 | c.insert(c.begin(), conversion_source()); |
| 226 | assert(c.construction_type() == Copied); |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | { |
| 231 | container<conversion_target_copymovable> c; |
| 232 | { |
| 233 | conversion_target_copymovable x; |
| 234 | c.push_back(x); |
| 235 | assert(c.construction_type() == Copied); |
| 236 | c.insert(c.begin(), x); |
| 237 | assert(c.construction_type() == Copied); |
| 238 | } |
| 239 | { |
| 240 | const conversion_target_copymovable x; |
| 241 | c.push_back(x); |
| 242 | assert(c.construction_type() == Copied); |
| 243 | c.insert(c.begin(), x); |
| 244 | assert(c.construction_type() == Copied); |
| 245 | } |
| 246 | { |
| 247 | c.push_back(conversion_target_copymovable()); |
| 248 | assert(c.construction_type() == Moved); |
| 249 | c.insert(c.begin(), conversion_target_copymovable()); |
| 250 | assert(c.construction_type() == Moved); |
| 251 | } |
| 252 | { |
| 253 | conversion_source x; |
| 254 | c.push_back(x); |
| 255 | assert(c.construction_type() == Moved); |
| 256 | c.insert(c.begin(), x); |
| 257 | assert(c.construction_type() == Moved); |
| 258 | } |
| 259 | { |
| 260 | const conversion_source x; |
| 261 | c.push_back(x); |
| 262 | assert(c.construction_type() == Moved); |
| 263 | c.insert(c.begin(), x); |
| 264 | assert(c.construction_type() == Moved); |
| 265 | } |
| 266 | { |
| 267 | c.push_back(conversion_source()); |
| 268 | assert(c.construction_type() == Moved); |
| 269 | c.insert(c.begin(), conversion_source()); |
| 270 | assert(c.construction_type() == Moved); |
| 271 | } |
| 272 | } |
| 273 | { |
| 274 | container<conversion_target_movable> c; |
| 275 | //This should not compile |
| 276 | //{ |
| 277 | // conversion_target_movable x; |
| 278 | // c.push_back(x); |
| 279 | // assert(c.construction_type() == Copied); |
| 280 | //} |
| 281 | //{ |
| 282 | // const conversion_target_movable x; |
| 283 | // c.push_back(x); |
| 284 | // assert(c.construction_type() == Copied); |
| 285 | //} |
| 286 | { |
| 287 | c.push_back(conversion_target_movable()); |
| 288 | assert(c.construction_type() == Moved); |
| 289 | c.insert(c.begin(), conversion_target_movable()); |
| 290 | assert(c.construction_type() == Moved); |
| 291 | } |
| 292 | { |
| 293 | conversion_source x; |
| 294 | c.push_back(x); |
| 295 | assert(c.construction_type() == Moved); |
| 296 | c.insert(c.begin(), x); |
| 297 | assert(c.construction_type() == Moved); |
| 298 | } |
| 299 | { |
| 300 | const conversion_source x; |
| 301 | c.push_back(x); |
| 302 | assert(c.construction_type() == Moved); |
| 303 | c.insert(c.begin(), x); |
| 304 | assert(c.construction_type() == Moved); |
| 305 | } |
| 306 | { |
| 307 | c.push_back(conversion_source()); |
| 308 | assert(c.construction_type() == Moved); |
| 309 | c.insert(c.begin(), conversion_source()); |
| 310 | assert(c.construction_type() == Moved); |
| 311 | } |
| 312 | } |
| 313 | { |
| 314 | container<int> c; |
| 315 | { |
| 316 | int x = 0; |
| 317 | c.push_back(x); |
| 318 | assert(c.construction_type() == Copied); |
| 319 | c.insert(c.begin(), c.construction_type()); |
| 320 | assert(c.construction_type() == Copied); |
| 321 | } |
| 322 | { |
| 323 | const int x = 0; |
| 324 | c.push_back(x); |
| 325 | assert(c.construction_type() == Copied); |
| 326 | c.insert(c.begin(), x); |
| 327 | assert(c.construction_type() == Copied); |
| 328 | } |
| 329 | { |
| 330 | c.push_back(int(0)); |
| 331 | assert(c.construction_type() == Copied); |
| 332 | c.insert(c.begin(), int(0)); |
| 333 | assert(c.construction_type() == Copied); |
| 334 | } |
| 335 | { |
| 336 | conversion_source x; |
| 337 | c.push_back(x); |
| 338 | assert(c.construction_type() == Copied); |
| 339 | c.insert(c.begin(), x); |
| 340 | assert(c.construction_type() == Copied); |
| 341 | } |
| 342 | |
| 343 | { |
| 344 | const conversion_source x; |
| 345 | c.push_back(x); |
| 346 | assert(c.construction_type() == Copied); |
| 347 | c.insert(c.begin(), x); |
| 348 | assert(c.construction_type() == Copied); |
| 349 | } |
| 350 | { |
| 351 | c.push_back(conversion_source()); |
| 352 | assert(c.construction_type() == Copied); |
| 353 | c.insert(c.begin(), conversion_source()); |
| 354 | assert(c.construction_type() == Copied); |
| 355 | } |
| 356 | //c.insert(c.begin(), c.begin()); |
| 357 | } |
| 358 | |
| 359 | { |
| 360 | container<int> c; |
| 361 | { |
| 362 | int x = 0; |
| 363 | c.push_back(x); |
| 364 | assert(c.construction_type() == Copied); |
| 365 | c.insert(c.begin(), c.construction_type()); |
| 366 | assert(c.construction_type() == Copied); |
| 367 | } |
| 368 | { |
| 369 | const int x = 0; |
| 370 | c.push_back(x); |
| 371 | assert(c.construction_type() == Copied); |
| 372 | c.insert(c.begin(), x); |
| 373 | assert(c.construction_type() == Copied); |
| 374 | } |
| 375 | { |
| 376 | c.push_back(int(0)); |
| 377 | assert(c.construction_type() == Copied); |
| 378 | c.insert(c.begin(), int(0)); |
| 379 | assert(c.construction_type() == Copied); |
| 380 | } |
| 381 | { |
| 382 | conversion_source x; |
| 383 | c.push_back(x); |
| 384 | assert(c.construction_type() == Copied); |
| 385 | c.insert(c.begin(), x); |
| 386 | assert(c.construction_type() == Copied); |
| 387 | } |
| 388 | |
| 389 | { |
| 390 | const conversion_source x; |
| 391 | c.push_back(x); |
| 392 | assert(c.construction_type() == Copied); |
| 393 | c.insert(c.begin(), x); |
| 394 | assert(c.construction_type() == Copied); |
| 395 | } |
| 396 | { |
| 397 | c.push_back(conversion_source()); |
| 398 | assert(c.construction_type() == Copied); |
| 399 | c.insert(c.begin(), conversion_source()); |
| 400 | assert(c.construction_type() == Copied); |
| 401 | } |
| 402 | c.insert(c.begin(), c.begin()); |
| 403 | } |
| 404 | |
| 405 | { |
| 406 | recursive_container c; |
| 407 | recursive_container internal; |
| 408 | c.container_.insert(c.container_.begin(), recursive_container()); |
| 409 | c.container_.insert(c.container_.begin(), internal); |
| 410 | c.container_.insert(c.container_.begin(), c.container_.begin()); |
| 411 | } |
| 412 | |
| 413 | return 0; |
| 414 | } |