| /* |
| Copyright 2005-2007 Adobe Systems Incorporated |
| |
| Use, modification and distribution are subject to the Boost Software License, |
| Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| http://www.boost.org/LICENSE_1_0.txt). |
| */ |
| |
| /*************************************************************************************************/ |
| |
| #ifndef BOOST_UNORDERED_DETAIL_MOVE_HEADER |
| #define BOOST_UNORDERED_DETAIL_MOVE_HEADER |
| |
| #include <boost/config.hpp> |
| #include <boost/mpl/bool.hpp> |
| #include <boost/mpl/and.hpp> |
| #include <boost/mpl/or.hpp> |
| #include <boost/mpl/not.hpp> |
| #include <boost/type_traits/is_convertible.hpp> |
| #include <boost/type_traits/is_same.hpp> |
| #include <boost/type_traits/is_class.hpp> |
| #include <boost/utility/enable_if.hpp> |
| #include <boost/detail/workaround.hpp> |
| |
| /*************************************************************************************************/ |
| |
| #if defined(BOOST_NO_SFINAE) |
| # define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN |
| #elif defined(__GNUC__) && \ |
| (__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3) |
| # define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN |
| #elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \ |
| BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \ |
| BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593)) |
| # define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN |
| #endif |
| |
| /*************************************************************************************************/ |
| |
| namespace boost { |
| namespace unordered_detail { |
| |
| /*************************************************************************************************/ |
| |
| namespace move_detail { |
| |
| /*************************************************************************************************/ |
| |
| #if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN) |
| |
| /*************************************************************************************************/ |
| |
| template <typename T> |
| struct class_has_move_assign { |
| class type { |
| typedef T& (T::*E)(T t); |
| typedef char (&no_type)[1]; |
| typedef char (&yes_type)[2]; |
| template <E e> struct sfinae { typedef yes_type type; }; |
| template <class U> |
| static typename sfinae<&U::operator=>::type test(int); |
| template <class U> |
| static no_type test(...); |
| public: |
| enum {value = sizeof(test<T>(1)) == sizeof(yes_type)}; |
| }; |
| }; |
| |
| /*************************************************************************************************/ |
| |
| template<typename T> |
| struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {}; |
| |
| /*************************************************************************************************/ |
| |
| class test_can_convert_anything { }; |
| |
| /*************************************************************************************************/ |
| |
| #endif // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN |
| |
| /*************************************************************************************************/ |
| |
| /* |
| REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where |
| boost::is_convertible<T, T> fails to compile. |
| */ |
| |
| template <typename T, typename U> |
| struct is_convertible : boost::mpl::or_< |
| boost::is_same<T, U>, |
| boost::is_convertible<T, U> |
| > { }; |
| |
| /*************************************************************************************************/ |
| |
| } //namespace move_detail |
| |
| |
| /*************************************************************************************************/ |
| |
| /*! |
| \ingroup move_related |
| \brief move_from is used for move_ctors. |
| */ |
| |
| template <typename T> |
| struct move_from |
| { |
| explicit move_from(T& x) : source(x) { } |
| T& source; |
| private: |
| move_from& operator=(move_from const&); |
| }; |
| |
| /*************************************************************************************************/ |
| |
| #if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN) |
| |
| /*************************************************************************************************/ |
| |
| /*! |
| \ingroup move_related |
| \brief The is_movable trait can be used to identify movable types. |
| */ |
| template <typename T> |
| struct is_movable : boost::mpl::and_< |
| boost::is_convertible<move_from<T>, T>, |
| move_detail::has_move_assign<T>, |
| boost::mpl::not_<boost::is_convertible<move_detail::test_can_convert_anything, T> > |
| > { }; |
| |
| /*************************************************************************************************/ |
| |
| #else // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN |
| |
| // On compilers which don't have adequate SFINAE support, treat most types as unmovable, |
| // unless the trait is specialized. |
| |
| template <typename T> |
| struct is_movable : boost::mpl::false_ { }; |
| |
| #endif |
| |
| /*************************************************************************************************/ |
| |
| #if !defined(BOOST_NO_SFINAE) |
| |
| /*************************************************************************************************/ |
| |
| /*! |
| \ingroup move_related |
| \brief copy_sink and move_sink are used to select between overloaded operations according to |
| whether type T is movable and convertible to type U. |
| \sa move |
| */ |
| |
| template <typename T, |
| typename U = T, |
| typename R = void*> |
| struct copy_sink : boost::enable_if< |
| boost::mpl::and_< |
| boost::unordered_detail::move_detail::is_convertible<T, U>, |
| boost::mpl::not_<is_movable<T> > |
| >, |
| R |
| > |
| { }; |
| |
| /*************************************************************************************************/ |
| |
| /*! |
| \ingroup move_related |
| \brief move_sink and copy_sink are used to select between overloaded operations according to |
| whether type T is movable and convertible to type U. |
| \sa move |
| */ |
| |
| template <typename T, |
| typename U = T, |
| typename R = void*> |
| struct move_sink : boost::enable_if< |
| boost::mpl::and_< |
| boost::unordered_detail::move_detail::is_convertible<T, U>, |
| is_movable<T> |
| >, |
| R |
| > |
| { }; |
| |
| /*************************************************************************************************/ |
| |
| /*! |
| \ingroup move_related |
| \brief This version of move is selected when T is_movable . It in turn calls the move |
| constructor. This call, with the help of the return value optimization, will cause x to be moved |
| instead of copied to its destination. See adobe/test/move/main.cpp for examples. |
| |
| */ |
| template <typename T> |
| T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); } |
| |
| /*************************************************************************************************/ |
| |
| /*! |
| \ingroup move_related |
| \brief This version of move is selected when T is not movable . The net result will be that |
| x gets copied. |
| */ |
| template <typename T> |
| T& move(T& x, typename copy_sink<T>::type = 0) { return x; } |
| |
| /*************************************************************************************************/ |
| |
| #else // BOOST_NO_SFINAE |
| |
| // On compilers without SFINAE, define copy_sink to always use the copy function. |
| |
| template <typename T, |
| typename U = T, |
| typename R = void*> |
| struct copy_sink |
| { |
| typedef R type; |
| }; |
| |
| // Always copy the element unless this is overloaded. |
| |
| template <typename T> |
| T& move(T& x) { |
| return x; |
| } |
| |
| #endif // BOOST_NO_SFINAE |
| |
| } // namespace unordered_detail |
| } // namespace boost |
| |
| /*************************************************************************************************/ |
| |
| #endif |
| |
| /*************************************************************************************************/ |