• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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