Thrill  0.1
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 <[email protected]>
12  * Copyright (C) 2015-2017 Timo Bingmann <[email protected]>
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 
24 namespace tlx {
25 
26 //! \addtogroup tlx_meta
27 //! \{
28 
29 namespace meta_detail {
30 
31 /*!
32  * Base case for the chaining of functors: zero functors, returns the identity.
33  */
34 static 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  */
46 template <typename Functor>
47 auto 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  */
63 template <typename Functor, typename... MoreFunctors>
64 auto 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  */
86 template <typename... Functors>
88 {
89 public:
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 
153 private:
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.
170 template <typename Functor>
171 static inline
172 auto make_function_chain(const Functor& functor) {
173  return FunctionChain<Functor>(std::make_tuple(functor));
174 }
175 
176 //! Construct and empty function chain.
177 static inline
179  return FunctionChain<>();
180 }
181 
182 //! \}
183 
184 } // namespace tlx
185 
186 #endif // !TLX_META_FUNCTION_CHAIN_HEADER
187 
188 /******************************************************************************/
static auto make_function_chain(const Functor &functor)
Functor chain maker. Can also be called with a lambda function.
FunctionChain(const std::tuple< Functors... > &chain)
Initialize the function chain with a given tuple of functions.
std::tuple< Functors... > chain_
Tuple of varying type that stores all functors.
int value
Definition: gen_data.py:41
A FunctionChain is a chain of functors that can be folded to a single functors.
static auto call_chain()
Base case for the chaining of functors: zero functors, returns the identity.
auto push(const Functor &functor) const
Add a functor to the end of the chain.
auto fold() const
Build a single functor by "folding" the chain.
auto fold_chain(index_sequence< Is... >) const
Auxilary function for "folding" the chain.