Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:38:15

0001 /*=============================================================================
0002     Copyright (c) 2014 Paul Fultz II
0003     lazy.h
0004     Distributed under the Boost Software License, Version 1.0. (See accompanying
0005     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 ==============================================================================*/
0007 
0008 #ifndef BOOST_HOF_GUARD_FUNCTION_LAZY_H
0009 #define BOOST_HOF_GUARD_FUNCTION_LAZY_H
0010 
0011 /// lazy
0012 /// ====
0013 /// 
0014 /// Description
0015 /// -----------
0016 /// 
0017 /// The `lazy` function adaptor returns a function object call wrapper for a
0018 /// function. Calling this wrapper is equivalent to invoking the function. It
0019 /// is a simple form of lambda expressions, but is constexpr friendly. By
0020 /// default, `lazy` captures all of its variables by value, just like `bind`.
0021 /// `std::ref` can be used to capture references instead.
0022 /// 
0023 /// Ultimately, calling `lazy(f)(x)` is the equivalent to calling
0024 /// `std::bind(f, x)` except the lazy version can be called in a constexpr
0025 /// context, as well. The `lazy` adaptor is compatible with `std::bind`, so
0026 /// most of the time `lazy` and `std::bind` can be used interchangeably.
0027 /// 
0028 /// Synopsis
0029 /// --------
0030 /// 
0031 ///     template<class F>
0032 ///     constexpr lazy_adaptor<F> lazy(F f);
0033 /// 
0034 /// Semantics
0035 /// ---------
0036 /// 
0037 ///     assert(lazy(f)(xs...) == std::bind(f, xs...))
0038 ///     assert(lazy(f)(xs...)() == f(xs...))
0039 ///     assert(lazy(f)(_1)(x) == f(x))
0040 ///     assert(lazy(f)(lazy(g)(_1))(x) == f(g(x)))
0041 /// 
0042 /// Requirements
0043 /// ------------
0044 /// 
0045 /// F must be:
0046 /// 
0047 /// * [ConstInvocable](ConstInvocable)
0048 /// * MoveConstructible
0049 /// 
0050 /// Example
0051 /// -------
0052 /// 
0053 ///     #include <boost/hof.hpp>
0054 ///     #include <cassert>
0055 ///     using namespace boost::hof;
0056 /// 
0057 ///     int main() {
0058 ///         auto add = [](auto x, auto y) { return x+y; };
0059 ///         auto increment = lazy(add)(_1, 1);
0060 ///         assert(increment(5) == 6);
0061 ///     }
0062 /// 
0063 /// References
0064 /// ----------
0065 /// 
0066 /// * [std::bind](http://en.cppreference.com/w/cpp/utility/functional/bind)
0067 /// 
0068 
0069 #include <boost/hof/arg.hpp>
0070 #include <boost/hof/first_of.hpp>
0071 #include <boost/hof/always.hpp>
0072 #include <boost/hof/static.hpp>
0073 #include <boost/hof/detail/delegate.hpp>
0074 #include <boost/hof/detail/compressed_pair.hpp>
0075 #include <boost/hof/pack.hpp>
0076 #include <boost/hof/detail/make.hpp>
0077 #include <boost/hof/detail/static_const_var.hpp>
0078 #include <functional>
0079 #include <type_traits>
0080 
0081 namespace boost { namespace hof {
0082 
0083 namespace detail {
0084 
0085 struct placeholder_transformer
0086 {
0087     template<class T, typename std::enable_if<(std::is_placeholder<T>::value > 0), int>::type = 0>
0088     constexpr detail::make_args_f<std::size_t, std::is_placeholder<T>::value> operator()(const T&) const noexcept
0089     {
0090         return {};
0091     }
0092 };
0093 
0094 struct bind_transformer
0095 {
0096     template<class T, typename std::enable_if<std::is_bind_expression<T>::value, int>::type = 0>
0097     constexpr const T& operator()(const T& x) const noexcept
0098     {
0099         return x;
0100     }
0101 };
0102 
0103 struct ref_transformer
0104 {
0105     template<class T>
0106     constexpr auto operator()(std::reference_wrapper<T> x) const 
0107     BOOST_HOF_SFINAE_RETURNS(boost::hof::always_ref(x.get()));
0108 };
0109 
0110 struct id_transformer
0111 {
0112     template<class T>
0113     constexpr auto operator()(T&& x) const 
0114     BOOST_HOF_SFINAE_RETURNS(always_detail::always_base<T>(BOOST_HOF_FORWARD(T)(x)));
0115 };
0116 
0117 BOOST_HOF_DECLARE_STATIC_VAR(pick_transformer, first_of_adaptor<placeholder_transformer, bind_transformer, ref_transformer, id_transformer>);
0118 
0119 template<class T, class Pack>
0120 constexpr auto lazy_transform(T&& x, const Pack& p) BOOST_HOF_RETURNS
0121 (
0122     p(boost::hof::detail::pick_transformer(BOOST_HOF_FORWARD(T)(x)))
0123 );
0124 
0125 template<class F, class Pack>
0126 struct lazy_unpack
0127 {
0128     const F& f;
0129     const Pack& p;
0130 
0131     constexpr lazy_unpack(const F& fp, const Pack& pp) noexcept
0132     : f(fp), p(pp)
0133     {}
0134 
0135     template<class... Ts>
0136     constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
0137     (
0138         f(lazy_transform(BOOST_HOF_FORWARD(Ts)(xs), p)...)
0139     );
0140 };
0141 
0142 template<class F, class Pack>
0143 constexpr lazy_unpack<F, Pack> make_lazy_unpack(const F& f, const Pack& p) noexcept
0144 {
0145     return lazy_unpack<F, Pack>(f, p);
0146 }
0147 
0148 template<class F, class Pack>
0149 struct lazy_invoker 
0150 : detail::compressed_pair<F, Pack>
0151 {
0152     typedef detail::compressed_pair<F, Pack> base_type;
0153     typedef lazy_invoker fit_rewritable1_tag;
0154 
0155 #ifdef _MSC_VER
0156     BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_invoker, base_type)
0157 #else
0158     BOOST_HOF_INHERIT_DEFAULT_EMPTY(lazy_invoker, base_type)
0159 
0160     template<class X, class Y, 
0161         BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(base_type, X&&, Y&&)
0162     >
0163     constexpr lazy_invoker(X&& x, Y&& y) 
0164     BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base_type, X&&, Y&&)
0165     : base_type(BOOST_HOF_FORWARD(X)(x), BOOST_HOF_FORWARD(Y)(y))
0166     {}
0167 #endif
0168 
0169     template<class... Ts>
0170     constexpr const F& base_function(Ts&&... xs) const noexcept
0171     {
0172         return this->first(xs...);
0173     }
0174 
0175     template<class... Ts>
0176     constexpr const Pack& get_pack(Ts&&... xs) const noexcept
0177     {
0178         return this->second(xs...);
0179     }
0180 
0181     BOOST_HOF_RETURNS_CLASS(lazy_invoker);
0182 
0183     template<class... Ts>
0184     constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
0185     (
0186         BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(xs...))(
0187             boost::hof::detail::make_lazy_unpack(
0188                 BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...)), 
0189                 boost::hof::pack_forward(BOOST_HOF_FORWARD(Ts)(xs)...)
0190             )
0191         )
0192     );
0193 };
0194 
0195 template<class F, class Pack>
0196 constexpr lazy_invoker<F, Pack> make_lazy_invoker(F f, Pack pack)
0197 BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(lazy_invoker<F, Pack>, F&&, Pack&&)
0198 {
0199     return lazy_invoker<F, Pack>(static_cast<F&&>(f), static_cast<Pack&&>(pack));
0200 }
0201 
0202 template<class F>
0203 struct lazy_nullary_invoker : F
0204 {
0205     BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_nullary_invoker, F);
0206 
0207     template<class... Ts>
0208     constexpr const F& base_function(Ts&&... xs) const noexcept
0209     {
0210         return boost::hof::always_ref(*this)(xs...);
0211     }
0212 
0213     BOOST_HOF_RETURNS_CLASS(lazy_nullary_invoker);
0214 
0215     template<class... Ts>
0216     constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
0217     (
0218         BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...))()
0219     );
0220 };
0221 
0222 template<class F>
0223 constexpr lazy_nullary_invoker<F> make_lazy_nullary_invoker(F f)
0224 BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(lazy_nullary_invoker<F>, F&&)
0225 {
0226     return lazy_nullary_invoker<F>(static_cast<F&&>(f));
0227 }
0228 }
0229 
0230 
0231 template<class F>
0232 struct lazy_adaptor : detail::callable_base<F>
0233 {
0234     BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_adaptor, detail::callable_base<F>);
0235 
0236     template<class... Ts>
0237     constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept
0238     {
0239         return boost::hof::always_ref(*this)(xs...);
0240     }
0241 
0242     BOOST_HOF_RETURNS_CLASS(lazy_adaptor);
0243 
0244     template<class T, class... Ts>
0245     constexpr auto operator()(T x, Ts... xs) const BOOST_HOF_RETURNS
0246     (
0247         boost::hof::detail::make_lazy_invoker(BOOST_HOF_RETURNS_C_CAST(detail::callable_base<F>&&)(BOOST_HOF_CONST_THIS->base_function(x, xs...)), 
0248             boost::hof::pack_basic(BOOST_HOF_RETURNS_STATIC_CAST(T&&)(x), BOOST_HOF_RETURNS_STATIC_CAST(Ts&&)(xs)...))
0249     );
0250 
0251     // Workaround for gcc 4.7
0252     template<class Unused=int>
0253     constexpr detail::lazy_nullary_invoker<F> operator()() const
0254     BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(
0255         boost::hof::detail::make_lazy_nullary_invoker(BOOST_HOF_RETURNS_C_CAST(detail::callable_base<F>&&)(
0256             BOOST_HOF_CONST_THIS->base_function(BOOST_HOF_RETURNS_CONSTRUCT(Unused)())
0257         ))
0258     )
0259     {
0260         return boost::hof::detail::make_lazy_nullary_invoker((detail::callable_base<F>&&)(
0261             this->base_function(Unused())
0262         ));
0263     }
0264 
0265     // TODO: Overloads to use with ref qualifiers
0266 
0267     // template<class... Ts>
0268     // constexpr auto operator()(Ts... xs) const& BOOST_HOF_RETURNS
0269     // (
0270     //     boost::hof::detail::make_lazy_invoker(this->base_function(xs...), 
0271     //         pack(boost::hof::move(xs)...))
0272     // );
0273 
0274     // template<class... Ts>
0275     // constexpr auto operator()(Ts... xs) && BOOST_HOF_RETURNS
0276     // (
0277     //     boost::hof::detail::make_lazy_invoker((F&&)this->base_function(xs...), 
0278     //         pack(boost::hof::move(xs)...))
0279     // );
0280     
0281 };
0282 
0283 BOOST_HOF_DECLARE_STATIC_VAR(lazy, detail::make<lazy_adaptor>);
0284 
0285 }} // namespace boost::hof
0286 
0287 namespace std {
0288     template<class F, class Pack>
0289     struct is_bind_expression<boost::hof::detail::lazy_invoker<F, Pack>>
0290     : std::true_type
0291     {};
0292 
0293     template<class F>
0294     struct is_bind_expression<boost::hof::detail::lazy_nullary_invoker<F>>
0295     : std::true_type
0296     {};
0297 }
0298 
0299 #endif