/*! @file Defines `boost::hana::lazy`. @copyright Louis Dionne 2013-2017 Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) */ #ifndef BOOST_HANA_LAZY_HPP #define BOOST_HANA_LAZY_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace hana { ////////////////////////////////////////////////////////////////////////// // lazy ////////////////////////////////////////////////////////////////////////// template struct lazy_apply_t; namespace detail { struct lazy_secret { }; } template struct lazy_apply_t, F, Args...> : detail::operators::adl<> { template constexpr lazy_apply_t(detail::lazy_secret, T&& ...t) : storage_{static_cast(t)...} { } basic_tuple storage_; using hana_tag = lazy_tag; }; template struct lazy_value_t : detail::operators::adl<> { template constexpr lazy_value_t(detail::lazy_secret, Y&& y) : storage_{static_cast(y)} { } basic_tuple storage_; using hana_tag = lazy_tag; // If this is called, we assume that `X` is in fact a function. template constexpr lazy_apply_t< std::make_index_sequence, X, typename detail::decay::type... > operator()(Args&& ...args) const& { return {detail::lazy_secret{}, hana::at_c<0>(storage_), static_cast(args)...}; } template constexpr lazy_apply_t< std::make_index_sequence, X, typename detail::decay::type... > operator()(Args&& ...args) && { return {detail::lazy_secret{}, static_cast(hana::at_c<0>(storage_)), static_cast(args)... }; } }; ////////////////////////////////////////////////////////////////////////// // make ////////////////////////////////////////////////////////////////////////// template <> struct make_impl { template static constexpr lazy_value_t::type> apply(X&& x) { return {detail::lazy_secret{}, static_cast(x)}; } }; ////////////////////////////////////////////////////////////////////////// // Operators ////////////////////////////////////////////////////////////////////////// namespace detail { template <> struct monad_operators { static constexpr bool value = true; }; } ////////////////////////////////////////////////////////////////////////// // eval for lazy_tag ////////////////////////////////////////////////////////////////////////// template <> struct eval_impl { // lazy_apply_t template static constexpr decltype(auto) apply(lazy_apply_t, F, Args...> const& expr) { return hana::at_c<0>(expr.storage_)( hana::at_c(expr.storage_)... ); } template static constexpr decltype(auto) apply(lazy_apply_t, F, Args...>& expr) { return hana::at_c<0>(expr.storage_)( hana::at_c(expr.storage_)... ); } template static constexpr decltype(auto) apply(lazy_apply_t, F, Args...>&& expr) { return static_cast(hana::at_c<0>(expr.storage_))( static_cast(hana::at_c(expr.storage_))... ); } // lazy_value_t template static constexpr X const& apply(lazy_value_t const& expr) { return hana::at_c<0>(expr.storage_); } template static constexpr X& apply(lazy_value_t& expr) { return hana::at_c<0>(expr.storage_); } template static constexpr X apply(lazy_value_t&& expr) { return static_cast(hana::at_c<0>(expr.storage_)); } }; ////////////////////////////////////////////////////////////////////////// // Functor ////////////////////////////////////////////////////////////////////////// template <> struct transform_impl { template static constexpr auto apply(Expr&& expr, F&& f) { return hana::make_lazy(hana::compose(static_cast(f), hana::eval))( static_cast(expr) ); } }; ////////////////////////////////////////////////////////////////////////// // Applicative ////////////////////////////////////////////////////////////////////////// template <> struct lift_impl { template static constexpr lazy_value_t::type> apply(X&& x) { return {detail::lazy_secret{}, static_cast(x)}; } }; template <> struct ap_impl { template static constexpr decltype(auto) apply(F&& f, X&& x) { return hana::make_lazy(hana::on(hana::apply, hana::eval))( static_cast(f), static_cast(x) ); } }; ////////////////////////////////////////////////////////////////////////// // Monad ////////////////////////////////////////////////////////////////////////// template <> struct flatten_impl { template static constexpr decltype(auto) apply(Expr&& expr) { return hana::make_lazy(hana::compose(hana::eval, hana::eval))( static_cast(expr) ); } }; ////////////////////////////////////////////////////////////////////////// // Comonad ////////////////////////////////////////////////////////////////////////// template <> struct extract_impl { template static constexpr decltype(auto) apply(Expr&& expr) { return hana::eval(static_cast(expr)); } }; template <> struct duplicate_impl { template static constexpr decltype(auto) apply(Expr&& expr) { return hana::make_lazy(static_cast(expr)); } }; template <> struct extend_impl { template static constexpr decltype(auto) apply(Expr&& expr, F&& f) { return hana::make_lazy(static_cast(f))(static_cast(expr)); } }; }} // end namespace boost::hana #endif // !BOOST_HANA_LAZY_HPP