tuple.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*!
  2. @file
  3. Defines `boost::hana::tuple`.
  4. @copyright Louis Dionne 2013-2017
  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. BOOST_HANA_NAMESPACE_BEGIN
  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. struct tuple<> final
  66. : detail::operators::adl<tuple<>>
  67. , detail::iterable_operators<tuple<>>
  68. {
  69. constexpr tuple() { }
  70. using hana_tag = tuple_tag;
  71. };
  72. template <typename ...Xn>
  73. struct tuple final
  74. : detail::operators::adl<tuple<Xn...>>
  75. , detail::iterable_operators<tuple<Xn...>>
  76. {
  77. basic_tuple<Xn...> storage_;
  78. using hana_tag = tuple_tag;
  79. private:
  80. template <typename Other, std::size_t ...n>
  81. explicit constexpr tuple(detail::from_index_sequence_t, std::index_sequence<n...>, Other&& other)
  82. : storage_(hana::at_c<n>(static_cast<Other&&>(other))...)
  83. { }
  84. public:
  85. template <typename ...dummy, typename = typename std::enable_if<
  86. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, dummy...)...>::value
  87. >::type>
  88. constexpr tuple()
  89. : storage_()
  90. { }
  91. template <typename ...dummy, typename = typename std::enable_if<
  92. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Xn const&, dummy...)...>::value
  93. >::type>
  94. constexpr tuple(Xn const& ...xn)
  95. : storage_(xn...)
  96. { }
  97. template <typename ...Yn, typename = typename detail::enable_tuple_variadic_ctor<
  98. detail::is_same_tuple<tuple, Yn...>::value,
  99. sizeof...(Xn) == sizeof...(Yn), tuple, Yn...
  100. >::type>
  101. constexpr tuple(Yn&& ...yn)
  102. : storage_(static_cast<Yn&&>(yn)...)
  103. { }
  104. template <typename ...Yn, typename = typename std::enable_if<
  105. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Yn const&)...>::value
  106. >::type>
  107. constexpr tuple(tuple<Yn...> const& other)
  108. : tuple(detail::from_index_sequence_t{},
  109. std::make_index_sequence<sizeof...(Xn)>{},
  110. other.storage_)
  111. { }
  112. template <typename ...Yn, typename = typename std::enable_if<
  113. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Yn&&)...>::value
  114. >::type>
  115. constexpr tuple(tuple<Yn...>&& other)
  116. : tuple(detail::from_index_sequence_t{},
  117. std::make_index_sequence<sizeof...(Xn)>{},
  118. static_cast<tuple<Yn...>&&>(other).storage_)
  119. { }
  120. // The three following constructors are required to make sure that
  121. // the tuple(Yn&&...) constructor is _not_ preferred over the copy
  122. // constructor for unary tuples containing a type that is constructible
  123. // from tuple<...>. See test/tuple/cnstr.trap.cpp
  124. template <typename ...dummy, typename = typename std::enable_if<
  125. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Xn const&, dummy...)...>::value
  126. >::type>
  127. constexpr tuple(tuple const& other)
  128. : tuple(detail::from_index_sequence_t{},
  129. std::make_index_sequence<sizeof...(Xn)>{},
  130. other.storage_)
  131. { }
  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& other)
  136. : tuple(const_cast<tuple const&>(other))
  137. { }
  138. template <typename ...dummy, typename = typename std::enable_if<
  139. detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Xn&&, dummy...)...>::value
  140. >::type>
  141. constexpr tuple(tuple&& other)
  142. : tuple(detail::from_index_sequence_t{},
  143. std::make_index_sequence<sizeof...(Xn)>{},
  144. static_cast<tuple&&>(other).storage_)
  145. { }
  146. template <typename ...Yn, typename = typename std::enable_if<
  147. detail::fast_and<BOOST_HANA_TT_IS_ASSIGNABLE(Xn&, Yn const&)...>::value
  148. >::type>
  149. constexpr tuple& operator=(tuple<Yn...> const& other) {
  150. detail::assign(this->storage_, other.storage_,
  151. std::make_index_sequence<sizeof...(Xn)>{});
  152. return *this;
  153. }
  154. template <typename ...Yn, typename = typename std::enable_if<
  155. detail::fast_and<BOOST_HANA_TT_IS_ASSIGNABLE(Xn&, Yn&&)...>::value
  156. >::type>
  157. constexpr tuple& operator=(tuple<Yn...>&& other) {
  158. detail::assign(this->storage_, static_cast<tuple<Yn...>&&>(other).storage_,
  159. std::make_index_sequence<sizeof...(Xn)>{});
  160. return *this;
  161. }
  162. };
  163. //////////////////////////////////////////////////////////////////////////
  164. // Operators
  165. //////////////////////////////////////////////////////////////////////////
  166. namespace detail {
  167. template <>
  168. struct comparable_operators<tuple_tag> {
  169. static constexpr bool value = true;
  170. };
  171. template <>
  172. struct orderable_operators<tuple_tag> {
  173. static constexpr bool value = true;
  174. };
  175. template <>
  176. struct monad_operators<tuple_tag> {
  177. static constexpr bool value = true;
  178. };
  179. }
  180. //////////////////////////////////////////////////////////////////////////
  181. // Foldable
  182. //////////////////////////////////////////////////////////////////////////
  183. template <>
  184. struct unpack_impl<tuple_tag> {
  185. template <typename F>
  186. static constexpr decltype(auto) apply(tuple<>&&, F&& f)
  187. { return static_cast<F&&>(f)(); }
  188. template <typename F>
  189. static constexpr decltype(auto) apply(tuple<>&, F&& f)
  190. { return static_cast<F&&>(f)(); }
  191. template <typename F>
  192. static constexpr decltype(auto) apply(tuple<> const&, F&& f)
  193. { return static_cast<F&&>(f)(); }
  194. template <typename Xs, typename F>
  195. static constexpr decltype(auto) apply(Xs&& xs, F&& f) {
  196. return hana::unpack(static_cast<Xs&&>(xs).storage_, static_cast<F&&>(f));
  197. }
  198. };
  199. template <>
  200. struct length_impl<tuple_tag> {
  201. template <typename ...Xs>
  202. static constexpr auto apply(tuple<Xs...> const&)
  203. { return hana::size_c<sizeof...(Xs)>; }
  204. };
  205. //////////////////////////////////////////////////////////////////////////
  206. // Iterable
  207. //////////////////////////////////////////////////////////////////////////
  208. template <>
  209. struct at_impl<tuple_tag> {
  210. template <typename Xs, typename N>
  211. static constexpr decltype(auto) apply(Xs&& xs, N const&) {
  212. constexpr std::size_t index = N::value;
  213. return hana::at_c<index>(static_cast<Xs&&>(xs).storage_);
  214. }
  215. };
  216. template <>
  217. struct drop_front_impl<tuple_tag> {
  218. template <std::size_t N, typename Xs, std::size_t ...i>
  219. static constexpr auto helper(Xs&& xs, std::index_sequence<i...>) {
  220. return hana::make<tuple_tag>(hana::at_c<i+N>(static_cast<Xs&&>(xs))...);
  221. }
  222. template <typename Xs, typename N>
  223. static constexpr auto apply(Xs&& xs, N const&) {
  224. constexpr std::size_t len = decltype(hana::length(xs))::value;
  225. return helper<N::value>(static_cast<Xs&&>(xs), std::make_index_sequence<
  226. N::value < len ? len - N::value : 0
  227. >{});
  228. }
  229. };
  230. template <>
  231. struct is_empty_impl<tuple_tag> {
  232. template <typename ...Xs>
  233. static constexpr auto apply(tuple<Xs...> const&)
  234. { return hana::bool_c<sizeof...(Xs) == 0>; }
  235. };
  236. // compile-time optimizations (to reduce the # of function instantiations)
  237. template <std::size_t n, typename ...Xs>
  238. constexpr decltype(auto) at_c(tuple<Xs...> const& xs) {
  239. return hana::at_c<n>(xs.storage_);
  240. }
  241. template <std::size_t n, typename ...Xs>
  242. constexpr decltype(auto) at_c(tuple<Xs...>& xs) {
  243. return hana::at_c<n>(xs.storage_);
  244. }
  245. template <std::size_t n, typename ...Xs>
  246. constexpr decltype(auto) at_c(tuple<Xs...>&& xs) {
  247. return hana::at_c<n>(static_cast<tuple<Xs...>&&>(xs).storage_);
  248. }
  249. template <>
  250. struct index_if_impl<tuple_tag> {
  251. template <typename ...Xs, typename Pred>
  252. static constexpr auto apply(tuple<Xs...> const&, Pred const&)
  253. -> typename detail::index_if<Pred, Xs...>::type
  254. { return {}; }
  255. };
  256. //////////////////////////////////////////////////////////////////////////
  257. // Sequence
  258. //////////////////////////////////////////////////////////////////////////
  259. template <>
  260. struct Sequence<tuple_tag> {
  261. static constexpr bool value = true;
  262. };
  263. template <>
  264. struct make_impl<tuple_tag> {
  265. template <typename ...Xs>
  266. static constexpr
  267. tuple<typename detail::decay<Xs>::type...> apply(Xs&& ...xs)
  268. { return {static_cast<Xs&&>(xs)...}; }
  269. };
  270. BOOST_HANA_NAMESPACE_END
  271. #endif // !BOOST_HANA_TUPLE_HPP