1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright 2007, 2008 Steven Watanabe, Joseph Gauterin, Niels Dekker |
4 | // (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost |
5 | // Software License, Version 1.0. (See accompanying file |
6 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | // |
8 | // See http://www.boost.org/libs/container for documentation. |
9 | // |
10 | ////////////////////////////////////////////////////////////////////////////// |
11 | |
12 | #ifndef BOOST_MOVE_ADL_MOVE_SWAP_HPP |
13 | #define BOOST_MOVE_ADL_MOVE_SWAP_HPP |
14 | |
15 | #ifndef BOOST_CONFIG_HPP |
16 | # include <boost/config.hpp> |
17 | #endif |
18 | # |
19 | #if defined(BOOST_HAS_PRAGMA_ONCE) |
20 | # pragma once |
21 | #endif |
22 | |
23 | //Based on Boost.Core's swap. |
24 | //Many thanks to Steven Watanabe, Joseph Gauterin and Niels Dekker. |
25 | #include <cstddef> //for std::size_t |
26 | #include <boost/move/detail/workaround.hpp> //forceinline |
27 | |
28 | //Try to avoid including <algorithm>, as it's quite big |
29 | #if defined(_MSC_VER) && defined(BOOST_DINKUMWARE_STDLIB) |
30 | #include <utility> //Dinkum libraries define std::swap in utility which is lighter than algorithm |
31 | #elif defined(BOOST_GNU_STDLIB) |
32 | //For non-GCC compilers, where GNUC version is not very reliable, or old GCC versions |
33 | //use the good old stl_algobase header, which is quite lightweight |
34 | #if !defined(BOOST_GCC) || ((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 3))) |
35 | #include <bits/stl_algobase.h> |
36 | #elif (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) |
37 | //In GCC 4.3 a tiny stl_move.h was created with swap and move utilities |
38 | #include <bits/stl_move.h> |
39 | #else |
40 | //In GCC 4.4 stl_move.h was renamed to move.h |
41 | #include <bits/move.h> |
42 | #endif |
43 | #elif defined(_LIBCPP_VERSION) |
44 | #include <type_traits> //The initial import of libc++ defines std::swap and still there |
45 | #elif __cplusplus >= 201103L |
46 | #include <utility> //Fallback for C++ >= 2011 |
47 | #else |
48 | #include <algorithm> //Fallback for C++98/03 |
49 | #endif |
50 | |
51 | #include <boost/move/utility_core.hpp> //for boost::move |
52 | |
53 | #if !defined(BOOST_MOVE_DOXYGEN_INVOKED) |
54 | |
55 | #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
56 | namespace boost_move_member_swap { |
57 | |
58 | struct dont_care |
59 | { |
60 | dont_care(...); |
61 | }; |
62 | |
63 | struct private_type |
64 | { |
65 | static private_type p; |
66 | private_type const &operator,(int) const; |
67 | }; |
68 | |
69 | typedef char yes_type; |
70 | struct no_type{ char dummy[2]; }; |
71 | |
72 | template<typename T> |
73 | no_type is_private_type(T const &); |
74 | |
75 | yes_type is_private_type(private_type const &); |
76 | |
77 | template <typename Type> |
78 | class has_member_function_named_swap |
79 | { |
80 | struct BaseMixin |
81 | { |
82 | void swap(); |
83 | }; |
84 | |
85 | struct Base : public Type, public BaseMixin { Base(); }; |
86 | template <typename T, T t> class Helper{}; |
87 | |
88 | template <typename U> |
89 | static no_type deduce(U*, Helper<void (BaseMixin::*)(), &U::swap>* = 0); |
90 | static yes_type deduce(...); |
91 | |
92 | public: |
93 | static const bool value = sizeof(yes_type) == sizeof(deduce((Base*)(0))); |
94 | }; |
95 | |
96 | template<typename Fun, bool HasFunc> |
97 | struct has_member_swap_impl |
98 | { |
99 | static const bool value = false; |
100 | }; |
101 | |
102 | template<typename Fun> |
103 | struct has_member_swap_impl<Fun, true> |
104 | { |
105 | struct FunWrap : Fun |
106 | { |
107 | FunWrap(); |
108 | |
109 | using Fun::swap; |
110 | private_type swap(dont_care) const; |
111 | }; |
112 | |
113 | static Fun &declval_fun(); |
114 | static FunWrap declval_wrap(); |
115 | |
116 | static bool const value = |
117 | sizeof(no_type) == sizeof(is_private_type( (declval_wrap().swap(declval_fun()), 0)) ); |
118 | }; |
119 | |
120 | template<typename Fun> |
121 | struct has_member_swap : public has_member_swap_impl |
122 | <Fun, has_member_function_named_swap<Fun>::value> |
123 | {}; |
124 | |
125 | } //namespace boost_move_member_swap |
126 | |
127 | namespace boost_move_adl_swap{ |
128 | |
129 | template<class P1, class P2, bool = P1::value> |
130 | struct and_op_impl |
131 | { static const bool value = false; }; |
132 | |
133 | template<class P1, class P2> |
134 | struct and_op_impl<P1, P2, true> |
135 | { static const bool value = P2::value; }; |
136 | |
137 | template<class P1, class P2> |
138 | struct and_op |
139 | : and_op_impl<P1, P2> |
140 | {}; |
141 | |
142 | ////// |
143 | |
144 | template<class P1, class P2, bool = P1::value> |
145 | struct and_op_not_impl |
146 | { static const bool value = false; }; |
147 | |
148 | template<class P1, class P2> |
149 | struct and_op_not_impl<P1, P2, true> |
150 | { static const bool value = !P2::value; }; |
151 | |
152 | template<class P1, class P2> |
153 | struct and_op_not |
154 | : and_op_not_impl<P1, P2> |
155 | {}; |
156 | |
157 | template<class T> |
158 | BOOST_MOVE_FORCEINLINE void swap_proxy(T& x, T& y, typename boost::move_detail::enable_if_c<!boost::move_detail::has_move_emulation_enabled_impl<T>::value>::type* = 0) |
159 | { |
160 | //use std::swap if argument dependent lookup fails |
161 | //Use using directive ("using namespace xxx;") instead as some older compilers |
162 | //don't do ADL with using declarations ("using ns::func;"). |
163 | using namespace std; |
164 | swap(x, y); |
165 | } |
166 | |
167 | template<class T> |
168 | BOOST_MOVE_FORCEINLINE void swap_proxy(T& x, T& y |
169 | , typename boost::move_detail::enable_if< and_op_not_impl<boost::move_detail::has_move_emulation_enabled_impl<T> |
170 | , boost_move_member_swap::has_member_swap<T> > |
171 | >::type* = 0) |
172 | { T t(::boost::move(x)); x = ::boost::move(y); y = ::boost::move(t); } |
173 | |
174 | template<class T> |
175 | BOOST_MOVE_FORCEINLINE void swap_proxy(T& x, T& y |
176 | , typename boost::move_detail::enable_if< and_op_impl< boost::move_detail::has_move_emulation_enabled_impl<T> |
177 | , boost_move_member_swap::has_member_swap<T> > |
178 | >::type* = 0) |
179 | { x.swap(y); } |
180 | |
181 | } //namespace boost_move_adl_swap{ |
182 | |
183 | #else |
184 | |
185 | namespace boost_move_adl_swap{ |
186 | |
187 | template<class T> |
188 | BOOST_MOVE_FORCEINLINE void swap_proxy(T& x, T& y) |
189 | { |
190 | using std::swap; |
191 | swap(x, y); |
192 | } |
193 | |
194 | } //namespace boost_move_adl_swap{ |
195 | |
196 | #endif //#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
197 | |
198 | namespace boost_move_adl_swap{ |
199 | |
200 | template<class T, std::size_t N> |
201 | void swap_proxy(T (& x)[N], T (& y)[N]) |
202 | { |
203 | for (std::size_t i = 0; i < N; ++i){ |
204 | ::boost_move_adl_swap::swap_proxy(x[i], y[i]); |
205 | } |
206 | } |
207 | |
208 | } //namespace boost_move_adl_swap { |
209 | |
210 | #endif //!defined(BOOST_MOVE_DOXYGEN_INVOKED) |
211 | |
212 | namespace boost{ |
213 | |
214 | //! Exchanges the values of a and b, using Argument Dependent Lookup (ADL) to select a |
215 | //! specialized swap function if available. If no specialized swap function is available, |
216 | //! std::swap is used. |
217 | //! |
218 | //! <b>Exception</b>: If T uses Boost.Move's move emulation and the compiler has |
219 | //! no rvalue references then: |
220 | //! |
221 | //! - If T has a <code>T::swap(T&)</code> member, that member is called. |
222 | //! - Otherwise a move-based swap is called, equivalent to: |
223 | //! <code>T t(::boost::move(x)); x = ::boost::move(y); y = ::boost::move(t);</code>. |
224 | template<class T> |
225 | BOOST_MOVE_FORCEINLINE void adl_move_swap(T& x, T& y) |
226 | { |
227 | ::boost_move_adl_swap::swap_proxy(x, y); |
228 | } |
229 | |
230 | //! Exchanges elements between range [first1, last1) and another range starting at first2 |
231 | //! using boost::adl_move_swap. |
232 | //! |
233 | //! Parameters: |
234 | //! first1, last1 - the first range of elements to swap |
235 | //! first2 - beginning of the second range of elements to swap |
236 | //! |
237 | //! Type requirements: |
238 | //! - ForwardIt1, ForwardIt2 must meet the requirements of ForwardIterator. |
239 | //! - The types of dereferenced ForwardIt1 and ForwardIt2 must meet the |
240 | //! requirements of Swappable |
241 | //! |
242 | //! Return value: Iterator to the element past the last element exchanged in the range |
243 | //! beginning with first2. |
244 | template<class ForwardIt1, class ForwardIt2> |
245 | ForwardIt2 adl_move_swap_ranges(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2) |
246 | { |
247 | while (first1 != last1) { |
248 | ::boost::adl_move_swap(*first1, *first2); |
249 | ++first1; |
250 | ++first2; |
251 | } |
252 | return first2; |
253 | } |
254 | |
255 | template<class BidirIt1, class BidirIt2> |
256 | BidirIt2 adl_move_swap_ranges_backward(BidirIt1 first1, BidirIt1 last1, BidirIt2 last2) |
257 | { |
258 | while (first1 != last1) { |
259 | ::boost::adl_move_swap(*(--last1), *(--last2)); |
260 | } |
261 | return last2; |
262 | } |
263 | |
264 | template<class ForwardIt1, class ForwardIt2> |
265 | void adl_move_iter_swap(ForwardIt1 a, ForwardIt2 b) |
266 | { |
267 | boost::adl_move_swap(*a, *b); |
268 | } |
269 | |
270 | } //namespace boost{ |
271 | |
272 | #endif //#ifndef BOOST_MOVE_ADL_MOVE_SWAP_HPP |
273 | |