00001
00002
00003
00004
00005
00006
00007
00008
00009 #ifndef ADOBE_MOVE_HPP
00010 #define ADOBE_MOVE_HPP
00011
00012 #include <cassert>
00013 #include <iterator>
00014 #include <memory>
00015
00016 #include <boost/iterator/iterator_adaptor.hpp>
00017 #include <boost/mpl/bool.hpp>
00018 #include <boost/mpl/and.hpp>
00019 #include <boost/mpl/or.hpp>
00020 #include <boost/mpl/not.hpp>
00021 #include <boost/mpl/assert.hpp>
00022 #include <boost/range/begin.hpp>
00023 #include <boost/range/end.hpp>
00024 #include <boost/type_traits/is_convertible.hpp>
00025 #include <boost/type_traits/is_same.hpp>
00026 #include <boost/type_traits/is_class.hpp>
00027 #include <boost/utility/enable_if.hpp>
00028
00247
00248
00249 namespace adobe {
00250
00251
00252
00253 namespace implementation {
00254
00255
00256
00257 template <typename T>
00258 struct class_has_move_assign {
00259 class type {
00260 typedef T& (T::*E)(T t);
00261 typedef char (&no_type)[1];
00262 typedef char (&yes_type)[2];
00263 template <E e> struct sfinae { typedef yes_type type; };
00264 template <class U>
00265 static typename sfinae<&U::operator=>::type test(int);
00266 template <class U>
00267 static no_type test(...);
00268 public:
00269 enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
00270 };
00271 };
00272
00273
00274
00275 template<typename T>
00276 struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};
00277
00278
00279
00280 class test_can_convert_anything { };
00281
00282
00283
00284 }
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 template <typename T, typename U>
00295 struct is_convertible : boost::mpl::or_<
00296 boost::is_same<T, U>,
00297 boost::is_convertible<T, U>
00298 > { };
00299
00305 template <typename T>
00306 struct move_from
00307 {
00308 explicit move_from(T& x) : source(x) { }
00309 T& source;
00310 };
00311
00316 template <typename T>
00317 struct is_movable : boost::mpl::and_<
00318 boost::is_convertible<move_from<T>, T>,
00319 implementation::has_move_assign<T>,
00320 boost::mpl::not_<boost::is_convertible<implementation::test_can_convert_anything, T> >
00321 > { };
00322
00323
00324
00332 template <typename T,
00333 typename U = T,
00334 typename R = void*>
00335 struct copy_sink : boost::enable_if<
00336 boost::mpl::and_<
00337 adobe::is_convertible<T, U>,
00338 boost::mpl::not_<is_movable<T> >
00339 >,
00340 R
00341 >
00342 { };
00343
00344
00345
00353 template <typename T,
00354 typename U = T,
00355 typename R = void*>
00356 struct move_sink : boost::enable_if<
00357 boost::mpl::and_<
00358 adobe::is_convertible<T, U>,
00359 is_movable<T>
00360 >,
00361 R
00362 >
00363 { };
00364
00365
00366
00374 template <typename T>
00375 T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }
00376
00377
00378
00384 template <typename T>
00385 T& move(T& x, typename copy_sink<T>::type = 0) { return x; }
00386
00387
00388
00394 template <typename I,
00395 typename O>
00396 O move(I f, I l, O result)
00397 {
00398 while (f != l) {
00399 *result = move(*f);
00400 ++f; ++result;
00401 }
00402 return result;
00403 }
00404
00405
00406
00412 template <typename I,
00413 typename O>
00414 inline O move(I& in, O out) { return move(boost::begin(in), boost::end(in), out); }
00415
00416
00417
00423 template <typename I,
00424 typename O>
00425 O move_backward(I f, I l, O result)
00426 {
00427 while (f != l) {
00428 --l; --result;
00429 *result = move(*l);
00430 }
00431 return result;
00432 }
00433
00434
00435
00441 template <typename I,
00442 typename O>
00443 inline O move_backward(I& in, O out)
00444 { return move_backward(boost::begin(in), boost::end(in), out); }
00445
00446
00447
00454 template <typename C>
00455 class back_move_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void>
00456 {
00457 C* container_m;
00458
00459 public:
00460 typedef C container_type;
00461
00462 explicit back_move_iterator(C& x) : container_m(&x) { }
00463
00464 back_move_iterator& operator=(typename C::value_type x)
00465 { container_m->push_back(move(x)); return *this; }
00466
00467 back_move_iterator& operator*() { return *this; }
00468 back_move_iterator& operator++() { return *this; }
00469 back_move_iterator& operator++(int) { return *this; }
00470 };
00471
00472
00473
00480 template <typename C>
00481 inline back_move_iterator<C> back_mover(C& x) { return back_move_iterator<C>(x); }
00482
00483
00484
00490 template <typename T, typename U>
00491 inline void move_construct(T* p, U& x, typename move_sink<U, T>::type = 0)
00492 {
00493 ::new(static_cast<void*>(p)) T(move(x));
00494 }
00495
00496
00497
00498
00503 template <typename T, typename U>
00504 inline void move_construct(T* p, const U& x, typename copy_sink<U, T>::type = 0)
00505 {
00506 ::new(static_cast<void*>(p)) T(x);
00507 }
00508
00509
00510
00516 template <typename I,
00517 typename F>
00518 F uninitialized_move(I f, I l, F r,
00519 typename move_sink<typename std::iterator_traits<I>::value_type>::type = 0)
00520 {
00521 while (f != l) {
00522 move_construct(&*r, *f);
00523 ++f; ++r;
00524 }
00525 return r;
00526 }
00527
00528
00529
00534 template <typename I,
00535 typename F>
00536 F uninitialized_move(I f, I l, F r,
00537 typename copy_sink<typename std::iterator_traits<I>::value_type>::type = 0)
00538 {
00539 return std::uninitialized_copy(f, l, r);
00540 }
00541
00542
00543
00544 }
00545
00546
00547
00548 #endif
00549
00550