tuple.hpp 11 KB

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