• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*!
2 @file
3 Defines `boost::hana::lazy`.
4 
5 @copyright Louis Dionne 2013-2017
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>
lazy_apply_tlazy_apply_t52         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>
lazy_value_tlazy_value_t63         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...
operator ()lazy_value_t75         > operator()(Args&& ...args) const& {
76             return {detail::lazy_secret{},
77                     hana::at_c<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...
operator ()lazy_value_t84         > operator()(Args&& ...args) && {
85             return {detail::lazy_secret{},
86                 static_cast<X&&>(hana::at_c<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>
applymake_impl98         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)
applyeval_impl119         apply(lazy_apply_t<std::index_sequence<n...>, F, Args...> const& expr) {
120             return hana::at_c<0>(expr.storage_)(
121                 hana::at_c<n+1>(expr.storage_)...
122             );
123         }
124 
125         template <std::size_t ...n, typename F, typename ...Args>
126         static constexpr decltype(auto)
applyeval_impl127         apply(lazy_apply_t<std::index_sequence<n...>, F, Args...>& expr) {
128             return hana::at_c<0>(expr.storage_)(
129                 hana::at_c<n+1>(expr.storage_)...
130             );
131         }
132 
133         template <std::size_t ...n, typename F, typename ...Args>
134         static constexpr decltype(auto)
applyeval_impl135         apply(lazy_apply_t<std::index_sequence<n...>, F, Args...>&& expr) {
136             return static_cast<F&&>(hana::at_c<0>(expr.storage_))(
137                 static_cast<Args&&>(hana::at_c<n+1>(expr.storage_))...
138             );
139         }
140 
141         // lazy_value_t
142         template <typename X>
applyeval_impl143         static constexpr X const& apply(lazy_value_t<X> const& expr)
144         { return hana::at_c<0>(expr.storage_); }
145 
146         template <typename X>
applyeval_impl147         static constexpr X& apply(lazy_value_t<X>& expr)
148         { return hana::at_c<0>(expr.storage_); }
149 
150         template <typename X>
applyeval_impl151         static constexpr X apply(lazy_value_t<X>&& expr)
152         { return static_cast<X&&>(hana::at_c<0>(expr.storage_)); }
153     };
154 
155     //////////////////////////////////////////////////////////////////////////
156     // Functor
157     //////////////////////////////////////////////////////////////////////////
158     template <>
159     struct transform_impl<lazy_tag> {
160         template <typename Expr, typename F>
applytransform_impl161         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>
applylift_impl175         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>
applyap_impl183         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>
applyflatten_impl196         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>
applyextract_impl209         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>
applyduplicate_impl216         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>
applyextend_impl223         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
230