1 // Copyright Louis Dionne 2013-2017
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 // An interesting way of implementing tuple using lambda captures.
41 struct lambda_tuple_tag
{ };
43 template <typename Storage
>
44 struct lambda_tuple_t
{
45 explicit constexpr lambda_tuple_t(Storage
&& s
)
46 : storage(std::move(s
))
49 using hana_tag
= lambda_tuple_tag
;
53 auto lambda_tuple
= [](auto ...xs
) {
54 auto storage
= [=](auto f
) -> decltype(auto) { return f(xs
...); };
55 return lambda_tuple_t
<decltype(storage
)>{std::move(storage
)};
58 namespace boost
{ namespace hana
{
59 //////////////////////////////////////////////////////////////////////////
61 //////////////////////////////////////////////////////////////////////////
63 struct unpack_impl
<lambda_tuple_tag
> {
64 template <typename Xs
, typename F
>
65 static constexpr decltype(auto) apply(Xs
&& xs
, F
&& f
) {
66 return static_cast<Xs
&&>(xs
).storage(static_cast<F
&&>(f
));
70 //////////////////////////////////////////////////////////////////////////
72 //////////////////////////////////////////////////////////////////////////
74 struct transform_impl
<lambda_tuple_tag
> {
75 template <typename Xs
, typename F
>
76 static constexpr decltype(auto) apply(Xs
&& xs
, F f
) {
77 return static_cast<Xs
&&>(xs
).storage(
78 [f(std::move(f
))](auto&& ...xs
) -> decltype(auto) {
79 return lambda_tuple(f(static_cast<decltype(xs
)&&>(xs
))...);
85 //////////////////////////////////////////////////////////////////////////
87 //////////////////////////////////////////////////////////////////////////
89 struct front_impl
<lambda_tuple_tag
> {
90 template <typename Xs
>
91 static constexpr decltype(auto) apply(Xs
&& xs
) {
92 return static_cast<Xs
&&>(xs
).storage(
93 [](auto&& x
, auto&& ...) -> decltype(auto) {
94 return id(static_cast<decltype(x
)&&>(x
));
101 struct is_empty_impl
<lambda_tuple_tag
> {
102 template <typename Xs
>
103 static constexpr decltype(auto) apply(Xs
&& xs
) {
104 return static_cast<Xs
&&>(xs
).storage(
105 [](auto const& ...xs
) -> decltype(auto) {
106 return hana::bool_c
<sizeof...(xs
) == 0>;
113 struct at_impl
<lambda_tuple_tag
> {
114 template <typename Xs
, typename Index
>
115 static constexpr decltype(auto) apply(Xs
&& xs
, Index
const&) {
116 return static_cast<Xs
&&>(xs
).storage(
117 detail::variadic::at
<Index::value
>
123 struct drop_front_impl
<lambda_tuple_tag
> {
124 template <typename Xs
, typename N
>
125 static constexpr decltype(auto) apply(Xs
&& xs
, N
const& n
) {
126 auto m
= min(n
, length(xs
));
127 return static_cast<Xs
&&>(xs
).storage(
128 detail::variadic::drop_into
<hana::value(m
)>(lambda_tuple
)
133 //////////////////////////////////////////////////////////////////////////
135 //////////////////////////////////////////////////////////////////////////
137 struct concat_impl
<lambda_tuple_tag
> {
138 template <typename Xs
, typename Ys
>
139 static constexpr decltype(auto) apply(Xs
&& xs
, Ys
&& ys
) {
140 return static_cast<Xs
&&>(xs
).storage(
141 [ys(static_cast<Ys
&&>(ys
))](auto&& ...xs
) -> decltype(auto) {
142 return std::move(ys
).storage(
143 // We can't initialize the capture with perfect
144 // forwarding since that's not supported by the
146 [=](auto&& ...ys
) -> decltype(auto) {
149 static_cast<decltype(ys
)&&>(ys
)...
159 struct prepend_impl
<lambda_tuple_tag
> {
160 template <typename Xs
, typename X
>
161 static constexpr decltype(auto) apply(Xs
&& xs
, X
&& x
) {
162 return static_cast<Xs
&&>(xs
).storage(
163 [x(static_cast<X
&&>(x
))](auto&& ...xs
) -> decltype(auto) {
166 static_cast<decltype(xs
)&&>(xs
)...
174 struct append_impl
<lambda_tuple_tag
> {
175 template <typename Xs
, typename X
>
176 static constexpr decltype(auto) apply(Xs
&& xs
, X
&& x
) {
177 return static_cast<Xs
&&>(xs
).storage(
178 [x(static_cast<X
&&>(x
))](auto&& ...xs
) -> decltype(auto) {
180 static_cast<decltype(xs
)&&>(xs
)...,
189 struct empty_impl
<lambda_tuple_tag
> {
190 static BOOST_HANA_CONSTEXPR_LAMBDA
decltype(auto) apply() {
191 return lambda_tuple();
195 //////////////////////////////////////////////////////////////////////////
197 //////////////////////////////////////////////////////////////////////////
199 struct Sequence
<lambda_tuple_tag
> {
200 static constexpr bool value
= true;
204 struct take_front_impl
<lambda_tuple_tag
> {
205 template <typename Xs
, typename N
>
206 static constexpr decltype(auto) apply(Xs
&& xs
, N
const& n
) {
207 auto m
= min(n
, length(xs
));
208 return static_cast<Xs
&&>(xs
).storage(
209 detail::variadic::take
<decltype(m
)::value
>
215 struct zip_shortest_with_impl
<lambda_tuple_tag
> {
216 template <typename F
, typename
...Xss
>
217 static constexpr auto apply(F f
, Xss
...tuples
) {
218 auto go
= [=](auto index
, auto ...nothing
) {
219 return always(f
)(nothing
...)(at(tuples
, index
)...);
221 auto zip_length
= minimum(lambda_tuple(length(tuples
)...));
222 return unpack(make_range(size_c
<0>, zip_length
),
228 //////////////////////////////////////////////////////////////////////////
230 //////////////////////////////////////////////////////////////////////////
232 struct make_impl
<lambda_tuple_tag
> {
233 template <typename
...Xs
>
234 static constexpr decltype(auto) apply(Xs
&& ...xs
) {
235 return lambda_tuple(static_cast<Xs
&&>(xs
)...);
238 }} // end namespace boost::hana
242 auto xs
= lambda_tuple(1, '2', 3.3);
243 static_assert(!decltype(hana::is_empty(xs
))::value
, "");