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 | { |
---|
110 | 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> |
---|
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> |
---|
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> |
---|
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 | /*************************************************************************************************/ |
---|