Horizon
swap.hpp
Go to the documentation of this file.
1 // Concepts library
3 //
4 // Copyright Eric Niebler 2013-present
5 //
6 // Use, modification and distribution is subject to the
7 // Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 //
11 // Project home: https://github.com/ericniebler/range-v3
12 
13 #ifndef CPP_SWAP_HPP
14 #define CPP_SWAP_HPP
15 
16 #include <tuple>
17 #include <utility>
18 #include <type_traits>
19 #include <meta/meta.hpp>
20 
21 // Note: constexpr implies inline, to retain the same visibility
22 // C++14 constexpr functions are inline in C++11
23 #if (defined(__cpp_constexpr) && __cpp_constexpr >= 201304L) ||\
24  (!defined(__cpp_constexpr) && __cplusplus >= 201402L)
25 #define CPP_CXX14_CONSTEXPR constexpr
26 #else
27 #define CPP_CXX14_CONSTEXPR inline
28 #endif
29 
30 #ifndef CPP_CXX_INLINE_VARIABLES
31 #ifdef __cpp_inline_variables // TODO: fix this if SD-6 picks another name
32 #define CPP_CXX_INLINE_VARIABLES __cpp_inline_variables
33 // TODO: remove once clang defines __cpp_inline_variables (or equivalent)
34 #elif defined(__clang__) && \
35  (__clang_major__ > 3 || __clang_major__ == 3 && __clang_minor__ == 9) && \
36  __cplusplus > 201402L
37 #define CPP_CXX_INLINE_VARIABLES 201606L
38 #else
39 #define CPP_CXX_INLINE_VARIABLES __cplusplus
40 #endif // __cpp_inline_variables
41 #endif // CPP_CXX_INLINE_VARIABLES
42 
43 #if defined(_MSC_VER) && !defined(__clang__)
44 #if _MSC_VER < 1926
45 #define CPP_WORKAROUND_MSVC_895622 // Error when phase 1 name binding finds only deleted function
46 #endif // _MSC_VER < 1926
47 #endif // MSVC
48 
49 #if CPP_CXX_INLINE_VARIABLES < 201606L
50 #define CPP_INLINE_VAR
51 #define CPP_INLINE_VARIABLE(type, name) \
52  inline namespace \
53  { \
54  constexpr auto &name = ::concepts::detail::static_const<type>::value; \
55  } \
56 
57 #else // CPP_CXX_INLINE_VARIABLES >= 201606L
58 #define CPP_INLINE_VAR inline
59 #define CPP_INLINE_VARIABLE(type, name) \
60  inline constexpr type name{}; \
61 
62 #endif // CPP_CXX_INLINE_VARIABLES
63 
64 #if CPP_CXX_INLINE_VARIABLES < 201606L
65 #define CPP_DEFINE_CPO(type, name) \
66  inline namespace \
67  { \
68  constexpr auto &name = ::concepts::detail::static_const<type>::value; \
69  } \
70 
71 #else // CPP_CXX_INLINE_VARIABLES >= 201606L
72 #define CPP_DEFINE_CPO(type, name) \
73  inline namespace _ \
74  { \
75  inline constexpr type name{}; \
76  } \
77 
78 #endif // CPP_CXX_INLINE_VARIABLES
79 
80 #if defined(_MSC_VER) && !defined(__clang__)
81 #define CPP_DIAGNOSTIC_PUSH __pragma(warning(push))
82 #define CPP_DIAGNOSTIC_POP __pragma(warning(pop))
83 #define CPP_DIAGNOSTIC_IGNORE_INIT_LIST_LIFETIME
84 #define CPP_DIAGNOSTIC_IGNORE_FLOAT_EQUAL
85 #define CPP_DIAGNOSTIC_IGNORE_CPP2A_COMPAT
86 #else // ^^^ defined(_MSC_VER) ^^^ / vvv !defined(_MSC_VER) vvv
87 #if defined(__GNUC__) || defined(__clang__)
88 #define CPP_PRAGMA(X) _Pragma(#X)
89 #define CPP_DIAGNOSTIC_PUSH CPP_PRAGMA(GCC diagnostic push)
90 #define CPP_DIAGNOSTIC_POP CPP_PRAGMA(GCC diagnostic pop)
91 #define CPP_DIAGNOSTIC_IGNORE_PRAGMAS \
92  CPP_PRAGMA(GCC diagnostic ignored "-Wpragmas")
93 #define CPP_DIAGNOSTIC_IGNORE(X) \
94  CPP_DIAGNOSTIC_IGNORE_PRAGMAS \
95  CPP_PRAGMA(GCC diagnostic ignored "-Wunknown-pragmas") \
96  CPP_PRAGMA(GCC diagnostic ignored X)
97 #define CPP_DIAGNOSTIC_IGNORE_INIT_LIST_LIFETIME \
98  CPP_DIAGNOSTIC_IGNORE("-Wunknown-warning-option") \
99  CPP_DIAGNOSTIC_IGNORE("-Winit-list-lifetime")
100 #define CPP_DIAGNOSTIC_IGNORE_FLOAT_EQUAL CPP_DIAGNOSTIC_IGNORE("-Wfloat-equal")
101 #define CPP_DIAGNOSTIC_IGNORE_CPP2A_COMPAT CPP_DIAGNOSTIC_IGNORE("-Wc++2a-compat")
102 #else
103 #define CPP_DIAGNOSTIC_PUSH
104 #define CPP_DIAGNOSTIC_POP
105 #define CPP_DIAGNOSTIC_IGNORE_INIT_LIST_LIFETIME
106 #define CPP_DIAGNOSTIC_IGNORE_FLOAT_EQUAL
107 #define CPP_DIAGNOSTIC_IGNORE_CPP2A_COMPAT
108 #endif
109 #endif // MSVC/Generic configuration switch
110 
111 namespace concepts
112 {
114  namespace detail
115  {
116  template<typename T>
117  CPP_INLINE_VAR constexpr bool is_movable_v =
118  std::is_object<T>::value &&
119  std::is_move_constructible<T>::value &&
120  std::is_move_assignable<T>::value;
121 
122  template<typename T>
123  struct static_const
124  {
125  static constexpr T const value {};
126  };
127  template<typename T>
128  constexpr T const static_const<T>::value;
129  }
131 
132  template<typename T>
133  struct is_swappable;
134 
135  template<typename T>
136  struct is_nothrow_swappable;
137 
138  template<typename T, typename U>
139  struct is_swappable_with;
140 
141  template<typename T, typename U>
142  struct is_nothrow_swappable_with;
143 
144  template<typename T, typename U = T>
145  CPP_CXX14_CONSTEXPR
146  meta::if_c<
147  std::is_move_constructible<T>::value &&
148  std::is_assignable<T &, U>::value, T>
149  exchange(T &t, U &&u)
150  noexcept(
151  std::is_nothrow_move_constructible<T>::value &&
152  std::is_nothrow_assignable<T &, U>::value)
153  {
154  T tmp((T &&) t);
155  t = (U &&) u;
156  CPP_DIAGNOSTIC_IGNORE_INIT_LIST_LIFETIME
157  return tmp;
158  }
159 
161  namespace adl_swap_detail
162  {
163  struct nope
164  {};
165 
166  // Intentionally create an ambiguity with std::swap, which is
167  // (possibly) unconstrained.
168  template<typename T>
169  nope swap(T &, T &) = delete;
170 
171  template<typename T, std::size_t N>
172  nope swap(T (&)[N], T (&)[N]) = delete;
173 
174 #ifdef CPP_WORKAROUND_MSVC_895622
175  nope swap();
176 #endif
177 
178  template<typename T, typename U>
179  decltype(swap(std::declval<T>(), std::declval<U>())) try_adl_swap_(int);
180 
181  template<typename T, typename U>
182  nope try_adl_swap_(long);
183 
184  template<typename T, typename U = T>
185  CPP_INLINE_VAR constexpr bool is_adl_swappable_v =
186  !META_IS_SAME(decltype(adl_swap_detail::try_adl_swap_<T, U>(42)), nope);
187 
188  struct swap_fn
189  {
190  // Dispatch to user-defined swap found via ADL:
191  template<typename T, typename U>
192  CPP_CXX14_CONSTEXPR
193  meta::if_c<is_adl_swappable_v<T, U>>
194  operator()(T &&t, U &&u) const
195  noexcept(noexcept(swap((T &&) t, (U &&) u)))
196  {
197  swap((T &&) t, (U &&) u);
198  }
199 
200  // For intrinsically swappable (i.e., movable) types for which
201  // a swap overload cannot be found via ADL, swap by moving.
202  template<typename T>
203  CPP_CXX14_CONSTEXPR
204  meta::if_c<
205  !is_adl_swappable_v<T &> &&
206  detail::is_movable_v<T>>
207  operator()(T &a, T &b) const
208  noexcept(noexcept(b = concepts::exchange(a, (T &&) b)))
209  {
210  b = concepts::exchange(a, (T &&) b);
211  }
212 
213  // For arrays of intrinsically swappable (i.e., movable) types
214  // for which a swap overload cannot be found via ADL, swap array
215  // elements by moving.
216  template<typename T, typename U, std::size_t N>
217  CPP_CXX14_CONSTEXPR
218  meta::if_c<
219  !is_adl_swappable_v<T (&)[N], U (&)[N]> &&
220  is_swappable_with<T &, U &>::value>
221  operator()(T (&t)[N], U (&u)[N]) const
222  noexcept(is_nothrow_swappable_with<T &, U &>::value)
223  {
224  for(std::size_t i = 0; i < N; ++i)
225  (*this)(t[i], u[i]);
226  }
227 
228  // For rvalue pairs and tuples of swappable types, swap the
229  // members. This permits code like:
230  // ranges::swap(std::tie(a,b,c), std::tie(d,e,f));
231  template<typename F0, typename S0, typename F1, typename S1>
232  CPP_CXX14_CONSTEXPR
233  meta::if_c<is_swappable_with<F0, F1>::value && is_swappable_with<S0, S1>::value>
234  operator()(std::pair<F0, S0> &&left, std::pair<F1, S1> &&right) const
235  noexcept(
236  is_nothrow_swappable_with<F0, F1>::value &&
237  is_nothrow_swappable_with<S0, S1>::value)
238  {
239  swap_fn()(static_cast<std::pair<F0, S0> &&>(left).first,
240  static_cast<std::pair<F1, S1> &&>(right).first);
241  swap_fn()(static_cast<std::pair<F0, S0> &&>(left).second,
242  static_cast<std::pair<F1, S1> &&>(right).second);
243  }
244 
245  template<typename ...Ts, typename ...Us>
246  CPP_CXX14_CONSTEXPR
247  meta::if_c<meta::and_c<is_swappable_with<Ts, Us>::value...>::value>
248  operator()(std::tuple<Ts...> &&left, std::tuple<Us...> &&right) const
249  noexcept(meta::and_c<is_nothrow_swappable_with<Ts, Us>::value...>::value)
250  {
251  swap_fn::impl(
252  static_cast<std::tuple<Ts...> &&>(left),
253  static_cast<std::tuple<Us...> &&>(right),
254  meta::make_index_sequence<sizeof...(Ts)>{});
255  }
256 
257  private:
258  template<typename... Ts>
259  static constexpr int ignore_unused(Ts &&...)
260  {
261  return 0;
262  }
263  template<typename T, typename U, std::size_t ...Is>
264  CPP_CXX14_CONSTEXPR
265  static void impl(T &&left, U &&right, meta::index_sequence<Is...>)
266  {
267  (void) swap_fn::ignore_unused(
268  (swap_fn()(std::get<Is>(static_cast<T &&>(left)),
269  std::get<Is>(static_cast<U &&>(right))), 42)...);
270  }
271  };
272 
273  template<typename T, typename U, typename = void>
274  struct is_swappable_with_
275  : std::false_type
276  {};
277 
278  template<typename T, typename U>
279  struct is_swappable_with_<T, U, meta::void_<
280  decltype(swap_fn()(std::declval<T>(), std::declval<U>())),
281  decltype(swap_fn()(std::declval<U>(), std::declval<T>()))>>
282  : std::true_type
283  {};
284 
285  template<typename T, typename U>
286  struct is_nothrow_swappable_with_
287  : meta::bool_<noexcept(swap_fn()(std::declval<T>(), std::declval<U>())) &&
288  noexcept(swap_fn()(std::declval<U>(), std::declval<T>()))>
289  {};
290 
291  // Q: Should std::reference_wrapper be considered a proxy wrt swapping rvalues?
292  // A: No. Its operator= is currently defined to reseat the references, so
293  // std::swap(ra, rb) already means something when ra and rb are (lvalue)
294  // reference_wrappers. That reseats the reference wrappers but leaves the
295  // referents unmodified. Treating rvalue reference_wrappers differently would
296  // be confusing.
297 
298  // Q: Then why is it OK to "re"-define swap for pairs and tuples of references?
299  // A: Because as defined above, swapping an rvalue tuple of references has the same
300  // semantics as swapping an lvalue tuple of references. Rather than reseat the
301  // references, assignment happens *through* the references.
302 
303  // Q: But I have an iterator whose operator* returns an rvalue
304  // std::reference_wrapper<T>. How do I make it model indirectly_swappable?
305  // A: With an overload of iter_swap.
306  }
308 
310  template<typename T, typename U>
312  : adl_swap_detail::is_swappable_with_<T, U>
313  {};
314 
316  template<typename T, typename U>
318  : meta::and_<
319  is_swappable_with<T, U>,
320  adl_swap_detail::is_nothrow_swappable_with_<T, U>>
321  {};
322 
324  template<typename T>
326  : is_swappable_with<T &, T &>
327  {};
328 
330  template<typename T>
332  : is_nothrow_swappable_with<T &, T &>
333  {};
334 
337  CPP_DEFINE_CPO(adl_swap_detail::swap_fn, swap)
338 }
339 
340 #endif
template(typename ActionFn, typename Rng)(concept(invocable_action_closure_)(ActionFn
\concept invocable_action_closure_
_t< detail::make_indices_< N, index_sequence< 0 >, detail::strategy_(1, N)> > make_index_sequence
Generate index_sequence containing integer constants [0,1,2,...,N-1].
Definition: meta.hpp:473
std::integral_constant< bool, B > bool_
An integral constant wrapper for bool.
Definition: meta.hpp:168
std::integral_constant< std::size_t, N > size_t
An integral constant wrapper for std::size_t.
Definition: meta.hpp:163
front< Pair > first
Retrieve the first element of the pair Pair.
Definition: meta.hpp:2251
front< pop_front< Pair > > second
Retrieve the first element of the pair Pair.
Definition: meta.hpp:2256
_t< defer< detail::_and_< 0==sizeof...(Bs)>::template invoke, Bs... > > and_
Logically AND together all the integral constant-wrapped Boolean parameters, with short-circuiting.
Definition: meta.hpp:1411
void void_
An alias for void.
Definition: meta.hpp:597
Tiny meta-programming library.
Tiny metaprogramming library.
Definition: meta.hpp:116
Definition: swap.hpp:321
Definition: swap.hpp:333
Definition: swap.hpp:313
Definition: swap.hpp:327
Definition: meta.hpp:1383
A container for a sequence of compile-time integer constants.
Definition: meta.hpp:434