1 /*============================================================================= 2 Copyright (c) 2015 Paul Fultz II 3 flow.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_FLOW_H 9 #define BOOST_HOF_GUARD_FUNCTION_FLOW_H 10 11 /// flow 12 /// ==== 13 /// 14 /// Description 15 /// ----------- 16 /// 17 /// The `flow` function adaptor provides function composition. It is useful as 18 /// an alternative to using the pipe operator `|` when chaining functions. It is 19 /// similiar to [`compose`](compose.md) except the evaluation order is 20 /// reversed. So, `flow(f, g)(0)` is equivalent to `g(f(0))`. 21 /// 22 /// 23 /// Synopsis 24 /// -------- 25 /// 26 /// template<class... Fs> 27 /// constexpr flow_adaptor<Fs...> flow(Fs... fs); 28 /// 29 /// Semantics 30 /// --------- 31 /// 32 /// assert(flow(f, g)(xs...) == g(f(xs...))); 33 /// 34 /// Requirements 35 /// ------------ 36 /// 37 /// Fs 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 increment 50 /// { 51 /// template<class T> 52 /// T operator()(T x) const 53 /// { 54 /// return x + 1; 55 /// } 56 /// }; 57 /// 58 /// struct decrement 59 /// { 60 /// template<class T> 61 /// T operator()(T x) const 62 /// { 63 /// return x - 1; 64 /// } 65 /// }; 66 /// 67 /// int main() { 68 /// int r = flow(increment(), decrement(), increment())(3); 69 /// assert(r == 4); 70 /// } 71 /// 72 /// References 73 /// ---------- 74 /// 75 /// * [Function composition](https://en.wikipedia.org/wiki/Function_composition) 76 /// 77 78 #include <boost/hof/detail/callable_base.hpp> 79 #include <boost/hof/always.hpp> 80 #include <boost/hof/detail/delegate.hpp> 81 #include <boost/hof/detail/compressed_pair.hpp> 82 #include <boost/hof/detail/join.hpp> 83 #include <tuple> 84 #include <boost/hof/detail/move.hpp> 85 #include <boost/hof/detail/make.hpp> 86 #include <boost/hof/detail/result_type.hpp> 87 #include <boost/hof/detail/static_const_var.hpp> 88 89 namespace boost { namespace hof { namespace detail { 90 91 template<class F1, class F2> 92 struct flow_kernel : detail::compressed_pair<detail::callable_base<F1>, detail::callable_base<F2>>, compose_function_result_type<F2, F1> 93 { 94 typedef detail::compressed_pair<detail::callable_base<F1>, detail::callable_base<F2>> base_type; 95 96 BOOST_HOF_INHERIT_CONSTRUCTOR(flow_kernel, base_type) 97 98 BOOST_HOF_RETURNS_CLASS(flow_kernel); 99 100 template<class... Ts> 101 constexpr BOOST_HOF_SFINAE_RESULT(const detail::callable_base<F2>&, result_of<const detail::callable_base<F1>&, id_<Ts>...>) 102 operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS 103 ( 104 BOOST_HOF_MANGLE_CAST(const detail::callable_base<F2>&)(BOOST_HOF_CONST_THIS->second(xs...))( 105 BOOST_HOF_MANGLE_CAST(const detail::callable_base<F1>&)(BOOST_HOF_CONST_THIS->first(xs...))(BOOST_HOF_FORWARD(Ts)(xs)...) 106 ) 107 ); 108 }; 109 } 110 111 template<class F, class... Fs> 112 struct flow_adaptor : detail::flow_kernel<F, BOOST_HOF_JOIN(flow_adaptor, Fs...)> 113 { 114 typedef flow_adaptor fit_rewritable_tag; 115 typedef BOOST_HOF_JOIN(flow_adaptor, Fs...) tail; 116 typedef detail::flow_kernel<F, tail> base_type; 117 BOOST_HOF_INHERIT_DEFAULTboost::hof::flow_adaptor118 BOOST_HOF_INHERIT_DEFAULT(flow_adaptor, base_type) 119 120 template<class X, class... Xs, 121 BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(detail::callable_base<F>, X), 122 BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(tail, Xs...) 123 > 124 constexpr flow_adaptor(X&& f1, Xs&& ... fs) 125 BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base_type, X&&, tail) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(tail, Xs&&...)) 126 : base_type(BOOST_HOF_FORWARD(X)(f1), tail(BOOST_HOF_FORWARD(Xs)(fs)...)) 127 {} 128 129 template<class X, 130 BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(detail::callable_base<F>, X) 131 > flow_adaptorboost::hof::flow_adaptor132 constexpr flow_adaptor(X&& f1) 133 BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base_type, X&&) 134 : base_type(BOOST_HOF_FORWARD(X)(f1)) 135 {} 136 }; 137 138 template<class F> 139 struct flow_adaptor<F> : detail::callable_base<F> 140 { 141 typedef flow_adaptor fit_rewritable_tag; BOOST_HOF_INHERIT_DEFAULTboost::hof::flow_adaptor142 BOOST_HOF_INHERIT_DEFAULT(flow_adaptor, detail::callable_base<F>) 143 144 template<class X, BOOST_HOF_ENABLE_IF_CONVERTIBLE(X, detail::callable_base<F>)> 145 constexpr flow_adaptor(X&& f1) 146 BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(detail::callable_base<F>, X&&) 147 : detail::callable_base<F>(BOOST_HOF_FORWARD(X)(f1)) 148 {} 149 150 }; 151 152 template<class F1, class F2> 153 struct flow_adaptor<F1, F2> 154 : detail::flow_kernel<detail::callable_base<F1>, detail::callable_base<F2>> 155 { 156 typedef flow_adaptor fit_rewritable_tag; 157 typedef detail::flow_kernel<detail::callable_base<F1>, detail::callable_base<F2>> base_type; 158 159 BOOST_HOF_INHERIT_CONSTRUCTOR(flow_adaptor, base_type) 160 }; 161 162 BOOST_HOF_DECLARE_STATIC_VAR(flow, detail::make<flow_adaptor>); 163 164 }} // namespace boost::hof 165 166 #endif 167