tuple.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*!
  2. @file
  3. Defines `boost::hana::tuple`.
  4. Copyright Louis Dionne 2013-2022
  5. Copyright Jason Rice 2017
  6. Distributed under the Boost Software License, Version 1.0.
  7. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  8. */
  9. #ifndef BOOST_HANA_TUPLE_HPP
  10. #define BOOST_HANA_TUPLE_HPP
  11. #include <boost/hana/fwd/tuple.hpp>
  12. #include <boost/hana/basic_tuple.hpp>
  13. #include <boost/hana/bool.hpp>
  14. #include <boost/hana/config.hpp>
  15. #include <boost/hana/detail/decay.hpp>
  16. #include <boost/hana/detail/fast_and.hpp>
  17. #include <boost/hana/detail/index_if.hpp>
  18. #include <boost/hana/detail/intrinsics.hpp>
  19. #include <boost/hana/detail/operators/adl.hpp>
  20. #include <boost/hana/detail/operators/comparable.hpp>
  21. #include <boost/hana/detail/operators/iterable.hpp>
  22. #include <boost/hana/detail/operators/monad.hpp>
  23. #include <boost/hana/detail/operators/orderable.hpp>
  24. #include <boost/hana/fwd/at.hpp>
  25. #include <boost/hana/fwd/core/make.hpp>
  26. #include <boost/hana/fwd/drop_front.hpp>
  27. #include <boost/hana/fwd/index_if.hpp>
  28. #include <boost/hana/fwd/is_empty.hpp>
  29. #include <boost/hana/fwd/length.hpp>
  30. #include <boost/hana/fwd/optional.hpp>
  31. #include <boost/hana/fwd/unpack.hpp>
  32. #include <boost/hana/type.hpp> // required by fwd decl of tuple_t
  33. #include <cstddef>
  34. #include <type_traits>
  35. #include <utility>
  36. namespace boost { namespace hana {
  37. namespace detail {
  38. template <typename Xs, typename Ys, std::size_t ...n>
  39. constexpr void assign(Xs& xs, Ys&& ys, std::index_sequence<n...>) {
  40. int sequence[] = {int{}, ((void)(
  41. hana::at_c<n>(xs) = hana::at_c<n>(static_cast<Ys&&>(ys))
  42. ), int{})...};
  43. (void)sequence;
  44. }
  45. struct from_index_sequence_t { };
  46. template <typename Tuple, typename ...Yn>
  47. struct is_same_tuple : std::false_type { };
  48. template <typename Tuple>
  49. struct is_same_tuple<typename detail::decay<Tuple>::type, Tuple>
  50. : std::true_type
  51. { };
  52. template <bool SameTuple, bool SameNumberOfElements, typename Tuple, typename ...Yn>
  53. struct enable_tuple_variadic_ctor;
  54. template <typename ...Xn, typename ...Yn>
  55. struct enable_tuple_variadic_ctor<false, true, hana::tuple<Xn...>, Yn...>
  56. : std::enable_if<
  57. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Yn&&)...>::value
  58. >
  59. { };
  60. }
  61. //////////////////////////////////////////////////////////////////////////
  62. // tuple
  63. //////////////////////////////////////////////////////////////////////////
  64. template <>
  65. #ifdef BOOST_HANA_WORKAROUND_MSVC_EMPTYBASE
  66. struct __declspec(empty_bases) tuple<> final
  67. #else
  68. struct tuple<> final
  69. #endif
  70. : detail::operators::adl<tuple<>>
  71. , detail::iterable_operators<tuple<>>
  72. {
  73. constexpr tuple() { }
  74. using hana_tag = tuple_tag;
  75. };
  76. template <typename ...Xn>
  77. #ifdef BOOST_HANA_WORKAROUND_MSVC_EMPTYBASE
  78. struct __declspec(empty_bases) tuple final
  79. #else
  80. struct tuple final
  81. #endif
  82. : detail::operators::adl<tuple<Xn...>>
  83. , detail::iterable_operators<tuple<Xn...>>
  84. {
  85. basic_tuple<Xn...> storage_;
  86. using hana_tag = tuple_tag;
  87. private:
  88. template <typename Other, std::size_t ...n>
  89. explicit constexpr tuple(detail::from_index_sequence_t, std::index_sequence<n...>, Other&& other)
  90. : storage_(hana::at_c<n>(static_cast<Other&&>(other))...)
  91. { }
  92. public:
  93. template <typename ...dummy, typename = typename std::enable_if<
  94. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, dummy...)...>::value
  95. >::type>
  96. constexpr tuple()
  97. : storage_()
  98. { }
  99. template <typename ...dummy, typename = typename std::enable_if<
  100. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Xn const&, dummy...)...>::value
  101. >::type>
  102. constexpr tuple(Xn const& ...xn)
  103. : storage_(xn...)
  104. { }
  105. template <typename ...Yn, typename = typename detail::enable_tuple_variadic_ctor<
  106. detail::is_same_tuple<tuple, Yn...>::value,
  107. sizeof...(Xn) == sizeof...(Yn), tuple, Yn...
  108. >::type>
  109. constexpr tuple(Yn&& ...yn)
  110. : storage_(static_cast<Yn&&>(yn)...)
  111. { }
  112. template <typename ...Yn, typename = typename std::enable_if<
  113. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Yn const&)...>::value
  114. >::type>
  115. constexpr tuple(tuple<Yn...> const& other)
  116. : tuple(detail::from_index_sequence_t{},
  117. std::make_index_sequence<sizeof...(Xn)>{},
  118. other.storage_)
  119. { }
  120. template <typename ...Yn, typename = typename std::enable_if<
  121. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Yn&&)...>::value
  122. >::type>
  123. constexpr tuple(tuple<Yn...>&& other)
  124. : tuple(detail::from_index_sequence_t{},
  125. std::make_index_sequence<sizeof...(Xn)>{},
  126. static_cast<tuple<Yn...>&&>(other).storage_)
  127. { }
  128. // The three following constructors are required to make sure that
  129. // the tuple(Yn&&...) constructor is _not_ preferred over the copy
  130. // constructor for unary tuples containing a type that is constructible
  131. // from tuple<...>. See test/tuple/cnstr.trap.cpp
  132. template <typename ...dummy, typename = typename std::enable_if<
  133. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Xn const&, dummy...)...>::value
  134. >::type>
  135. constexpr tuple(tuple const& other)
  136. : tuple(detail::from_index_sequence_t{},
  137. std::make_index_sequence<sizeof...(Xn)>{},
  138. other.storage_)
  139. { }
  140. template <typename ...dummy, typename = typename std::enable_if<
  141. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Xn const&, dummy...)...>::value
  142. >::type>
  143. constexpr tuple(tuple& other)
  144. : tuple(const_cast<tuple const&>(other))
  145. { }
  146. template <typename ...dummy, typename = typename std::enable_if<
  147. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Xn&&, dummy...)...>::value
  148. >::type>
  149. constexpr tuple(tuple&& other)
  150. : tuple(detail::from_index_sequence_t{},
  151. std::make_index_sequence<sizeof...(Xn)>{},
  152. static_cast<tuple&&>(other).storage_)
  153. { }
  154. template <typename ...Yn, typename = typename std::enable_if<
  155. detail::fast_and<BOOST_HANA_TT_IS_ASSIGNABLE(Xn&, Yn const&)...>::value
  156. >::type>
  157. constexpr tuple& operator=(tuple<Yn...> const& other) {
  158. detail::assign(this->storage_, other.storage_,
  159. std::make_index_sequence<sizeof...(Xn)>{});
  160. return *this;
  161. }
  162. template <typename ...Yn, typename = typename std::enable_if<
  163. detail::fast_and<BOOST_HANA_TT_IS_ASSIGNABLE(Xn&, Yn&&)...>::value
  164. >::type>
  165. constexpr tuple& operator=(tuple<Yn...>&& other) {
  166. detail::assign(this->storage_, static_cast<tuple<Yn...>&&>(other).storage_,
  167. std::make_index_sequence<sizeof...(Xn)>{});
  168. return *this;
  169. }
  170. };
  171. //////////////////////////////////////////////////////////////////////////
  172. // Operators
  173. //////////////////////////////////////////////////////////////////////////
  174. namespace detail {
  175. template <>
  176. struct comparable_operators<tuple_tag> {
  177. static constexpr bool value = true;
  178. };
  179. template <>
  180. struct orderable_operators<tuple_tag> {
  181. static constexpr bool value = true;
  182. };
  183. template <>
  184. struct monad_operators<tuple_tag> {
  185. static constexpr bool value = true;
  186. };
  187. }
  188. //////////////////////////////////////////////////////////////////////////
  189. // Foldable
  190. //////////////////////////////////////////////////////////////////////////
  191. template <>
  192. struct unpack_impl<tuple_tag> {
  193. template <typename F>
  194. static constexpr decltype(auto) apply(tuple<>&&, F&& f)
  195. { return static_cast<F&&>(f)(); }
  196. template <typename F>
  197. static constexpr decltype(auto) apply(tuple<>&, F&& f)
  198. { return static_cast<F&&>(f)(); }
  199. template <typename F>
  200. static constexpr decltype(auto) apply(tuple<> const&, F&& f)
  201. { return static_cast<F&&>(f)(); }
  202. template <typename Xs, typename F>
  203. static constexpr decltype(auto) apply(Xs&& xs, F&& f) {
  204. return hana::unpack(static_cast<Xs&&>(xs).storage_, static_cast<F&&>(f));
  205. }
  206. };
  207. template <>
  208. struct length_impl<tuple_tag> {
  209. template <typename ...Xs>
  210. static constexpr auto apply(tuple<Xs...> const&)
  211. { return hana::size_c<sizeof...(Xs)>; }
  212. };
  213. //////////////////////////////////////////////////////////////////////////
  214. // Iterable
  215. //////////////////////////////////////////////////////////////////////////
  216. template <>
  217. struct at_impl<tuple_tag> {
  218. template <typename Xs, typename N>
  219. static constexpr decltype(auto) apply(Xs&& xs, N const&) {
  220. constexpr std::size_t index = N::value;
  221. return hana::at_c<index>(static_cast<Xs&&>(xs).storage_);
  222. }
  223. };
  224. template <>
  225. struct drop_front_impl<tuple_tag> {
  226. template <std::size_t N, typename Xs, std::size_t ...i>
  227. static constexpr auto helper(Xs&& xs, std::index_sequence<i...>) {
  228. return hana::make<tuple_tag>(hana::at_c<i+N>(static_cast<Xs&&>(xs))...);
  229. }
  230. template <typename Xs, typename N>
  231. static constexpr auto apply(Xs&& xs, N const&) {
  232. constexpr std::size_t len = decltype(hana::length(xs))::value;
  233. return helper<N::value>(static_cast<Xs&&>(xs), std::make_index_sequence<
  234. (N::value < len) ? len - N::value : 0
  235. >{});
  236. }
  237. };
  238. template <>
  239. struct is_empty_impl<tuple_tag> {
  240. template <typename ...Xs>
  241. static constexpr auto apply(tuple<Xs...> const&)
  242. { return hana::bool_c<sizeof...(Xs) == 0>; }
  243. };
  244. // compile-time optimizations (to reduce the # of function instantiations)
  245. template <std::size_t n, typename ...Xs>
  246. constexpr decltype(auto) at_c(tuple<Xs...> const& xs) {
  247. return hana::at_c<n>(xs.storage_);
  248. }
  249. template <std::size_t n, typename ...Xs>
  250. constexpr decltype(auto) at_c(tuple<Xs...>& xs) {
  251. return hana::at_c<n>(xs.storage_);
  252. }
  253. template <std::size_t n, typename ...Xs>
  254. constexpr decltype(auto) at_c(tuple<Xs...>&& xs) {
  255. return hana::at_c<n>(static_cast<tuple<Xs...>&&>(xs).storage_);
  256. }
  257. template <>
  258. struct index_if_impl<tuple_tag> {
  259. template <typename ...Xs, typename Pred>
  260. static constexpr auto apply(tuple<Xs...> const&, Pred const&)
  261. -> typename detail::index_if<Pred, Xs...>::type
  262. { return {}; }
  263. };
  264. //////////////////////////////////////////////////////////////////////////
  265. // Sequence
  266. //////////////////////////////////////////////////////////////////////////
  267. template <>
  268. struct Sequence<tuple_tag> {
  269. static constexpr bool value = true;
  270. };
  271. template <>
  272. struct make_impl<tuple_tag> {
  273. template <typename ...Xs>
  274. static constexpr
  275. tuple<typename detail::decay<Xs>::type...> apply(Xs&& ...xs)
  276. { return {static_cast<Xs&&>(xs)...}; }
  277. };
  278. }} // end namespace boost::hana
  279. #endif // !BOOST_HANA_TUPLE_HPP