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 90namespace boost { namespace hof { namespace detail { 91 92template<class F1, class F2> 93struct 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 112template<class F, class... Fs> 113struct 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 120 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 > 134 constexpr compose_adaptor(X&& f1) 135 BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base_type, X&&) 136 : base_type(BOOST_HOF_FORWARD(X)(f1)) 137 {} 138}; 139 140template<class F> 141struct compose_adaptor<F> : detail::callable_base<F> 142{ 143 typedef compose_adaptor fit_rewritable_tag; 144 145 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 155template<class F1, class F2> 156struct 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 165BOOST_HOF_DECLARE_STATIC_VAR(compose, detail::make<compose_adaptor>); 166 167}} // namespace boost::hof 168 169#endif 170