Apache Mesos
defer.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License
12 
13 #ifndef __PROCESS_DEFER_HPP__
14 #define __PROCESS_DEFER_HPP__
15 
16 #include <functional>
17 #include <memory>
18 
19 #include <process/deferred.hpp>
20 #include <process/dispatch.hpp>
21 #include <process/executor.hpp>
22 
23 #include <stout/preprocessor.hpp>
24 
25 namespace process {
26 
27 // The defer mechanism is very similar to the dispatch mechanism (see
28 // dispatch.hpp), however, rather than scheduling the method to get
29 // invoked, the defer mechanism returns a 'Deferred' object that when
30 // invoked does the underlying dispatch.
31 
32 // First, definitions of defer for methods returning void:
33 
34 template <typename T>
35 Deferred<void()> defer(const PID<T>& pid, void (T::*method)())
36 {
37  return Deferred<void()>([=]() { dispatch(pid, method); });
38 }
39 
40 
41 template <typename T>
42 Deferred<void()> defer(const Process<T>& process, void (T::*method)())
43 {
44  return defer(process.self(), method);
45 }
46 
47 
48 template <typename T>
49 Deferred<void()> defer(const Process<T>* process, void (T::*method)())
50 {
51  return defer(process->self(), method);
52 }
53 
54 
55 // Due to a bug (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41933)
56 // with variadic templates and lambdas, we still need to do
57 // preprocessor expansions. In addition, due to a bug with clang (or
58 // libc++) we can't use std::bind with a std::function so we have to
59 // explicitly use the std::function<R(P...)>::operator() (see
60 // http://stackoverflow.com/questions/20097616/stdbind-to-a-stdfunction-crashes-with-clang).
61 
62 // This assumes that type and variable base names are `A` and `a` respectively.
63 #define FORWARD_A(Z, N, DATA) std::forward<A ## N>(a ## N)
64 
65 // This assumes that type and variable base names are `P` and `p` respectively.
66 #define FORWARD_P(Z, N, DATA) std::forward<P ## N>(p ## N)
67 
68 #define TEMPLATE(Z, N, DATA) \
69  template <typename T, \
70  ENUM_PARAMS(N, typename P), \
71  ENUM_PARAMS(N, typename A)> \
72  auto defer(const PID<T>& pid, \
73  void (T::*method)(ENUM_PARAMS(N, P)), \
74  ENUM_BINARY_PARAMS(N, A, &&a)) \
75  -> _Deferred<decltype( \
76  lambda::partial( \
77  &std::function<void(ENUM_PARAMS(N, P))>::operator(), \
78  std::function<void(ENUM_PARAMS(N, P))>(), \
79  ENUM(N, FORWARD_A, _)))> \
80  { \
81  std::function<void(ENUM_PARAMS(N, P))> f( \
82  [=](ENUM_BINARY_PARAMS(N, P, &&p)) { \
83  dispatch(pid, method, ENUM(N, FORWARD_P, _)); \
84  }); \
85  return lambda::partial( \
86  &std::function<void(ENUM_PARAMS(N, P))>::operator(), \
87  std::move(f), \
88  ENUM(N, FORWARD_A, _)); \
89  } \
90  \
91  template <typename T, \
92  ENUM_PARAMS(N, typename P), \
93  ENUM_PARAMS(N, typename A)> \
94  auto defer(const Process<T>& process, \
95  void (T::*method)(ENUM_PARAMS(N, P)), \
96  ENUM_BINARY_PARAMS(N, A, &&a)) \
97  -> decltype(defer(process.self(), method, ENUM(N, FORWARD_A, _))) \
98  { \
99  return defer(process.self(), method, ENUM(N, FORWARD_A, _)); \
100  } \
101  \
102  template <typename T, \
103  ENUM_PARAMS(N, typename P), \
104  ENUM_PARAMS(N, typename A)> \
105  auto defer(const Process<T>* process, \
106  void (T::*method)(ENUM_PARAMS(N, P)), \
107  ENUM_BINARY_PARAMS(N, A, &&a)) \
108  -> decltype(defer(process->self(), method, ENUM(N, FORWARD_A, _))) \
109  { \
110  return defer(process->self(), method, ENUM(N, FORWARD_A, _)); \
111  }
112 
113  REPEAT_FROM_TO(1, 13, TEMPLATE, _) // Args A0 -> A11.
114 #undef TEMPLATE
115 
116 
117 // Next, definitions of defer for methods returning future:
118 
119 template <typename R, typename T>
120 Deferred<Future<R>()> defer(const PID<T>& pid, Future<R> (T::*method)())
121 {
122  return Deferred<Future<R>()>([=]() { return dispatch(pid, method); });
123 }
124 
125 template <typename R, typename T>
126 Deferred<Future<R>()> defer(const Process<T>& process, Future<R> (T::*method)())
127 {
128  return defer(process.self(), method);
129 }
130 
131 template <typename R, typename T>
132 Deferred<Future<R>()> defer(const Process<T>* process, Future<R> (T::*method)())
133 {
134  return defer(process->self(), method);
135 }
136 
137 #define TEMPLATE(Z, N, DATA) \
138  template <typename R, \
139  typename T, \
140  ENUM_PARAMS(N, typename P), \
141  ENUM_PARAMS(N, typename A)> \
142  auto defer(const PID<T>& pid, \
143  Future<R> (T::*method)(ENUM_PARAMS(N, P)), \
144  ENUM_BINARY_PARAMS(N, A, &&a)) \
145  -> _Deferred<decltype( \
146  lambda::partial( \
147  &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), \
148  std::function<Future<R>(ENUM_PARAMS(N, P))>(), \
149  ENUM(N, FORWARD_A, _)))> \
150  { \
151  std::function<Future<R>(ENUM_PARAMS(N, P))> f( \
152  [=](ENUM_BINARY_PARAMS(N, P, &&p)) { \
153  return dispatch(pid, method, ENUM(N, FORWARD_P, _)); \
154  }); \
155  return lambda::partial( \
156  &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), \
157  std::move(f), \
158  ENUM(N, FORWARD_A, _)); \
159  } \
160  \
161  template <typename R, \
162  typename T, \
163  ENUM_PARAMS(N, typename P), \
164  ENUM_PARAMS(N, typename A)> \
165  auto defer(const Process<T>& process, \
166  Future<R> (T::*method)(ENUM_PARAMS(N, P)), \
167  ENUM_BINARY_PARAMS(N, A, &&a)) \
168  -> decltype(defer(process.self(), method, ENUM(N, FORWARD_A, _))) \
169  { \
170  return defer(process.self(), method, ENUM(N, FORWARD_A, _)); \
171  } \
172  \
173  template <typename R, \
174  typename T, \
175  ENUM_PARAMS(N, typename P), \
176  ENUM_PARAMS(N, typename A)> \
177  auto defer(const Process<T>* process, \
178  Future<R> (T::*method)(ENUM_PARAMS(N, P)), \
179  ENUM_BINARY_PARAMS(N, A, &&a)) \
180  -> decltype(defer(process->self(), method, ENUM(N, FORWARD_A, _))) \
181  { \
182  return defer(process->self(), method, ENUM(N, FORWARD_A, _)); \
183  }
184 
185  REPEAT_FROM_TO(1, 13, TEMPLATE, _) // Args A0 -> A11.
186 #undef TEMPLATE
187 
188 
189 // Finally, definitions of defer for methods returning a value:
190 
191 template <typename R, typename T>
192 Deferred<Future<R>()> defer(const PID<T>& pid, R (T::*method)())
193 {
194  return Deferred<Future<R>()>([=]() { return dispatch(pid, method); });
195 }
196 
197 template <typename R, typename T>
198 Deferred<Future<R>()> defer(const Process<T>& process, R (T::*method)())
199 {
200  return defer(process.self(), method);
201 }
202 
203 template <typename R, typename T>
204 Deferred<Future<R>()> defer(const Process<T>* process, R (T::*method)())
205 {
206  return defer(process->self(), method);
207 }
208 
209 #define TEMPLATE(Z, N, DATA) \
210  template <typename R, \
211  typename T, \
212  ENUM_PARAMS(N, typename P), \
213  ENUM_PARAMS(N, typename A)> \
214  auto defer(const PID<T>& pid, \
215  R (T::*method)(ENUM_PARAMS(N, P)), \
216  ENUM_BINARY_PARAMS(N, A, &&a)) \
217  -> _Deferred<decltype( \
218  lambda::partial( \
219  &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), \
220  std::function<Future<R>(ENUM_PARAMS(N, P))>(), \
221  ENUM(N, FORWARD_A, _)))> \
222  { \
223  std::function<Future<R>(ENUM_PARAMS(N, P))> f( \
224  [=](ENUM_BINARY_PARAMS(N, P, &&p)) { \
225  return dispatch(pid, method, ENUM(N, FORWARD_P, _)); \
226  }); \
227  return lambda::partial( \
228  &std::function<Future<R>(ENUM_PARAMS(N, P))>::operator(), \
229  std::move(f), \
230  ENUM(N, FORWARD_A, _)); \
231  } \
232  \
233  template <typename R, \
234  typename T, \
235  ENUM_PARAMS(N, typename P), \
236  ENUM_PARAMS(N, typename A)> \
237  auto \
238  defer(const Process<T>& process, \
239  R (T::*method)(ENUM_PARAMS(N, P)), \
240  ENUM_BINARY_PARAMS(N, A, &&a)) \
241  -> decltype(defer(process.self(), method, ENUM(N, FORWARD_A, _))) \
242  { \
243  return defer(process.self(), method, ENUM(N, FORWARD_A, _)); \
244  } \
245  \
246  template <typename R, \
247  typename T, \
248  ENUM_PARAMS(N, typename P), \
249  ENUM_PARAMS(N, typename A)> \
250  auto \
251  defer(const Process<T>* process, \
252  R (T::*method)(ENUM_PARAMS(N, P)), \
253  ENUM_BINARY_PARAMS(N, A, &&a)) \
254  -> decltype(defer(process->self(), method, ENUM(N, FORWARD_A, _))) \
255  { \
256  return defer(process->self(), method, ENUM(N, FORWARD_A, _)); \
257  }
258 
259  REPEAT_FROM_TO(1, 13, TEMPLATE, _) // Args A0 -> A11.
260 #undef TEMPLATE
261 
262 #undef FORWARD_A
263 #undef FORWARD_P
264 
265 
266 // Now we define defer calls for functors (with and without a PID):
267 
268 template <typename F>
269 _Deferred<F> defer(const UPID& pid, F&& f)
270 {
271  return _Deferred<F>(pid, std::forward<F>(f));
272 }
273 
274 
275 template <typename F>
277 {
278  if (__process__ != nullptr) {
279  return defer(__process__->self(), std::forward<F>(f));
280  }
281 
282  return __executor__->defer(std::forward<F>(f));
283 }
284 
285 } // namespace process {
286 
287 #endif // __PROCESS_DEFER_HPP__
F && f
Definition: defer.hpp:270
REPEAT_FROM_TO(1, 13, TEMPLATE, _) class AsyncExecutorProcess
Definition: async.hpp:63
Definition: deferred.hpp:29
void dispatch(const PID< T > &pid, void(T::*method)())
Definition: dispatch.hpp:174
thread_local ProcessBase * __process__
Definition: deferred.hpp:64
#define TEMPLATE(Z, N, DATA)
Definition: defer.hpp:209
A "process identifier" used to uniquely identify a process when dispatching messages.
Definition: pid.hpp:289
Definition: executor.hpp:48
PID< T > self() const
Returns the PID of the process.
Definition: process.hpp:514
#define __executor__
Definition: executor.hpp:108
Definition: process.hpp:505
Deferred< void()> defer(const PID< T > &pid, void(T::*method)())
Definition: defer.hpp:35
const UPID & self() const
Definition: process.hpp:79