Line data Source code
1 : /*!
2 : @file
3 : Defines `boost::hana::tuple`.
4 :
5 : Copyright Louis Dionne 2013-2022
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 : namespace boost { namespace hana {
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)(
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 : {
86 : 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>
104 : 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>
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 :
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>
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
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>
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 983945 : static constexpr decltype(auto) apply(Xs&& xs, F&& f) {
233 983945 : 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;
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>
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<
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>
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) {
282 : return hana::at_c<n>(xs.storage_);
283 : }
284 :
285 : template <std::size_t n, typename ...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>
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>
298 : 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
315 : tuple<typename detail::decay<Xs>::type...> apply(Xs&& ...xs)
316 : { return {static_cast<Xs&&>(xs)...}; }
317 : };
318 : }} // end namespace boost::hana
319 :
320 : #endif // !BOOST_HANA_TUPLE_HPP
|