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 77 namespace boost { namespace hof { 78 79 template<class F> 80 struct pipable_adaptor; 81 82 namespace detail { 83 84 template<class F, class Pack> 85 struct pipe_closure : F, Pack 86 { 87 88 template<class X, class P> pipe_closureboost::hof::detail::pipe_closure89 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> base_functionboost::hof::detail::pipe_closure95 constexpr const F& base_function(Ts&&...) const noexcept 96 { 97 return *this; 98 } 99 100 template<class... Ts> get_packboost::hof::detail::pipe_closure101 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> invokeboost::hof::detail::pipe_closure::invoke112 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 133 template<class F, class Pack> 134 constexpr 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 140 template<class Derived, class F> 141 struct pipe_pack 142 { 143 template<class... Ts> get_functionboost::hof::detail::pipe_pack144 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 158 template<class A, class F, class Pack> 159 constexpr auto operator|(A&& a, const pipe_closure<F, Pack>& p) BOOST_HOF_RETURNS 160 (p(BOOST_HOF_FORWARD(A)(a))); 161 162 } 163 164 template<class F> 165 struct 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 base_functionboost::hof::pipable_adaptor173 constexpr const detail::callable_base<F>& base_function() const noexcept 174 { 175 return *this; 176 } 177 }; 178 179 template<class A, class F> 180 constexpr auto operator|(A&& a, const pipable_adaptor<F>& p) BOOST_HOF_RETURNS 181 (p(BOOST_HOF_FORWARD(A)(a))); 182 183 BOOST_HOF_DECLARE_STATIC_VAR(pipable, detail::make<pipable_adaptor>); 184 185 namespace detail { 186 187 template<class F> 188 struct static_function_wrapper; 189 190 // Operators for static_function_wrapper adaptor 191 template<class A, class F> 192 auto operator|(A&& a, const boost::hof::detail::static_function_wrapper<F>& f) BOOST_HOF_RETURNS 193 (f(BOOST_HOF_FORWARD(A)(a))); 194 195 template<class F> 196 struct static_default_function; 197 198 // Operators for static_default_function adaptor 199 template<class A, class F> 200 auto 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 205 template<class F> 206 struct static_; 207 208 // Operators for static_ adaptor 209 template<class A, class F> 210 auto 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