Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

327 lines
12KB

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