diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:12:59 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:12:59 +0900 |
commit | b8cf34c691623e4ec329053cbbf68522a855882d (patch) | |
tree | 34da08632a99677f6b79ecb65e5b655a5b69a67f /boost/hof/lazy.hpp | |
parent | 3fdc3e5ee96dca5b11d1694975a65200787eab86 (diff) | |
download | boost-b8cf34c691623e4ec329053cbbf68522a855882d.tar.gz boost-b8cf34c691623e4ec329053cbbf68522a855882d.tar.bz2 boost-b8cf34c691623e4ec329053cbbf68522a855882d.zip |
Imported Upstream version 1.67.0upstream/1.67.0
Diffstat (limited to 'boost/hof/lazy.hpp')
-rw-r--r-- | boost/hof/lazy.hpp | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/boost/hof/lazy.hpp b/boost/hof/lazy.hpp new file mode 100644 index 0000000000..713e78a87b --- /dev/null +++ b/boost/hof/lazy.hpp @@ -0,0 +1,299 @@ +/*============================================================================= + 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 |