summaryrefslogtreecommitdiff
path: root/boost/hof/lazy.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/hof/lazy.hpp')
-rw-r--r--boost/hof/lazy.hpp299
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