1/*============================================================================= 2 Copyright (c) 2012 Paul Fultz II 3 pipable.h 4 Distributed under the Boost Software License, Version 1.0. (See accompanying 5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6==============================================================================*/ 7 8#ifndef BOOST_HOF_GUARD_FUNCTION_PIPABLE_H 9#define BOOST_HOF_GUARD_FUNCTION_PIPABLE_H 10 11/// pipable 12/// ======= 13/// 14/// Description 15/// ----------- 16/// 17/// The `pipable` function adaptor provides an extension method. The first 18/// parameter of the function can be piped into the function using the pipe 19/// `|` operator. This can be especially convenient when there are a lot of 20/// nested function calls. Functions that are made pipable can still be called 21/// the traditional way without piping in the first parameter. 22/// 23/// Synopsis 24/// -------- 25/// 26/// template<class F> 27/// constexpr pipable_adaptor<F> pipable(F f); 28/// 29/// Semantics 30/// --------- 31/// 32/// assert(x | pipable(f)(ys...) == f(x, ys...)); 33/// 34/// Requirements 35/// ------------ 36/// 37/// F must be: 38/// 39/// * [ConstInvocable](ConstInvocable) 40/// * MoveConstructible 41/// 42/// Example 43/// ------- 44/// 45/// #include <boost/hof.hpp> 46/// #include <cassert> 47/// using namespace boost::hof; 48/// 49/// struct sum 50/// { 51/// template<class T, class U> 52/// T operator()(T x, U y) const 53/// { 54/// return x+y; 55/// } 56/// }; 57/// 58/// int main() { 59/// assert(3 == (1 | pipable(sum())(2))); 60/// assert(3 == pipable(sum())(1, 2)); 61/// } 62/// 63/// References 64/// ---------- 65/// 66/// * [Extension methods](<Extension methods>) 67/// 68 69#include <boost/hof/first_of.hpp> 70#include <boost/hof/pack.hpp> 71#include <boost/hof/detail/delegate.hpp> 72#include <boost/hof/detail/move.hpp> 73#include <boost/hof/detail/make.hpp> 74#include <boost/hof/detail/static_const_var.hpp> 75#include <boost/hof/limit.hpp> 76 77namespace boost { namespace hof { 78 79template<class F> 80struct pipable_adaptor; 81 82namespace detail { 83 84template<class F, class Pack> 85struct pipe_closure : F, Pack 86{ 87 88 template<class X, class P> 89 constexpr pipe_closure(X&& fp, P&& packp) 90 BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, X&&) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(Pack, P&&)) 91 : F(BOOST_HOF_FORWARD(X)(fp)), Pack(BOOST_HOF_FORWARD(P)(packp)) 92 {} 93 94 template<class... Ts> 95 constexpr const F& base_function(Ts&&...) const noexcept 96 { 97 return *this; 98 } 99 100 template<class... Ts> 101 constexpr const Pack& get_pack(Ts&&...) const noexcept 102 { 103 return *this; 104 } 105 106 template<class A> 107 struct invoke 108 { 109 A a; 110 const pipe_closure * self; 111 template<class X> 112 constexpr invoke(X&& xp, const pipe_closure * selfp) 113 BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(A, X&&)) 114 : a(BOOST_HOF_FORWARD(X)(xp)), self(selfp) 115 {} 116 117 BOOST_HOF_RETURNS_CLASS(invoke); 118 119 template<class... Ts> 120 constexpr BOOST_HOF_SFINAE_RESULT(const F&, id_<A>, id_<Ts>...) 121 operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS 122 (BOOST_HOF_RETURNS_STATIC_CAST(const F&)(*BOOST_HOF_CONST_THIS->self)(BOOST_HOF_FORWARD(A)(a), BOOST_HOF_FORWARD(Ts)(xs)...)); 123 }; 124 125 BOOST_HOF_RETURNS_CLASS(pipe_closure); 126 127 template<class A> 128 constexpr BOOST_HOF_SFINAE_RESULT(const Pack&, id_<invoke<A&&>>) 129 operator()(A&& a) const BOOST_HOF_SFINAE_RETURNS 130 (BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(a))(invoke<A&&>(BOOST_HOF_FORWARD(A)(a), BOOST_HOF_CONST_THIS))); 131}; 132 133template<class F, class Pack> 134constexpr auto make_pipe_closure(F f, Pack&& p) BOOST_HOF_RETURNS 135( 136 pipe_closure<F, typename std::remove_reference<Pack>::type>(BOOST_HOF_RETURNS_STATIC_CAST(F&&)(f), BOOST_HOF_FORWARD(Pack)(p)) 137); 138 139 140template<class Derived, class F> 141struct pipe_pack 142{ 143 template<class... Ts> 144 constexpr const F& get_function(Ts&&...) const noexcept 145 { 146 return static_cast<const F&>(static_cast<const Derived&>(*this)); 147 } 148 149 BOOST_HOF_RETURNS_CLASS(pipe_pack); 150 151 template<class... Ts, class=typename std::enable_if< 152 (sizeof...(Ts) < function_param_limit<F>::value) 153 >::type> 154 constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS 155 (make_pipe_closure(BOOST_HOF_RETURNS_C_CAST(F&&)(BOOST_HOF_CONST_THIS->get_function(xs...)), boost::hof::pack_forward(BOOST_HOF_FORWARD(Ts)(xs)...))); 156}; 157 158template<class A, class F, class Pack> 159constexpr auto operator|(A&& a, const pipe_closure<F, Pack>& p) BOOST_HOF_RETURNS 160(p(BOOST_HOF_FORWARD(A)(a))); 161 162} 163 164template<class F> 165struct pipable_adaptor 166: detail::basic_first_of_adaptor<detail::callable_base<F>, detail::pipe_pack<pipable_adaptor<F>, detail::callable_base<F>> > 167{ 168 typedef detail::basic_first_of_adaptor<detail::callable_base<F>, detail::pipe_pack<pipable_adaptor<F>, detail::callable_base<F>> > base; 169 typedef pipable_adaptor fit_rewritable_tag; 170 171 BOOST_HOF_INHERIT_CONSTRUCTOR(pipable_adaptor, base); 172 173 constexpr const detail::callable_base<F>& base_function() const noexcept 174 { 175 return *this; 176 } 177}; 178 179template<class A, class F> 180constexpr auto operator|(A&& a, const pipable_adaptor<F>& p) BOOST_HOF_RETURNS 181(p(BOOST_HOF_FORWARD(A)(a))); 182 183BOOST_HOF_DECLARE_STATIC_VAR(pipable, detail::make<pipable_adaptor>); 184 185namespace detail { 186 187template<class F> 188struct static_function_wrapper; 189 190// Operators for static_function_wrapper adaptor 191template<class A, class F> 192auto operator|(A&& a, const boost::hof::detail::static_function_wrapper<F>& f) BOOST_HOF_RETURNS 193(f(BOOST_HOF_FORWARD(A)(a))); 194 195template<class F> 196struct static_default_function; 197 198// Operators for static_default_function adaptor 199template<class A, class F> 200auto operator|(A&& a, const boost::hof::detail::static_default_function<F>& f) BOOST_HOF_RETURNS 201(f(BOOST_HOF_FORWARD(A)(a))); 202 203} 204 205template<class F> 206struct static_; 207 208// Operators for static_ adaptor 209template<class A, class F> 210auto operator|(A&& a, static_<F> f) BOOST_HOF_RETURNS 211(f.base_function().base_function()(BOOST_HOF_FORWARD(A)(a))); 212 213}} // namespace boost::hof 214 215#endif 216