123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- /*=============================================================================
- Copyright (c) 2014 Paul Fultz II
- lazy.h
- Distributed under the Boost Software License, Version 1.0. (See accompanying
- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- ==============================================================================*/
- #ifndef BOOST_HOF_GUARD_FUNCTION_LAZY_H
- #define BOOST_HOF_GUARD_FUNCTION_LAZY_H
- /// lazy
- /// ====
- ///
- /// Description
- /// -----------
- ///
- /// The `lazy` function adaptor returns a function object call wrapper for a
- /// function. Calling this wrapper is equivalent to invoking the function. It
- /// is a simple form of lambda expressions, but is constexpr friendly. By
- /// default, `lazy` captures all of its variables by value, just like `bind`.
- /// `std::ref` can be used to capture references instead.
- ///
- /// Ultimately, calling `lazy(f)(x)` is the equivalent to calling
- /// `std::bind(f, x)` except the lazy version can be called in a constexpr
- /// context, as well. The `lazy` adaptor is compatible with `std::bind`, so
- /// most of the time `lazy` and `std::bind` can be used interchangeably.
- ///
- /// Synopsis
- /// --------
- ///
- /// template<class F>
- /// constexpr lazy_adaptor<F> lazy(F f);
- ///
- /// Semantics
- /// ---------
- ///
- /// assert(lazy(f)(xs...) == std::bind(f, xs...))
- /// assert(lazy(f)(xs...)() == f(xs...))
- /// assert(lazy(f)(_1)(x) == f(x))
- /// assert(lazy(f)(lazy(g)(_1))(x) == f(g(x)))
- ///
- /// Requirements
- /// ------------
- ///
- /// F must be:
- ///
- /// * [ConstInvocable](ConstInvocable)
- /// * MoveConstructible
- ///
- /// Example
- /// -------
- ///
- /// #include <boost/hof.hpp>
- /// #include <cassert>
- /// using namespace boost::hof;
- ///
- /// int main() {
- /// auto add = [](auto x, auto y) { return x+y; };
- /// auto increment = lazy(add)(_1, 1);
- /// assert(increment(5) == 6);
- /// }
- ///
- /// References
- /// ----------
- ///
- /// * [std::bind](http://en.cppreference.com/w/cpp/utility/functional/bind)
- ///
- #include <boost/hof/arg.hpp>
- #include <boost/hof/first_of.hpp>
- #include <boost/hof/always.hpp>
- #include <boost/hof/static.hpp>
- #include <boost/hof/detail/delegate.hpp>
- #include <boost/hof/detail/compressed_pair.hpp>
- #include <boost/hof/pack.hpp>
- #include <boost/hof/detail/make.hpp>
- #include <boost/hof/detail/static_const_var.hpp>
- #include <functional>
- #include <type_traits>
- namespace boost { namespace hof {
- namespace detail {
- struct placeholder_transformer
- {
- template<class T, typename std::enable_if<(std::is_placeholder<T>::value > 0), int>::type = 0>
- constexpr detail::make_args_f<std::size_t, std::is_placeholder<T>::value> operator()(const T&) const noexcept
- {
- return {};
- }
- };
- struct bind_transformer
- {
- template<class T, typename std::enable_if<std::is_bind_expression<T>::value, int>::type = 0>
- constexpr const T& operator()(const T& x) const noexcept
- {
- return x;
- }
- };
- struct ref_transformer
- {
- template<class T>
- constexpr auto operator()(std::reference_wrapper<T> x) const
- BOOST_HOF_SFINAE_RETURNS(boost::hof::always_ref(x.get()));
- };
- struct id_transformer
- {
- template<class T>
- constexpr auto operator()(T&& x) const
- BOOST_HOF_SFINAE_RETURNS(always_detail::always_base<T>(BOOST_HOF_FORWARD(T)(x)));
- };
- BOOST_HOF_DECLARE_STATIC_VAR(pick_transformer, first_of_adaptor<placeholder_transformer, bind_transformer, ref_transformer, id_transformer>);
- template<class T, class Pack>
- constexpr auto lazy_transform(T&& x, const Pack& p) BOOST_HOF_RETURNS
- (
- p(boost::hof::detail::pick_transformer(BOOST_HOF_FORWARD(T)(x)))
- );
- template<class F, class Pack>
- struct lazy_unpack
- {
- const F& f;
- const Pack& p;
- constexpr lazy_unpack(const F& fp, const Pack& pp) noexcept
- : f(fp), p(pp)
- {}
- template<class... Ts>
- constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
- (
- f(lazy_transform(BOOST_HOF_FORWARD(Ts)(xs), p)...)
- );
- };
- template<class F, class Pack>
- constexpr lazy_unpack<F, Pack> make_lazy_unpack(const F& f, const Pack& p) noexcept
- {
- return lazy_unpack<F, Pack>(f, p);
- }
- template<class F, class Pack>
- struct lazy_invoker
- : detail::compressed_pair<F, Pack>
- {
- typedef detail::compressed_pair<F, Pack> base_type;
- typedef lazy_invoker fit_rewritable1_tag;
- #ifdef _MSC_VER
- BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_invoker, base_type)
- #else
- BOOST_HOF_INHERIT_DEFAULT_EMPTY(lazy_invoker, base_type)
- template<class X, class Y,
- BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(base_type, X&&, Y&&)
- >
- constexpr lazy_invoker(X&& x, Y&& y)
- BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base_type, X&&, Y&&)
- : base_type(BOOST_HOF_FORWARD(X)(x), BOOST_HOF_FORWARD(Y)(y))
- {}
- #endif
- template<class... Ts>
- constexpr const F& base_function(Ts&&... xs) const noexcept
- {
- return this->first(xs...);
- }
- template<class... Ts>
- constexpr const Pack& get_pack(Ts&&... xs) const noexcept
- {
- return this->second(xs...);
- }
- BOOST_HOF_RETURNS_CLASS(lazy_invoker);
- template<class... Ts>
- constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
- (
- BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(xs...))(
- boost::hof::detail::make_lazy_unpack(
- BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...)),
- boost::hof::pack_forward(BOOST_HOF_FORWARD(Ts)(xs)...)
- )
- )
- );
- };
- template<class F, class Pack>
- constexpr lazy_invoker<F, Pack> make_lazy_invoker(F f, Pack pack)
- BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(lazy_invoker<F, Pack>, F&&, Pack&&)
- {
- return lazy_invoker<F, Pack>(static_cast<F&&>(f), static_cast<Pack&&>(pack));
- }
- template<class F>
- struct lazy_nullary_invoker : F
- {
- BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_nullary_invoker, F);
- template<class... Ts>
- constexpr const F& base_function(Ts&&... xs) const noexcept
- {
- return boost::hof::always_ref(*this)(xs...);
- }
- BOOST_HOF_RETURNS_CLASS(lazy_nullary_invoker);
- template<class... Ts>
- constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
- (
- BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...))()
- );
- };
- template<class F>
- constexpr lazy_nullary_invoker<F> make_lazy_nullary_invoker(F f)
- BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(lazy_nullary_invoker<F>, F&&)
- {
- return lazy_nullary_invoker<F>(static_cast<F&&>(f));
- }
- }
- template<class F>
- struct lazy_adaptor : detail::callable_base<F>
- {
- BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_adaptor, detail::callable_base<F>);
- template<class... Ts>
- constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept
- {
- return boost::hof::always_ref(*this)(xs...);
- }
- BOOST_HOF_RETURNS_CLASS(lazy_adaptor);
- template<class T, class... Ts>
- constexpr auto operator()(T x, Ts... xs) const BOOST_HOF_RETURNS
- (
- boost::hof::detail::make_lazy_invoker(BOOST_HOF_RETURNS_C_CAST(detail::callable_base<F>&&)(BOOST_HOF_CONST_THIS->base_function(x, xs...)),
- boost::hof::pack_basic(BOOST_HOF_RETURNS_STATIC_CAST(T&&)(x), BOOST_HOF_RETURNS_STATIC_CAST(Ts&&)(xs)...))
- );
- // Workaround for gcc 4.7
- template<class Unused=int>
- constexpr detail::lazy_nullary_invoker<F> operator()() const
- BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(
- boost::hof::detail::make_lazy_nullary_invoker(BOOST_HOF_RETURNS_C_CAST(detail::callable_base<F>&&)(
- BOOST_HOF_CONST_THIS->base_function(BOOST_HOF_RETURNS_CONSTRUCT(Unused)())
- ))
- )
- {
- return boost::hof::detail::make_lazy_nullary_invoker((detail::callable_base<F>&&)(
- this->base_function(Unused())
- ));
- }
- // TODO: Overloads to use with ref qualifiers
- // template<class... Ts>
- // constexpr auto operator()(Ts... xs) const& BOOST_HOF_RETURNS
- // (
- // boost::hof::detail::make_lazy_invoker(this->base_function(xs...),
- // pack(boost::hof::move(xs)...))
- // );
- // template<class... Ts>
- // constexpr auto operator()(Ts... xs) && BOOST_HOF_RETURNS
- // (
- // boost::hof::detail::make_lazy_invoker((F&&)this->base_function(xs...),
- // pack(boost::hof::move(xs)...))
- // );
-
- };
- BOOST_HOF_DECLARE_STATIC_VAR(lazy, detail::make<lazy_adaptor>);
- }} // namespace boost::hof
- namespace std {
- template<class F, class Pack>
- struct is_bind_expression<boost::hof::detail::lazy_invoker<F, Pack>>
- : std::true_type
- {};
- template<class F>
- struct is_bind_expression<boost::hof::detail::lazy_nullary_invoker<F>>
- : std::true_type
- {};
- }
- #endif
|