tlx
function_chain.hpp
Go to the documentation of this file.
1/*******************************************************************************
2 * tlx/meta/function_chain.hpp
3 *
4 * A FunctionChain stores a sequence of lambdas or functors f_1, f_2, ... f_n,
5 * which are composed together as f_n(... f_2(f_1(x))). Each lambda/functor is
6 * called with the result of the previous. This basically implements
7 * compile-time function composition.
8 *
9 * Part of tlx - http://panthema.net/tlx
10 *
11 * Copyright (C) 2015 Sebastian Lamm <seba.lamm@gmail.com>
12 * Copyright (C) 2015-2017 Timo Bingmann <tb@panthema.net>
13 *
14 * All rights reserved. Published under the Boost Software License, Version 1.0
15 ******************************************************************************/
16
17#ifndef TLX_META_FUNCTION_CHAIN_HEADER
18#define TLX_META_FUNCTION_CHAIN_HEADER
19
21
22#include <tuple>
23
24namespace tlx {
25
26//! \addtogroup tlx_meta
27//! \{
28
29namespace meta_detail {
30
31/*!
32 * Base case for the chaining of functors: zero functors, returns the identity.
33 */
34static inline auto call_chain() {
35 return [](const auto& input) mutable -> auto {
36 return input;
37 };
38}
39
40/*!
41 * Base case for the chaining of functors. The one functor receives an input
42 * element
43 *
44 * \param functor functor that represents the chain end.
45 */
46template <typename Functor>
47auto call_chain(const Functor& functor) {
48 // the functor is captured by non-const copy so that we can use functors
49 // with non-const operator(), i.e. stateful functors (e.g. for sampling)
50 return [functor = functor](const auto& input) mutable -> auto {
51 return functor(input);
52 };
53}
54
55/*!
56 * Recursive case for the chaining of functors. The first functor receives an
57 * input element, and the remaining chain is applied to the result.
58 *
59 * \param functor Current functor to be chained.
60 *
61 * \param rest Remaining functors.
62 */
63template <typename Functor, typename... MoreFunctors>
64auto call_chain(const Functor& functor, const MoreFunctors& ... rest) {
65 // the functor is captured by non-const copy so that we can use functors
66 // with non-const operator(), i.e. stateful functors (e.g. for sampling)
67 return [=, functor = functor](const auto& input) mutable -> auto {
68 return call_chain(rest...)(functor(input));
69 };
70}
71
72} // namespace meta_detail
73
74/*!
75 * A FunctionChain is a chain of functors that can be folded to a single
76 * functors. All functors within the chain receive a single input value, which
77 * is the result of all preceding functors in the chain.
78 *
79 * The FunctionChain basically consists of a tuple that contains functors of
80 * varying types.
81 *
82 * \tparam Input_ Input to first functor functor.
83 *
84 * \tparam Functors Types of the different functors.
85 */
86template <typename... Functors>
88{
89public:
90 //! default constructor: empty functor chain.
91 FunctionChain() = default;
92
93 /*!
94 * Initialize the function chain with a given tuple of functions.
95 *
96 * \param chain Tuple of functors.
97 */
98 explicit FunctionChain(const std::tuple<Functors...>& chain)
99 : chain_(chain) { }
100
101 /*!
102 * Add a functor to the end of the chain.
103 *
104 * \tparam Functor Type of the functors.
105 *
106 * \param functor functor that should be added to the chain.
107 *
108 * \return New chain containing the previous and new functor(s).
109 */
110 template <typename Functor>
111 auto push(const Functor& functor) const {
112 // append to function chain's type the new function.
113 return FunctionChain<Functors..., Functor>(
114 std::tuple_cat(chain_, std::make_tuple(functor)));
115 }
116
117 /*!
118 * Add a functor to the end of the chain. Alias for fold().
119 *
120 * \tparam Functor Type of the functors.
121 *
122 * \param functor functor that should be added to the chain.
123 *
124 * \return New chain containing the previous and new functor(s).
125 */
126 template <typename Functor>
127 auto operator & (const Functor& functor) const { return push(functor); }
128
129 /*!
130 * Build a single functor by "folding" the chain. Folding means
131 * that the chain is processed from front to back.
132 *
133 * \return Single "folded" functor representing the chain.
134 */
135 auto fold() const {
136 return fold_chain(make_index_sequence<sizeof ... (Functors)>{ });
137 }
138
139 /*!
140 * Directly call the folded function chain with a value.
141 */
142 template <typename... Input>
143 auto operator () (Input&& ... value) const {
144 return fold()(std::move(value...));
145 }
146
147 //! Is true if the FunctionChain is empty.
148 static constexpr bool empty = (sizeof ... (Functors) == 0);
149
150 //! Number of functors in the FunctionChain
151 static constexpr size_t size = sizeof ... (Functors);
152
153private:
154 //! Tuple of varying type that stores all functors.
155 std::tuple<Functors...> chain_;
156
157 /*!
158 * Auxilary function for "folding" the chain. This is needed to send all
159 * functors as parameters to the function that folds them together.
160 *
161 * \return Single "folded" functor representing the chain.
162 */
163 template <size_t... Is>
165 return meta_detail::call_chain(std::get<Is>(chain_) ...);
166 }
167};
168
169//! Functor chain maker. Can also be called with a lambda function.
170template <typename Functor>
171static inline
172auto make_function_chain(const Functor& functor) {
173 return FunctionChain<Functor>(std::make_tuple(functor));
174}
175
176//! Construct and empty function chain.
177static inline
179 return FunctionChain<>();
180}
181
182//! \}
183
184} // namespace tlx
185
186#endif // !TLX_META_FUNCTION_CHAIN_HEADER
187
188/******************************************************************************/
A FunctionChain is a chain of functors that can be folded to a single functors.
auto push(const Functor &functor) const
Add a functor to the end of the chain.
static constexpr bool empty
Is true if the FunctionChain is empty.
FunctionChain(const std::tuple< Functors... > &chain)
Initialize the function chain with a given tuple of functions.
FunctionChain()=default
default constructor: empty functor chain.
auto fold() const
Build a single functor by "folding" the chain.
auto operator()(Input &&... value) const
Directly call the folded function chain with a value.
std::tuple< Functors... > chain_
Tuple of varying type that stores all functors.
auto fold_chain(index_sequence< Is... >) const
Auxilary function for "folding" the chain.
auto operator&(const Functor &functor) const
Add a functor to the end of the chain.
static constexpr size_t size
Number of functors in the FunctionChain.
static auto make_function_chain(const Functor &functor)
Functor chain maker. Can also be called with a lambda function.
static auto call_chain()
Base case for the chaining of functors: zero functors, returns the identity.