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