]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*! |
2 | @file | |
3 | Defines `boost::hana::tuple`. | |
4 | ||
b32b8144 FG |
5 | @copyright Louis Dionne 2013-2017 |
6 | @copyright Jason Rice 2017 | |
7c673cae FG |
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> | |
b32b8144 | 31 | #include <boost/hana/fwd/index_if.hpp> |
7c673cae FG |
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> | |
46 | constexpr void assign(Xs& xs, Ys&& ys, std::index_sequence<n...>) { | |
47 | int sequence[] = {int{}, ((void)( | |
b32b8144 | 48 | hana::at_c<n>(xs) = hana::at_c<n>(static_cast<Ys&&>(ys)) |
7c673cae FG |
49 | ), int{})...}; |
50 | (void)sequence; | |
51 | } | |
52 | ||
53 | struct from_index_sequence_t { }; | |
b32b8144 FG |
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 | { }; | |
7c673cae FG |
72 | } |
73 | ||
74 | ////////////////////////////////////////////////////////////////////////// | |
75 | // tuple | |
76 | ////////////////////////////////////////////////////////////////////////// | |
77 | template <> | |
92f5a8d4 TL |
78 | #ifdef BOOST_HANA_WORKAROUND_MSVC_EMPTYBASE |
79 | struct __declspec(empty_bases) tuple<> final | |
80 | #else | |
81 | struct tuple<> final | |
82 | #endif | |
7c673cae FG |
83 | : detail::operators::adl<tuple<>> |
84 | , detail::iterable_operators<tuple<>> | |
85 | { | |
86 | constexpr tuple() { } | |
87 | using hana_tag = tuple_tag; | |
88 | }; | |
89 | ||
90 | template <typename ...Xn> | |
92f5a8d4 TL |
91 | #ifdef BOOST_HANA_WORKAROUND_MSVC_EMPTYBASE |
92 | struct __declspec(empty_bases) tuple final | |
93 | #else | |
94 | struct tuple final | |
95 | #endif | |
7c673cae FG |
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> | |
104 | explicit constexpr tuple(detail::from_index_sequence_t, std::index_sequence<n...>, Other&& other) | |
b32b8144 | 105 | : storage_(hana::at_c<n>(static_cast<Other&&>(other))...) |
7c673cae FG |
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> | |
112 | 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> | |
119 | constexpr tuple(Xn const& ...xn) | |
120 | : storage_(xn...) | |
121 | { } | |
122 | ||
b32b8144 FG |
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... | |
7c673cae FG |
126 | >::type> |
127 | 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> | |
134 | 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> | |
143 | 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 | |
b32b8144 | 152 | // from tuple<...>. See test/tuple/cnstr.trap.cpp |
7c673cae FG |
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> | |
156 | 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> | |
165 | 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> | |
172 | 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> | |
182 | 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> | |
191 | 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> | |
222 | static constexpr decltype(auto) apply(tuple<>&&, F&& f) | |
223 | { return static_cast<F&&>(f)(); } | |
224 | template <typename F> | |
225 | static constexpr decltype(auto) apply(tuple<>&, F&& f) | |
226 | { return static_cast<F&&>(f)(); } | |
227 | template <typename F> | |
228 | static constexpr decltype(auto) apply(tuple<> const&, F&& f) | |
229 | { return static_cast<F&&>(f)(); } | |
230 | ||
231 | template <typename Xs, typename F> | |
232 | 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> | |
240 | 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> | |
250 | static constexpr decltype(auto) apply(Xs&& xs, N const&) { | |
251 | constexpr std::size_t index = N::value; | |
b32b8144 | 252 | return hana::at_c<index>(static_cast<Xs&&>(xs).storage_); |
7c673cae FG |
253 | } |
254 | }; | |
255 | ||
256 | template <> | |
257 | struct drop_front_impl<tuple_tag> { | |
258 | template <std::size_t N, typename Xs, std::size_t ...i> | |
259 | 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> | |
264 | 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< | |
92f5a8d4 | 267 | (N::value < len) ? len - N::value : 0 |
7c673cae FG |
268 | >{}); |
269 | } | |
270 | }; | |
271 | ||
272 | template <> | |
273 | struct is_empty_impl<tuple_tag> { | |
274 | template <typename ...Xs> | |
275 | 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> | |
281 | constexpr decltype(auto) at_c(tuple<Xs...> const& xs) { | |
b32b8144 | 282 | return hana::at_c<n>(xs.storage_); |
7c673cae FG |
283 | } |
284 | ||
285 | template <std::size_t n, typename ...Xs> | |
286 | constexpr decltype(auto) at_c(tuple<Xs...>& xs) { | |
b32b8144 | 287 | return hana::at_c<n>(xs.storage_); |
7c673cae FG |
288 | } |
289 | ||
290 | template <std::size_t n, typename ...Xs> | |
291 | constexpr decltype(auto) at_c(tuple<Xs...>&& xs) { | |
b32b8144 | 292 | return hana::at_c<n>(static_cast<tuple<Xs...>&&>(xs).storage_); |
7c673cae FG |
293 | } |
294 | ||
b32b8144 FG |
295 | template <> |
296 | struct index_if_impl<tuple_tag> { | |
297 | template <typename ...Xs, typename Pred> | |
298 | static constexpr auto apply(tuple<Xs...> const&, Pred const&) | |
299 | -> typename detail::index_if<Pred, Xs...>::type | |
300 | { return {}; } | |
301 | }; | |
302 | ||
7c673cae FG |
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 | |
315 | tuple<typename detail::decay<Xs>::type...> apply(Xs&& ...xs) | |
316 | { return {static_cast<Xs&&>(xs)...}; } | |
317 | }; | |
7c673cae FG |
318 | BOOST_HANA_NAMESPACE_END |
319 | ||
320 | #endif // !BOOST_HANA_TUPLE_HPP |