move.hpp
Go to the documentation of this file.
00001 /* 00002 Copyright 2005-2007 Adobe Systems Incorporated 00003 Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt 00004 or a copy at http://stlab.adobe.com/licenses.html) 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 } //namespace implementation 00285 00286 00287 /*************************************************************************************************/ 00288 00289 /* 00290 REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where 00291 boost::is_convertible<T, T> fails to compile. 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, // I models InputIterator 00395 typename O> // O models OutputIterator 00396 O move(I f, I l, O result) 00397 { 00398 while (f != l) { 00399 *result = adobe::move(*f); 00400 ++f; ++result; 00401 } 00402 return result; 00403 } 00404 00405 /*************************************************************************************************/ 00406 00412 template <typename I, // I models InputRange 00413 typename O> // O models OutputIterator 00414 inline O move(I& in, O out) { return adobe::move(boost::begin(in), boost::end(in), out); } 00415 00416 /*************************************************************************************************/ 00417 00423 template <typename I, // I models BidirectionalIterator 00424 typename O> // O models BidirectionalIterator 00425 O move_backward(I f, I l, O result) 00426 { 00427 while (f != l) { 00428 --l; --result; 00429 *result = adobe::move(*l); 00430 } 00431 return result; 00432 } 00433 00434 /*************************************************************************************************/ 00435 00441 template <typename I, // I models BidirectionalRange 00442 typename O> // O models BidirectionalIterator 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> // C models Container 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(adobe::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> // C models Container 00481 inline back_move_iterator<C> back_mover(C& x) { return back_move_iterator<C>(x); } 00482 00483 /*************************************************************************************************/ 00484 00485 } // namespace adobe 00486 00487 /*************************************************************************************************/ 00488 00489 #endif 00490 00491 /*************************************************************************************************/ |