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