1 /*============================================================================= 2 Copyright (c) 2014 Paul Fultz II 3 compose.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_COMPOSE_H 9 #define BOOST_HOF_GUARD_FUNCTION_COMPOSE_H 10 11 /// compose 12 /// ======= 13 /// 14 /// Description 15 /// ----------- 16 /// 17 /// The `compose` function adaptor provides function composition. It produces 18 /// a function object that composes a set of functions, ie the output of one 19 /// function becomes the input of the second function. So, `compose(f, g)(0)` 20 /// is equivalent to `f(g(0))`. 21 /// 22 /// 23 /// Synopsis 24 /// -------- 25 /// 26 /// template<class... Fs> 27 /// constexpr compose_adaptor<Fs...> compose(Fs... fs); 28 /// 29 /// Semantics 30 /// --------- 31 /// 32 /// assert(compose(f, g)(xs...) == f(g(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 = compose(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 79 #include <boost/hof/detail/callable_base.hpp> 80 #include <boost/hof/always.hpp> 81 #include <boost/hof/detail/delegate.hpp> 82 #include <boost/hof/detail/compressed_pair.hpp> 83 #include <boost/hof/detail/join.hpp> 84 #include <tuple> 85 #include <boost/hof/detail/move.hpp> 86 #include <boost/hof/detail/make.hpp> 87 #include <boost/hof/detail/result_type.hpp> 88 #include <boost/hof/detail/static_const_var.hpp> 89 90 namespace boost { namespace hof { namespace detail { 91 92 template<class F1, class F2> 93 struct compose_kernel : detail::compressed_pair<F1, F2>, compose_function_result_type<F1, F2> 94 { 95 typedef detail::compressed_pair<F1, F2> base_type; 96 97 BOOST_HOF_INHERIT_CONSTRUCTOR(compose_kernel, base_type) 98 99 BOOST_HOF_RETURNS_CLASS(compose_kernel); 100 101 template<class... Ts> 102 constexpr BOOST_HOF_SFINAE_RESULT(const F1&, result_of<const F2&, id_<Ts>...>) 103 operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS 104 ( 105 BOOST_HOF_MANGLE_CAST(const F1&)(BOOST_HOF_CONST_THIS->first(xs...))( 106 BOOST_HOF_MANGLE_CAST(const F2&)(BOOST_HOF_CONST_THIS->second(xs...))(BOOST_HOF_FORWARD(Ts)(xs)...) 107 ) 108 ); 109 }; 110 } 111 112 template<class F, class... Fs> 113 struct compose_adaptor 114 : detail::compose_kernel<detail::callable_base<F>, BOOST_HOF_JOIN(compose_adaptor, detail::callable_base<Fs>...)> 115 { 116 typedef compose_adaptor fit_rewritable_tag; 117 typedef BOOST_HOF_JOIN(compose_adaptor, detail::callable_base<Fs>...) tail; 118 typedef detail::compose_kernel<detail::callable_base<F>, tail> base_type; 119 BOOST_HOF_INHERIT_DEFAULTboost::hof::compose_adaptor120 BOOST_HOF_INHERIT_DEFAULT(compose_adaptor, base_type) 121 122 template<class X, class... Xs, 123 BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(detail::callable_base<F>, X), 124 BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(tail, Xs...) 125 > 126 constexpr compose_adaptor(X&& f1, Xs&& ... fs) 127 BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base_type, X&&, tail) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(tail, Xs&&...)) 128 : base_type(BOOST_HOF_FORWARD(X)(f1), tail(BOOST_HOF_FORWARD(Xs)(fs)...)) 129 {} 130 131 template<class X, 132 BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(detail::callable_base<F>, X) 133 > compose_adaptorboost::hof::compose_adaptor134 constexpr compose_adaptor(X&& f1) 135 BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base_type, X&&) 136 : base_type(BOOST_HOF_FORWARD(X)(f1)) 137 {} 138 }; 139 140 template<class F> 141 struct compose_adaptor<F> : detail::callable_base<F> 142 { 143 typedef compose_adaptor fit_rewritable_tag; 144 BOOST_HOF_INHERIT_DEFAULTboost::hof::compose_adaptor145 BOOST_HOF_INHERIT_DEFAULT(compose_adaptor, detail::callable_base<F>) 146 147 template<class X, BOOST_HOF_ENABLE_IF_CONVERTIBLE(X, detail::callable_base<F>)> 148 constexpr compose_adaptor(X&& f1) 149 BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(detail::callable_base<F>, X&&) 150 : detail::callable_base<F>(BOOST_HOF_FORWARD(X)(f1)) 151 {} 152 153 }; 154 155 template<class F1, class F2> 156 struct compose_adaptor<F1, F2> 157 : detail::compose_kernel<detail::callable_base<F1>, detail::callable_base<F2>> 158 { 159 typedef compose_adaptor fit_rewritable_tag; 160 typedef detail::compose_kernel<detail::callable_base<F1>, detail::callable_base<F2>> base_type; 161 162 BOOST_HOF_INHERIT_CONSTRUCTOR(compose_adaptor, base_type) 163 }; 164 165 BOOST_HOF_DECLARE_STATIC_VAR(compose, detail::make<compose_adaptor>); 166 167 }} // namespace boost::hof 168 169 #endif 170