• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
4 
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>
34 
35 #include <utility>
36 namespace hana = boost::hana;
37 
38 
39 // An interesting way of implementing tuple using lambda captures.
40 
41 struct lambda_tuple_tag { };
42 
43 template <typename Storage>
44 struct lambda_tuple_t {
lambda_tuple_tlambda_tuple_t45     explicit constexpr lambda_tuple_t(Storage&& s)
46         : storage(std::move(s))
47     { }
48 
49     using hana_tag = lambda_tuple_tag;
50     Storage storage;
51 };
52 
__anonc3a3336e0102(auto ...xs) 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)};
56 };
57 
58 namespace boost { namespace hana {
59     //////////////////////////////////////////////////////////////////////////
60     // Foldable
61     //////////////////////////////////////////////////////////////////////////
62     template <>
63     struct unpack_impl<lambda_tuple_tag> {
64         template <typename Xs, typename F>
applyboost::hana::unpack_impl65         static constexpr decltype(auto) apply(Xs&& xs, F&& f) {
66             return static_cast<Xs&&>(xs).storage(static_cast<F&&>(f));
67         }
68     };
69 
70     //////////////////////////////////////////////////////////////////////////
71     // Functor
72     //////////////////////////////////////////////////////////////////////////
73     template <>
74     struct transform_impl<lambda_tuple_tag> {
75         template <typename Xs, typename F>
applyboost::hana::transform_impl76         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))...);
80                 }
81             );
82         }
83     };
84 
85     //////////////////////////////////////////////////////////////////////////
86     // Iterable
87     //////////////////////////////////////////////////////////////////////////
88     template <>
89     struct front_impl<lambda_tuple_tag> {
90         template <typename Xs>
applyboost::hana::front_impl91         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));
95                 }
96             );
97         }
98     };
99 
100     template <>
101     struct is_empty_impl<lambda_tuple_tag> {
102         template <typename Xs>
applyboost::hana::is_empty_impl103         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>;
107                 }
108             );
109         }
110     };
111 
112     template <>
113     struct at_impl<lambda_tuple_tag> {
114         template <typename Xs, typename Index>
applyboost::hana::at_impl115         static constexpr decltype(auto) apply(Xs&& xs, Index const&) {
116             return static_cast<Xs&&>(xs).storage(
117                 detail::variadic::at<Index::value>
118             );
119         }
120     };
121 
122     template <>
123     struct drop_front_impl<lambda_tuple_tag> {
124         template <typename Xs, typename N>
applyboost::hana::drop_front_impl125         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)
129             );
130         }
131     };
132 
133     //////////////////////////////////////////////////////////////////////////
134     // MonadPlus
135     //////////////////////////////////////////////////////////////////////////
136     template <>
137     struct concat_impl<lambda_tuple_tag> {
138         template <typename Xs, typename Ys>
applyboost::hana::concat_impl139         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
145                         // language.
146                         [=](auto&& ...ys) -> decltype(auto) {
147                             return lambda_tuple(
148                                 std::move(xs)...,
149                                 static_cast<decltype(ys)&&>(ys)...
150                             );
151                         }
152                     );
153                 }
154             );
155         }
156     };
157 
158     template <>
159     struct prepend_impl<lambda_tuple_tag> {
160         template <typename Xs, typename X>
applyboost::hana::prepend_impl161         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) {
164                     return lambda_tuple(
165                         std::move(x),
166                         static_cast<decltype(xs)&&>(xs)...
167                     );
168                 }
169             );
170         }
171     };
172 
173     template <>
174     struct append_impl<lambda_tuple_tag> {
175         template <typename Xs, typename X>
applyboost::hana::append_impl176         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) {
179                     return lambda_tuple(
180                         static_cast<decltype(xs)&&>(xs)...,
181                         std::move(x)
182                     );
183                 }
184             );
185         }
186     };
187 
188     template <>
189     struct empty_impl<lambda_tuple_tag> {
applyboost::hana::empty_impl190         static BOOST_HANA_CONSTEXPR_LAMBDA decltype(auto) apply() {
191             return lambda_tuple();
192         }
193     };
194 
195     //////////////////////////////////////////////////////////////////////////
196     // Sequence
197     //////////////////////////////////////////////////////////////////////////
198     template <>
199     struct Sequence<lambda_tuple_tag> {
200         static constexpr bool value = true;
201     };
202 
203     template <>
204     struct take_front_impl<lambda_tuple_tag> {
205         template <typename Xs, typename N>
applyboost::hana::take_front_impl206         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>
210             )(lambda_tuple);
211         }
212     };
213 
214     template <>
215     struct zip_shortest_with_impl<lambda_tuple_tag> {
216         template <typename F, typename ...Xss>
applyboost::hana::zip_shortest_with_impl217         static constexpr auto apply(F f, Xss ...tuples) {
218             auto go = [=](auto index, auto ...nothing) {
219                 return always(f)(nothing...)(at(tuples, index)...);
220             };
221             auto zip_length = minimum(lambda_tuple(length(tuples)...));
222             return unpack(make_range(size_c<0>, zip_length),
223                 on(lambda_tuple, go)
224             );
225         }
226     };
227 
228     //////////////////////////////////////////////////////////////////////////
229     // make
230     //////////////////////////////////////////////////////////////////////////
231     template <>
232     struct make_impl<lambda_tuple_tag> {
233         template <typename ...Xs>
applyboost::hana::make_impl234         static constexpr decltype(auto) apply(Xs&& ...xs) {
235             return lambda_tuple(static_cast<Xs&&>(xs)...);
236         }
237     };
238 }} // end namespace boost::hana
239 
240 
main()241 int main() {
242     auto xs = lambda_tuple(1, '2', 3.3);
243     static_assert(!decltype(hana::is_empty(xs))::value, "");
244 }
245