• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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