]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*! |
2 | @file | |
3 | Defines `boost::hana::lazy`. | |
4 | ||
5 | @copyright Louis Dionne 2013-2016 | |
6 | Distributed under the Boost Software License, Version 1.0. | |
7 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) | |
8 | */ | |
9 | ||
10 | #ifndef BOOST_HANA_LAZY_HPP | |
11 | #define BOOST_HANA_LAZY_HPP | |
12 | ||
13 | #include <boost/hana/fwd/lazy.hpp> | |
14 | ||
15 | #include <boost/hana/basic_tuple.hpp> | |
16 | #include <boost/hana/config.hpp> | |
17 | #include <boost/hana/core/make.hpp> | |
18 | #include <boost/hana/detail/decay.hpp> | |
19 | #include <boost/hana/detail/operators/adl.hpp> | |
20 | #include <boost/hana/detail/operators/monad.hpp> | |
21 | #include <boost/hana/functional/apply.hpp> | |
22 | #include <boost/hana/functional/compose.hpp> | |
23 | #include <boost/hana/functional/on.hpp> | |
24 | #include <boost/hana/fwd/ap.hpp> | |
25 | #include <boost/hana/fwd/duplicate.hpp> | |
26 | #include <boost/hana/fwd/eval.hpp> | |
27 | #include <boost/hana/fwd/extend.hpp> | |
28 | #include <boost/hana/fwd/extract.hpp> | |
29 | #include <boost/hana/fwd/flatten.hpp> | |
30 | #include <boost/hana/fwd/lift.hpp> | |
31 | #include <boost/hana/fwd/transform.hpp> | |
32 | ||
33 | #include <cstddef> | |
34 | #include <type_traits> | |
35 | #include <utility> | |
36 | ||
37 | ||
38 | BOOST_HANA_NAMESPACE_BEGIN | |
39 | ////////////////////////////////////////////////////////////////////////// | |
40 | // lazy | |
41 | ////////////////////////////////////////////////////////////////////////// | |
42 | template <typename Indices, typename F, typename ...Args> | |
43 | struct lazy_apply_t; | |
44 | ||
45 | namespace detail { struct lazy_secret { }; } | |
46 | ||
47 | template <std::size_t ...n, typename F, typename ...Args> | |
48 | struct lazy_apply_t<std::index_sequence<n...>, F, Args...> | |
49 | : detail::operators::adl<> | |
50 | { | |
51 | template <typename ...T> | |
52 | constexpr lazy_apply_t(detail::lazy_secret, T&& ...t) | |
53 | : storage_{static_cast<T&&>(t)...} | |
54 | { } | |
55 | ||
56 | basic_tuple<F, Args...> storage_; | |
57 | using hana_tag = lazy_tag; | |
58 | }; | |
59 | ||
60 | template <typename X> | |
61 | struct lazy_value_t : detail::operators::adl<> { | |
62 | template <typename Y> | |
63 | constexpr lazy_value_t(detail::lazy_secret, Y&& y) | |
64 | : storage_{static_cast<Y&&>(y)} | |
65 | { } | |
66 | ||
67 | basic_tuple<X> storage_; | |
68 | using hana_tag = lazy_tag; | |
69 | ||
70 | // If this is called, we assume that `X` is in fact a function. | |
71 | template <typename ...Args> | |
72 | constexpr lazy_apply_t< | |
73 | std::make_index_sequence<sizeof...(Args)>, | |
74 | X, typename detail::decay<Args>::type... | |
75 | > operator()(Args&& ...args) const& { | |
76 | return {detail::lazy_secret{}, | |
77 | hana::get_impl<0>(storage_), static_cast<Args&&>(args)...}; | |
78 | } | |
79 | ||
80 | template <typename ...Args> | |
81 | constexpr lazy_apply_t< | |
82 | std::make_index_sequence<sizeof...(Args)>, | |
83 | X, typename detail::decay<Args>::type... | |
84 | > operator()(Args&& ...args) && { | |
85 | return {detail::lazy_secret{}, | |
86 | static_cast<X&&>(hana::get_impl<0>(storage_)), | |
87 | static_cast<Args&&>(args)... | |
88 | }; | |
89 | } | |
90 | }; | |
91 | ||
92 | ////////////////////////////////////////////////////////////////////////// | |
93 | // make<lazy_tag> | |
94 | ////////////////////////////////////////////////////////////////////////// | |
95 | template <> | |
96 | struct make_impl<lazy_tag> { | |
97 | template <typename X> | |
98 | static constexpr lazy_value_t<typename detail::decay<X>::type> apply(X&& x) { | |
99 | return {detail::lazy_secret{}, static_cast<X&&>(x)}; | |
100 | } | |
101 | }; | |
102 | ||
103 | ////////////////////////////////////////////////////////////////////////// | |
104 | // Operators | |
105 | ////////////////////////////////////////////////////////////////////////// | |
106 | namespace detail { | |
107 | template <> | |
108 | struct monad_operators<lazy_tag> { static constexpr bool value = true; }; | |
109 | } | |
110 | ||
111 | ////////////////////////////////////////////////////////////////////////// | |
112 | // eval for lazy_tag | |
113 | ////////////////////////////////////////////////////////////////////////// | |
114 | template <> | |
115 | struct eval_impl<lazy_tag> { | |
116 | // lazy_apply_t | |
117 | template <std::size_t ...n, typename F, typename ...Args> | |
118 | static constexpr decltype(auto) | |
119 | apply(lazy_apply_t<std::index_sequence<n...>, F, Args...> const& expr) { | |
120 | return hana::get_impl<0>(expr.storage_)( | |
121 | hana::get_impl<n+1>(expr.storage_)... | |
122 | ); | |
123 | } | |
124 | ||
125 | template <std::size_t ...n, typename F, typename ...Args> | |
126 | static constexpr decltype(auto) | |
127 | apply(lazy_apply_t<std::index_sequence<n...>, F, Args...>& expr) { | |
128 | return hana::get_impl<0>(expr.storage_)( | |
129 | hana::get_impl<n+1>(expr.storage_)... | |
130 | ); | |
131 | } | |
132 | ||
133 | template <std::size_t ...n, typename F, typename ...Args> | |
134 | static constexpr decltype(auto) | |
135 | apply(lazy_apply_t<std::index_sequence<n...>, F, Args...>&& expr) { | |
136 | return static_cast<F&&>(hana::get_impl<0>(expr.storage_))( | |
137 | static_cast<Args&&>(hana::get_impl<n+1>(expr.storage_))... | |
138 | ); | |
139 | } | |
140 | ||
141 | // lazy_value_t | |
142 | template <typename X> | |
143 | static constexpr X const& apply(lazy_value_t<X> const& expr) | |
144 | { return hana::get_impl<0>(expr.storage_); } | |
145 | ||
146 | template <typename X> | |
147 | static constexpr X& apply(lazy_value_t<X>& expr) | |
148 | { return hana::get_impl<0>(expr.storage_); } | |
149 | ||
150 | template <typename X> | |
151 | static constexpr X apply(lazy_value_t<X>&& expr) | |
152 | { return static_cast<X&&>(hana::get_impl<0>(expr.storage_)); } | |
153 | }; | |
154 | ||
155 | ////////////////////////////////////////////////////////////////////////// | |
156 | // Functor | |
157 | ////////////////////////////////////////////////////////////////////////// | |
158 | template <> | |
159 | struct transform_impl<lazy_tag> { | |
160 | template <typename Expr, typename F> | |
161 | static constexpr auto apply(Expr&& expr, F&& f) { | |
162 | return hana::make_lazy(hana::compose(static_cast<F&&>(f), hana::eval))( | |
163 | static_cast<Expr&&>(expr) | |
164 | ); | |
165 | } | |
166 | }; | |
167 | ||
168 | ////////////////////////////////////////////////////////////////////////// | |
169 | // Applicative | |
170 | ////////////////////////////////////////////////////////////////////////// | |
171 | template <> | |
172 | struct lift_impl<lazy_tag> { | |
173 | template <typename X> | |
174 | static constexpr lazy_value_t<typename detail::decay<X>::type> | |
175 | apply(X&& x) { | |
176 | return {detail::lazy_secret{}, static_cast<X&&>(x)}; | |
177 | } | |
178 | }; | |
179 | ||
180 | template <> | |
181 | struct ap_impl<lazy_tag> { | |
182 | template <typename F, typename X> | |
183 | static constexpr decltype(auto) apply(F&& f, X&& x) { | |
184 | return hana::make_lazy(hana::on(hana::apply, hana::eval))( | |
185 | static_cast<F&&>(f), static_cast<X&&>(x) | |
186 | ); | |
187 | } | |
188 | }; | |
189 | ||
190 | ////////////////////////////////////////////////////////////////////////// | |
191 | // Monad | |
192 | ////////////////////////////////////////////////////////////////////////// | |
193 | template <> | |
194 | struct flatten_impl<lazy_tag> { | |
195 | template <typename Expr> | |
196 | static constexpr decltype(auto) apply(Expr&& expr) { | |
197 | return hana::make_lazy(hana::compose(hana::eval, hana::eval))( | |
198 | static_cast<Expr&&>(expr) | |
199 | ); | |
200 | } | |
201 | }; | |
202 | ||
203 | ////////////////////////////////////////////////////////////////////////// | |
204 | // Comonad | |
205 | ////////////////////////////////////////////////////////////////////////// | |
206 | template <> | |
207 | struct extract_impl<lazy_tag> { | |
208 | template <typename Expr> | |
209 | static constexpr decltype(auto) apply(Expr&& expr) | |
210 | { return hana::eval(static_cast<Expr&&>(expr)); } | |
211 | }; | |
212 | ||
213 | template <> | |
214 | struct duplicate_impl<lazy_tag> { | |
215 | template <typename Expr> | |
216 | static constexpr decltype(auto) apply(Expr&& expr) | |
217 | { return hana::make_lazy(static_cast<Expr&&>(expr)); } | |
218 | }; | |
219 | ||
220 | template <> | |
221 | struct extend_impl<lazy_tag> { | |
222 | template <typename Expr, typename F> | |
223 | static constexpr decltype(auto) apply(Expr&& expr, F&& f) { | |
224 | return hana::make_lazy(static_cast<F&&>(f))(static_cast<Expr&&>(expr)); | |
225 | } | |
226 | }; | |
227 | BOOST_HANA_NAMESPACE_END | |
228 | ||
229 | #endif // !BOOST_HANA_LAZY_HPP |