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 89namespace boost { namespace hof { namespace detail { 90 91template<class F1, class F2> 92struct 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 111template<class F, class... Fs> 112struct 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 118 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 > 132 constexpr flow_adaptor(X&& f1) 133 BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base_type, X&&) 134 : base_type(BOOST_HOF_FORWARD(X)(f1)) 135 {} 136}; 137 138template<class F> 139struct flow_adaptor<F> : detail::callable_base<F> 140{ 141 typedef flow_adaptor fit_rewritable_tag; 142 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 152template<class F1, class F2> 153struct 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 162BOOST_HOF_DECLARE_STATIC_VAR(flow, detail::make<flow_adaptor>); 163 164}} // namespace boost::hof 165 166#endif 167