]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | // Copyright Louis Dionne 2013-2017 |
7c673cae FG |
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 | ||
b32b8144 FG |
39 | // An interesting way of implementing tuple using lambda captures. |
40 | ||
7c673cae FG |
41 | struct lambda_tuple_tag { }; |
42 | ||
43 | template <typename Storage> | |
44 | struct lambda_tuple_t { | |
45 | 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 | ||
b32b8144 | 53 | auto lambda_tuple = [](auto ...xs) { |
7c673cae FG |
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> | |
65 | static constexpr decltype(auto) apply(Xs&& xs, F&& f) { | |
b32b8144 | 66 | return static_cast<Xs&&>(xs).storage(static_cast<F&&>(f)); |
7c673cae FG |
67 | } |
68 | }; | |
69 | ||
70 | ////////////////////////////////////////////////////////////////////////// | |
71 | // Functor | |
72 | ////////////////////////////////////////////////////////////////////////// | |
73 | template <> | |
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))...); | |
80 | } | |
81 | ); | |
82 | } | |
83 | }; | |
84 | ||
85 | ////////////////////////////////////////////////////////////////////////// | |
86 | // Iterable | |
87 | ////////////////////////////////////////////////////////////////////////// | |
88 | template <> | |
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)); | |
95 | } | |
96 | ); | |
97 | } | |
98 | }; | |
99 | ||
100 | template <> | |
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>; | |
107 | } | |
108 | ); | |
109 | } | |
110 | }; | |
111 | ||
112 | template <> | |
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> | |
118 | ); | |
119 | } | |
120 | }; | |
121 | ||
122 | template <> | |
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) | |
129 | ); | |
130 | } | |
131 | }; | |
132 | ||
133 | ////////////////////////////////////////////////////////////////////////// | |
134 | // MonadPlus | |
135 | ////////////////////////////////////////////////////////////////////////// | |
136 | template <> | |
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 | |
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> | |
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) { | |
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> | |
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) { | |
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> { | |
190 | 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> | |
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> | |
210 | )(lambda_tuple); | |
211 | } | |
212 | }; | |
213 | ||
214 | template <> | |
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)...); | |
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> | |
234 | static constexpr decltype(auto) apply(Xs&& ...xs) { | |
235 | return lambda_tuple(static_cast<Xs&&>(xs)...); | |
236 | } | |
237 | }; | |
238 | }} // end namespace boost::hana | |
239 | ||
240 | ||
241 | int main() { | |
242 | auto xs = lambda_tuple(1, '2', 3.3); | |
243 | static_assert(!decltype(hana::is_empty(xs))::value, ""); | |
244 | } |