forked from boostorg/unordered
		
	
		
			
				
	
	
		
			244 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|     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
 | |
| 
 | |
| /*************************************************************************************************/
 |