1 // Copyright Louis Dionne 2013-2016
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
5 #include <boost/hana/at.hpp>
6 #include <boost/hana/bool.hpp>
7 #include <boost/hana/config.hpp>
8 #include <boost/hana/detail/variadic/at.hpp>
9 #include <boost/hana/detail/variadic/drop_into.hpp>
10 #include <boost/hana/detail/variadic/take.hpp>
11 #include <boost/hana/functional/always.hpp>
12 #include <boost/hana/functional/id.hpp>
13 #include <boost/hana/functional/on.hpp>
14 #include <boost/hana/fwd/append.hpp>
15 #include <boost/hana/fwd/at.hpp>
16 #include <boost/hana/fwd/concat.hpp>
17 #include <boost/hana/fwd/concept/sequence.hpp>
18 #include <boost/hana/fwd/core/make.hpp>
19 #include <boost/hana/fwd/drop_front.hpp>
20 #include <boost/hana/fwd/empty.hpp>
21 #include <boost/hana/fwd/front.hpp>
22 #include <boost/hana/fwd/prepend.hpp>
23 #include <boost/hana/fwd/take_front.hpp>
24 #include <boost/hana/fwd/transform.hpp>
25 #include <boost/hana/fwd/unpack.hpp>
26 #include <boost/hana/fwd/zip_shortest_with.hpp>
27 #include <boost/hana/integral_constant.hpp>
28 #include <boost/hana/is_empty.hpp>
29 #include <boost/hana/length.hpp>
30 #include <boost/hana/min.hpp>
31 #include <boost/hana/minimum.hpp>
32 #include <boost/hana/range.hpp>
33 #include <boost/hana/unpack.hpp>
36 namespace hana
= boost::hana
;
39 struct lambda_tuple_tag
{ };
41 template <typename Storage
>
42 struct lambda_tuple_t
{
43 explicit constexpr lambda_tuple_t(Storage
&& s
)
44 : storage(std::move(s
))
47 using hana_tag
= lambda_tuple_tag
;
51 BOOST_HANA_CONSTEXPR_LAMBDA
auto lambda_tuple
= [](auto ...xs
) -> decltype(auto) {
52 auto storage
= [=](auto f
) -> decltype(auto) { return f(xs
...); };
53 return lambda_tuple_t
<decltype(storage
)>{std::move(storage
)};
56 namespace boost
{ namespace hana
{
57 //////////////////////////////////////////////////////////////////////////
59 //////////////////////////////////////////////////////////////////////////
61 struct unpack_impl
<lambda_tuple_tag
> {
62 template <typename Xs
, typename F
>
63 static constexpr decltype(auto) apply(Xs
&& xs
, F
&& f
) {
64 return static_cast<Xs
&&>(xs
)
65 .storage(static_cast<F
&&>(f
));
69 //////////////////////////////////////////////////////////////////////////
71 //////////////////////////////////////////////////////////////////////////
73 struct transform_impl
<lambda_tuple_tag
> {
74 template <typename Xs
, typename F
>
75 static constexpr decltype(auto) apply(Xs
&& xs
, F f
) {
76 return static_cast<Xs
&&>(xs
).storage(
77 [f(std::move(f
))](auto&& ...xs
) -> decltype(auto) {
78 return lambda_tuple(f(static_cast<decltype(xs
)&&>(xs
))...);
84 //////////////////////////////////////////////////////////////////////////
86 //////////////////////////////////////////////////////////////////////////
88 struct front_impl
<lambda_tuple_tag
> {
89 template <typename Xs
>
90 static constexpr decltype(auto) apply(Xs
&& xs
) {
91 return static_cast<Xs
&&>(xs
).storage(
92 [](auto&& x
, auto&& ...) -> decltype(auto) {
93 return id(static_cast<decltype(x
)&&>(x
));
100 struct is_empty_impl
<lambda_tuple_tag
> {
101 template <typename Xs
>
102 static constexpr decltype(auto) apply(Xs
&& xs
) {
103 return static_cast<Xs
&&>(xs
).storage(
104 [](auto const& ...xs
) -> decltype(auto) {
105 return hana::bool_c
<sizeof...(xs
) == 0>;
112 struct at_impl
<lambda_tuple_tag
> {
113 template <typename Xs
, typename Index
>
114 static constexpr decltype(auto) apply(Xs
&& xs
, Index
const&) {
115 return static_cast<Xs
&&>(xs
).storage(
116 detail::variadic::at
<Index::value
>
122 struct drop_front_impl
<lambda_tuple_tag
> {
123 template <typename Xs
, typename N
>
124 static constexpr decltype(auto) apply(Xs
&& xs
, N
const& n
) {
125 auto m
= min(n
, length(xs
));
126 return static_cast<Xs
&&>(xs
).storage(
127 detail::variadic::drop_into
<hana::value(m
)>(lambda_tuple
)
132 //////////////////////////////////////////////////////////////////////////
134 //////////////////////////////////////////////////////////////////////////
136 struct concat_impl
<lambda_tuple_tag
> {
137 template <typename Xs
, typename Ys
>
138 static constexpr decltype(auto) apply(Xs
&& xs
, Ys
&& ys
) {
139 return static_cast<Xs
&&>(xs
).storage(
140 [ys(static_cast<Ys
&&>(ys
))](auto&& ...xs
) -> decltype(auto) {
141 return std::move(ys
).storage(
142 // We can't initialize the capture with perfect
143 // forwarding since that's not supported by the
145 [=](auto&& ...ys
) -> decltype(auto) {
148 static_cast<decltype(ys
)&&>(ys
)...
158 struct prepend_impl
<lambda_tuple_tag
> {
159 template <typename Xs
, typename X
>
160 static constexpr decltype(auto) apply(Xs
&& xs
, X
&& x
) {
161 return static_cast<Xs
&&>(xs
).storage(
162 [x(static_cast<X
&&>(x
))](auto&& ...xs
) -> decltype(auto) {
165 static_cast<decltype(xs
)&&>(xs
)...
173 struct append_impl
<lambda_tuple_tag
> {
174 template <typename Xs
, typename X
>
175 static constexpr decltype(auto) apply(Xs
&& xs
, X
&& x
) {
176 return static_cast<Xs
&&>(xs
).storage(
177 [x(static_cast<X
&&>(x
))](auto&& ...xs
) -> decltype(auto) {
179 static_cast<decltype(xs
)&&>(xs
)...,
188 struct empty_impl
<lambda_tuple_tag
> {
189 static BOOST_HANA_CONSTEXPR_LAMBDA
decltype(auto) apply() {
190 return lambda_tuple();
194 //////////////////////////////////////////////////////////////////////////
196 //////////////////////////////////////////////////////////////////////////
198 struct Sequence
<lambda_tuple_tag
> {
199 static constexpr bool value
= true;
203 struct take_front_impl
<lambda_tuple_tag
> {
204 template <typename Xs
, typename N
>
205 static constexpr decltype(auto) apply(Xs
&& xs
, N
const& n
) {
206 auto m
= min(n
, length(xs
));
207 return static_cast<Xs
&&>(xs
).storage(
208 detail::variadic::take
<decltype(m
)::value
>
214 struct zip_shortest_with_impl
<lambda_tuple_tag
> {
215 template <typename F
, typename
...Xss
>
216 static constexpr auto apply(F f
, Xss
...tuples
) {
217 auto go
= [=](auto index
, auto ...nothing
) {
218 return always(f
)(nothing
...)(at(tuples
, index
)...);
220 auto zip_length
= minimum(lambda_tuple(length(tuples
)...));
221 return unpack(make_range(size_c
<0>, zip_length
),
227 //////////////////////////////////////////////////////////////////////////
229 //////////////////////////////////////////////////////////////////////////
231 struct make_impl
<lambda_tuple_tag
> {
232 template <typename
...Xs
>
233 static constexpr decltype(auto) apply(Xs
&& ...xs
) {
234 return lambda_tuple(static_cast<Xs
&&>(xs
)...);
237 }} // end namespace boost::hana
241 auto xs
= lambda_tuple(1, '2', 3.3);
242 static_assert(!decltype(hana::is_empty(xs
))::value
, "");