1 /*
2     Copyright 2005-2007 Adobe Systems Incorporated
3 
4     Use, modification and distribution are subject to the Boost Software License,
5     Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6     http://www.boost.org/LICENSE_1_0.txt).
7 */
8 
9 /*************************************************************************************************/
10 
11 #ifndef BOOST_UNORDERED_DETAIL_MOVE_HEADER
12 #define BOOST_UNORDERED_DETAIL_MOVE_HEADER
13 
14 #include <boost/config.hpp>
15 #include <boost/mpl/bool.hpp>
16 #include <boost/mpl/and.hpp>
17 #include <boost/mpl/or.hpp>
18 #include <boost/mpl/not.hpp>
19 #include <boost/type_traits/is_convertible.hpp>
20 #include <boost/type_traits/is_same.hpp>
21 #include <boost/type_traits/is_class.hpp>
22 #include <boost/utility/enable_if.hpp>
23 #include <boost/detail/workaround.hpp>
24 
25 /*************************************************************************************************/
26 
27 #if defined(BOOST_NO_SFINAE)
28 #  define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
29 #elif defined(__GNUC__) && \
30     (__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
31 #  define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
32 #elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \
33     BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \
34     BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593))
35 #  define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
36 #endif
37 
38 /*************************************************************************************************/
39 
40 namespace boost {
41 namespace unordered_detail {
42 
43 /*************************************************************************************************/
44 
45 namespace move_detail {
46 
47 /*************************************************************************************************/
48 
49 #if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
50 
51 /*************************************************************************************************/
52 
53 template <typename T>
54 struct class_has_move_assign {
55     class type {
56         typedef T& (T::*E)(T t);
57         typedef char (&no_type)[1];
58         typedef char (&yes_type)[2];
59         template <E e> struct sfinae { typedef yes_type type; };
60         template <class U>
61         static typename sfinae<&U::operator=>::type test(int);
62         template <class U>
63         static no_type test(...);
64     public:
65         enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
66     };
67  };
68 
69 /*************************************************************************************************/
70 
71 template<typename T>
72 struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};
73 
74 /*************************************************************************************************/
75 
76 class test_can_convert_anything { };
77 
78 /*************************************************************************************************/
79 
80 #endif // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
81 
82 /*************************************************************************************************/
83 
84 /*
85     REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where
86     boost::is_convertible<T, T> fails to compile.
87 */
88 
89 template <typename T, typename U>
90 struct is_convertible : boost::mpl::or_<
91     boost::is_same<T, U>,
92     boost::is_convertible<T, U>
93 > { };
94 
95 /*************************************************************************************************/
96 
97 } //namespace move_detail
98 
99 
100 /*************************************************************************************************/
101 
102 /*!
103 \ingroup move_related
104 \brief move_from is used for move_ctors.
105 */
106 
107 template <typename T>
108 struct move_from
109 {
move_fromboost::unordered_detail::move_from110     explicit move_from(T& x) : source(x) { }
111     T& source;
112 private:
113     move_from& operator=(move_from const&);
114 };
115 
116 /*************************************************************************************************/
117 
118 #if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
119 
120 /*************************************************************************************************/
121 
122 /*!
123 \ingroup move_related
124 \brief The is_movable trait can be used to identify movable types.
125 */
126 template <typename T>
127 struct is_movable : boost::mpl::and_<
128                         boost::is_convertible<move_from<T>, T>,
129                         move_detail::has_move_assign<T>,
130                         boost::mpl::not_<boost::is_convertible<move_detail::test_can_convert_anything, T> >
131                     > { };
132 
133 /*************************************************************************************************/
134 
135 #else // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
136 
137 // On compilers which don't have adequate SFINAE support, treat most types as unmovable,
138 // unless the trait is specialized.
139 
140 template <typename T>
141 struct is_movable : boost::mpl::false_ { };
142 
143 #endif
144 
145 /*************************************************************************************************/
146 
147 #if !defined(BOOST_NO_SFINAE)
148 
149 /*************************************************************************************************/
150 
151 /*!
152 \ingroup move_related
153 \brief copy_sink and move_sink are used to select between overloaded operations according to
154  whether type T is movable and convertible to type U.
155 \sa move
156 */
157 
158 template <typename T,
159           typename U = T,
160           typename R = void*>
161 struct copy_sink : boost::enable_if<
162                         boost::mpl::and_<
163                             boost::unordered_detail::move_detail::is_convertible<T, U>,
164                             boost::mpl::not_<is_movable<T> >
165                         >,
166                         R
167                     >
168 { };
169 
170 /*************************************************************************************************/
171 
172 /*!
173 \ingroup move_related
174 \brief move_sink and copy_sink are used to select between overloaded operations according to
175  whether type T is movable and convertible to type U.
176  \sa move
177 */
178 
179 template <typename T,
180           typename U = T,
181           typename R = void*>
182 struct move_sink : boost::enable_if<
183                         boost::mpl::and_<
184                             boost::unordered_detail::move_detail::is_convertible<T, U>,
185                             is_movable<T>
186                         >,
187                         R
188                     >
189 { };
190 
191 /*************************************************************************************************/
192 
193 /*!
194 \ingroup move_related
195 \brief This version of move is selected when T is_movable . It in turn calls the move
196 constructor. This call, with the help of the return value optimization, will cause x to be moved
197 instead of copied to its destination. See adobe/test/move/main.cpp for examples.
198 
199 */
200 template <typename T>
move(T & x,typename move_sink<T>::type=0)201 T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }
202 
203 /*************************************************************************************************/
204 
205 /*!
206 \ingroup move_related
207 \brief This version of move is selected when T is not movable . The net result will be that
208 x gets copied.
209 */
210 template <typename T>
move(T & x,typename copy_sink<T>::type=0)211 T& move(T& x, typename copy_sink<T>::type = 0) { return x; }
212 
213 /*************************************************************************************************/
214 
215 #else // BOOST_NO_SFINAE
216 
217 // On compilers without SFINAE, define copy_sink to always use the copy function.
218 
219 template <typename T,
220           typename U = T,
221           typename R = void*>
222 struct copy_sink
223 {
224     typedef R type;
225 };
226 
227 // Always copy the element unless this is overloaded.
228 
229 template <typename T>
move(T & x)230 T& move(T& x) {
231     return x;
232 }
233 
234 #endif // BOOST_NO_SFINAE
235 
236 } // namespace unordered_detail
237 } // namespace boost
238 
239 /*************************************************************************************************/
240 
241 #endif
242 
243 /*************************************************************************************************/
244