swap.hpp 13 KB

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