1 | /** |
2 | * Copyright 2021 Alibaba, Inc. and its affiliates. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | |
16 | * \author Hechong.xyf |
17 | * \date Aug 2019 |
18 | * \brief Interface of AiLego Utility Closure |
19 | * \detail Construct a closure and run it at another time. |
20 | * All closure objects use the same running interfaces, but they |
21 | * can be constructed with ifferent functions and parameters. |
22 | * The parameters will be saved into the closure objects, then |
23 | * passed to the callback functions when they are invoked. |
24 | */ |
25 | |
26 | #ifndef __AILEGO_PATTERN_CLOSURE_H__ |
27 | #define __AILEGO_PATTERN_CLOSURE_H__ |
28 | |
29 | #include <memory> |
30 | #include <tuple> |
31 | #include <type_traits> |
32 | |
33 | namespace ailego { |
34 | |
35 | /*! Callback Validator (declaration) |
36 | */ |
37 | template <typename TFunc> |
38 | struct CallbackValidator; |
39 | |
40 | /*! Callback Validator (function pointer) |
41 | */ |
42 | template <typename R, typename... TParams> |
43 | struct CallbackValidator<R (*)(TParams...)> { |
44 | enum { Value = true }; |
45 | }; |
46 | |
47 | /*! Callback Validator (function) |
48 | */ |
49 | template <typename R, typename... TParams> |
50 | struct CallbackValidator<R(TParams...)> : CallbackValidator<R (*)(TParams...)> { |
51 | }; |
52 | |
53 | /*! Callback Validator (member function pointer) |
54 | */ |
55 | template <typename T, typename R, typename... TParams> |
56 | struct CallbackValidator<R (T::*)(TParams...)> |
57 | : CallbackValidator<R (*)(TParams...)> {}; |
58 | |
59 | /*! Callback Validator (constable member function pointer) |
60 | */ |
61 | template <typename T, typename R, typename... TParams> |
62 | struct CallbackValidator<R (T::*)(TParams...) const> |
63 | : CallbackValidator<R (*)(TParams...)> {}; |
64 | |
65 | /*! Callback Validator (volatile member function pointer) |
66 | */ |
67 | template <typename T, typename R, typename... TParams> |
68 | struct CallbackValidator<R (T::*)(TParams...) volatile> |
69 | : CallbackValidator<R (*)(TParams...)> {}; |
70 | |
71 | /*! Callback Validator (constable volatile member function pointer) |
72 | */ |
73 | template <typename T, typename R, typename... TParams> |
74 | struct CallbackValidator<R (T::*)(TParams...) const volatile> |
75 | : CallbackValidator<R (*)(TParams...)> {}; |
76 | |
77 | /*! Callback Validator |
78 | */ |
79 | template <typename TFunc> |
80 | struct CallbackValidator { |
81 | protected: |
82 | using FalseType = long; |
83 | using TrueType = char; |
84 | |
85 | //! Check if the class contains operator() |
86 | template <typename T> |
87 | static TrueType &Validate(decltype(&T::operator())); |
88 | |
89 | //! Check if the class contains operator() |
90 | template <typename T> |
91 | static FalseType &Validate(...); |
92 | |
93 | public: |
94 | enum { Value = (sizeof(Validate<TFunc>(nullptr)) == sizeof(TrueType)) }; |
95 | }; |
96 | |
97 | /*! Callback Validator (left reference) |
98 | */ |
99 | template <typename TFunc> |
100 | struct CallbackValidator<TFunc &> : CallbackValidator<TFunc> {}; |
101 | |
102 | /*! Callback Validator (right reference) |
103 | */ |
104 | template <typename TFunc> |
105 | struct CallbackValidator<TFunc &&> : CallbackValidator<TFunc> {}; |
106 | |
107 | /*! Callback Traits (declaration) |
108 | */ |
109 | template <typename TFunc> |
110 | struct CallbackTraits; |
111 | |
112 | /*! Callback Traits (function pointer) |
113 | */ |
114 | template <typename R, typename... TParams> |
115 | struct CallbackTraits<R (*)(TParams...)> { |
116 | using Type = R (*)(TParams...); |
117 | using ResultType = R; |
118 | using TupleType = std::tuple<typename std::decay<TParams>::type...>; |
119 | |
120 | //! Callback Traits Parameter |
121 | template <size_t N> |
122 | struct Parameter { |
123 | using Type = typename std::tuple_element<N, std::tuple<TParams...>>::type; |
124 | }; |
125 | |
126 | //! Number of parameters |
127 | enum { Arity = sizeof...(TParams) }; |
128 | }; |
129 | |
130 | /*! Callback Traits (function) |
131 | */ |
132 | template <typename R, typename... TParams> |
133 | struct CallbackTraits<R(TParams...)> : CallbackTraits<R (*)(TParams...)> { |
134 | using Type = R (*)(TParams...); |
135 | }; |
136 | |
137 | /*! Callback Traits (member function pointer) |
138 | */ |
139 | template <typename T, typename R, typename... TParams> |
140 | struct CallbackTraits<R (T::*)(TParams...)> |
141 | : CallbackTraits<R (*)(TParams...)> { |
142 | using Type = R (T::*)(TParams...); |
143 | }; |
144 | |
145 | /*! Callback Traits (constable member function pointer) |
146 | */ |
147 | template <typename T, typename R, typename... TParams> |
148 | struct CallbackTraits<R (T::*)(TParams...) const> |
149 | : CallbackTraits<R (*)(TParams...)> { |
150 | using Type = R (T::*)(TParams...) const; |
151 | }; |
152 | |
153 | /*! Callback Traits (volatile member function pointer) |
154 | */ |
155 | template <typename T, typename R, typename... TParams> |
156 | struct CallbackTraits<R (T::*)(TParams...) volatile> |
157 | : CallbackTraits<R (*)(TParams...)> { |
158 | using Type = R (T::*)(TParams...) volatile; |
159 | }; |
160 | |
161 | /*! Callback Traits (constable volatile member function pointer) |
162 | */ |
163 | template <typename T, typename R, typename... TParams> |
164 | struct CallbackTraits<R (T::*)(TParams...) const volatile> |
165 | : CallbackTraits<R (*)(TParams...)> { |
166 | using Type = R (T::*)(TParams...) const volatile; |
167 | }; |
168 | |
169 | /*! Callback Traits |
170 | */ |
171 | template <typename TFunc> |
172 | struct CallbackTraits : CallbackTraits<decltype(&TFunc::operator())> { |
173 | using Type = TFunc; |
174 | }; |
175 | |
176 | /*! Callback Traits (left reference) |
177 | */ |
178 | template <typename TFunc> |
179 | struct CallbackTraits<TFunc &> : CallbackTraits<TFunc> {}; |
180 | |
181 | /*! Callback Traits (right reference) |
182 | */ |
183 | template <typename TFunc> |
184 | struct CallbackTraits<TFunc &&> : CallbackTraits<TFunc> {}; |
185 | |
186 | /*! Callback Functor |
187 | */ |
188 | template <typename TFunc> |
189 | struct CallbackFunctor { |
190 | using Traits = CallbackTraits<TFunc>; |
191 | using Type = typename Traits::Type; |
192 | using ResultType = typename Traits::ResultType; |
193 | using TupleType = typename Traits::TupleType; |
194 | |
195 | //! Tuple Index Maker |
196 | template <size_t N, size_t... I> |
197 | struct TupleIndexMaker : TupleIndexMaker<N - 1, N - 1, I...> {}; |
198 | |
199 | //! Tuple Index |
200 | template <size_t...> |
201 | struct TupleIndex {}; |
202 | |
203 | //! Tuple Index Maker (special) |
204 | template <size_t... I> |
205 | struct TupleIndexMaker<0, I...> { |
206 | using Type = TupleIndex<I...>; |
207 | }; |
208 | |
209 | //! Run the callback function |
210 | template <size_t... I> |
211 | static ResultType Run(Type &impl, TupleType &tuple, TupleIndex<I...>) { |
212 | return (impl)(std::forward<typename Traits::template Parameter<I>::Type>( |
213 | std::get<I>(tuple))...); |
214 | } |
215 | |
216 | //! Run the callback member function |
217 | template <typename T, size_t... I> |
218 | static ResultType Run(T *obj, Type &impl, TupleType &tuple, |
219 | TupleIndex<I...>) { |
220 | return (obj->*impl)( |
221 | std::forward<typename Traits::template Parameter<I>::Type>( |
222 | std::get<I>(tuple))...); |
223 | } |
224 | |
225 | //! Run the callback function |
226 | static ResultType Run(Type &impl, TupleType &tuple) { |
227 | return Run(impl, tuple, typename TupleIndexMaker<Traits::Arity>::Type()); |
228 | } |
229 | |
230 | //! Run the callback member function |
231 | template <typename T> |
232 | static ResultType Run(T *obj, Type &impl, TupleType &tuple) { |
233 | return Run(obj, impl, tuple, |
234 | typename TupleIndexMaker<Traits::Arity>::Type()); |
235 | } |
236 | }; |
237 | |
238 | /*! Callback Object |
239 | */ |
240 | template <typename T> |
241 | struct CallbackObject { |
242 | using Type = typename std::remove_reference<T>::type; |
243 | }; |
244 | |
245 | /*! Callback (declaration) |
246 | */ |
247 | template <typename R> |
248 | class Callback; |
249 | |
250 | /*! Callback (void) |
251 | */ |
252 | template <> |
253 | class Callback<void> { |
254 | public: |
255 | using Pointer = std::shared_ptr<Callback<void>>; |
256 | |
257 | //! Destructor |
258 | virtual ~Callback(void) {} |
259 | |
260 | //! Function call |
261 | void operator()(void) { |
262 | this->run(); |
263 | } |
264 | |
265 | //! Run the callback function |
266 | virtual void run(void) = 0; |
267 | |
268 | //! Create callback closure (member function pointer) |
269 | template <typename T, typename R, typename... TParams, typename... TArgs> |
270 | static typename Callback<R>::Pointer New(T *obj, R (T::*impl)(TParams...), |
271 | TArgs &&...args); |
272 | |
273 | //! Create callback closure (constable member function pointer) |
274 | template <typename T, typename R, typename... TParams, typename... TArgs> |
275 | static typename Callback<R>::Pointer New(const T *obj, |
276 | R (T::*impl)(TParams...) const, |
277 | TArgs &&...args); |
278 | |
279 | //! Create callback closure (volatile member function pointer) |
280 | template <typename T, typename R, typename... TParams, typename... TArgs> |
281 | static typename Callback<R>::Pointer New(volatile T *obj, |
282 | R (T::*impl)(TParams...) volatile, |
283 | TArgs &&...args); |
284 | |
285 | //! Create callback closure (constable volatile member function pointer) |
286 | template <typename T, typename R, typename... TParams, typename... TArgs> |
287 | static typename Callback<R>::Pointer New(const volatile T *obj, |
288 | R (T::*impl)(TParams...) |
289 | const volatile, |
290 | TArgs &&...args); |
291 | |
292 | //! Create callback closure (function) |
293 | template < |
294 | typename TFunc, typename... TArgs, |
295 | typename = typename std::enable_if<CallbackValidator<TFunc>::Value>::type> |
296 | static typename Callback<typename CallbackTraits<TFunc>::ResultType>::Pointer |
297 | New(TFunc &&impl, TArgs &&...args); |
298 | }; |
299 | |
300 | /*! Callback |
301 | */ |
302 | template <typename R> |
303 | class Callback : public Callback<void> { |
304 | public: |
305 | using Pointer = std::shared_ptr<Callback<R>>; |
306 | using Callback<void>::run; |
307 | |
308 | //! Function call |
309 | void operator()(void) { |
310 | this->run(); |
311 | } |
312 | |
313 | //! Function call with return |
314 | void operator()(R *r) { |
315 | this->run(r); |
316 | } |
317 | |
318 | //! Run the callback function |
319 | virtual void run(R *) = 0; |
320 | |
321 | protected: |
322 | //! Constructor |
323 | Callback(void){}; |
324 | }; |
325 | |
326 | /*! Callback Implementation |
327 | */ |
328 | template <typename T, typename R, typename TFunc> |
329 | class CallbackImpl : public Callback<R> { |
330 | public: |
331 | using Object = CallbackObject<T>; |
332 | using Functor = CallbackFunctor<TFunc>; |
333 | |
334 | //! Constructor |
335 | template <typename... TArgs> |
336 | CallbackImpl(typename Object::Type *obj, const typename Functor::Type &impl, |
337 | TArgs &&...args) |
338 | : obj_(obj), impl_(impl), tuple_(std::forward<TArgs>(args)...) {} |
339 | |
340 | //! Constructor |
341 | template <typename... TArgs> |
342 | CallbackImpl(typename Object::Type *obj, typename Functor::Type &&impl, |
343 | TArgs &&...args) |
344 | : obj_(obj), |
345 | impl_(std::move(impl)), |
346 | tuple_(std::forward<TArgs>(args)...) {} |
347 | |
348 | //! Run the callback function |
349 | void run(void) override { |
350 | Functor::Run(obj_, impl_, tuple_); |
351 | } |
352 | |
353 | //! Run the callback function |
354 | void run(R *r) override { |
355 | *r = Functor::Run(obj_, impl_, tuple_); |
356 | } |
357 | |
358 | protected: |
359 | //! Disable them |
360 | CallbackImpl(void) = delete; |
361 | CallbackImpl(const CallbackImpl &) = delete; |
362 | CallbackImpl(CallbackImpl &&) = delete; |
363 | CallbackImpl &operator=(const CallbackImpl &) = delete; |
364 | |
365 | private: |
366 | typename Object::Type *obj_; |
367 | typename Functor::Type impl_; |
368 | typename Functor::TupleType tuple_; |
369 | }; |
370 | |
371 | /*! Callback Implementation |
372 | */ |
373 | template <typename T, typename TFunc> |
374 | class CallbackImpl<T, void, TFunc> : public Callback<void> { |
375 | public: |
376 | using Object = CallbackObject<T>; |
377 | using Functor = CallbackFunctor<TFunc>; |
378 | |
379 | //! Constructor |
380 | template <typename... TArgs> |
381 | CallbackImpl(typename Object::Type *obj, const typename Functor::Type &impl, |
382 | TArgs &&...args) |
383 | : obj_(obj), impl_(impl), tuple_(std::forward<TArgs>(args)...) {} |
384 | |
385 | //! Constructor |
386 | template <typename... TArgs> |
387 | CallbackImpl(typename Object::Type *obj, typename Functor::Type &&impl, |
388 | TArgs &&...args) |
389 | : obj_(obj), |
390 | impl_(std::move(impl)), |
391 | tuple_(std::forward<TArgs>(args)...) {} |
392 | |
393 | //! Run the callback function |
394 | void run(void) override { |
395 | Functor::Run(obj_, impl_, tuple_); |
396 | } |
397 | |
398 | protected: |
399 | //! Disable them |
400 | CallbackImpl(void) = delete; |
401 | CallbackImpl(const CallbackImpl &) = delete; |
402 | CallbackImpl(CallbackImpl &&) = delete; |
403 | CallbackImpl &operator=(const CallbackImpl &) = delete; |
404 | |
405 | private: |
406 | typename Object::Type *obj_; |
407 | typename Functor::Type impl_; |
408 | typename Functor::TupleType tuple_; |
409 | }; |
410 | |
411 | /*! Callback Implementation |
412 | */ |
413 | template <typename R, typename TFunc> |
414 | class CallbackImpl<void, R, TFunc> : public Callback<R> { |
415 | public: |
416 | using Functor = CallbackFunctor<TFunc>; |
417 | |
418 | //! Constructor |
419 | template <typename... TArgs> |
420 | CallbackImpl(const typename Functor::Type &impl, TArgs &&...args) |
421 | : impl_(impl), tuple_(std::forward<TArgs>(args)...) {} |
422 | |
423 | //! Constructor |
424 | template <typename... TArgs> |
425 | CallbackImpl(typename Functor::Type &&impl, TArgs &&...args) |
426 | : impl_(std::move(impl)), tuple_(std::forward<TArgs>(args)...) {} |
427 | |
428 | //! Run the callback function |
429 | void run(void) override { |
430 | Functor::Run(impl_, tuple_); |
431 | } |
432 | |
433 | //! Run the callback function |
434 | void run(R *r) override { |
435 | *r = Functor::Run(impl_, tuple_); |
436 | } |
437 | |
438 | protected: |
439 | //! Disable them |
440 | CallbackImpl(void) = delete; |
441 | CallbackImpl(const CallbackImpl &) = delete; |
442 | CallbackImpl(CallbackImpl &&) = delete; |
443 | CallbackImpl &operator=(const CallbackImpl &) = delete; |
444 | |
445 | private: |
446 | typename Functor::Type impl_; |
447 | typename Functor::TupleType tuple_; |
448 | }; |
449 | |
450 | /*! Callback Implementation |
451 | */ |
452 | template <typename TFunc> |
453 | class CallbackImpl<void, void, TFunc> : public Callback<void> { |
454 | public: |
455 | using Functor = CallbackFunctor<TFunc>; |
456 | |
457 | //! Constructor |
458 | template <typename... TArgs> |
459 | CallbackImpl(const typename Functor::Type &impl, TArgs &&...args) |
460 | : impl_(impl), tuple_(std::forward<TArgs>(args)...) {} |
461 | |
462 | //! Constructor |
463 | template <typename... TArgs> |
464 | CallbackImpl(typename Functor::Type &&impl, TArgs &&...args) |
465 | : impl_(std::move(impl)), tuple_(std::forward<TArgs>(args)...) {} |
466 | |
467 | //! Run the callback function |
468 | void run(void) override { |
469 | Functor::Run(impl_, tuple_); |
470 | } |
471 | |
472 | protected: |
473 | //! Disable them |
474 | CallbackImpl(void) = delete; |
475 | CallbackImpl(const CallbackImpl &) = delete; |
476 | CallbackImpl(CallbackImpl &&) = delete; |
477 | CallbackImpl &operator=(const CallbackImpl &) = delete; |
478 | |
479 | private: |
480 | typename Functor::Type impl_; |
481 | typename Functor::TupleType tuple_; |
482 | }; |
483 | |
484 | //! Create callback closure (member function pointer) |
485 | template <typename T, typename R, typename... TParams, typename... TArgs> |
486 | typename Callback<R>::Pointer Callback<void>::New(T *obj, |
487 | R (T::*impl)(TParams...), |
488 | TArgs &&...args) { |
489 | return std::make_shared<CallbackImpl<T, R, decltype(impl)>>( |
490 | obj, impl, std::forward<TArgs>(args)...); |
491 | } |
492 | |
493 | //! Create callback closure (constable member function pointer) |
494 | template <typename T, typename R, typename... TParams, typename... TArgs> |
495 | typename Callback<R>::Pointer Callback<void>::New(const T *obj, |
496 | R (T::*impl)(TParams...) |
497 | const, |
498 | TArgs &&...args) { |
499 | return std::make_shared<CallbackImpl<const T, R, decltype(impl)>>( |
500 | obj, impl, std::forward<TArgs>(args)...); |
501 | } |
502 | |
503 | //! Create callback closure (volatile member function pointer) |
504 | template <typename T, typename R, typename... TParams, typename... TArgs> |
505 | typename Callback<R>::Pointer Callback<void>::New( |
506 | volatile T *obj, R (T::*impl)(TParams...) volatile, TArgs &&...args) { |
507 | return std::make_shared<CallbackImpl<volatile T, R, decltype(impl)>>( |
508 | obj, impl, std::forward<TArgs>(args)...); |
509 | } |
510 | |
511 | //! Create callback closure (constable volatile member function pointer) |
512 | template <typename T, typename R, typename... TParams, typename... TArgs> |
513 | typename Callback<R>::Pointer Callback<void>::New(const volatile T *obj, |
514 | R (T::*impl)(TParams...) |
515 | const volatile, |
516 | TArgs &&...args) { |
517 | return std::make_shared<CallbackImpl<const volatile T, R, decltype(impl)>>( |
518 | obj, impl, std::forward<TArgs>(args)...); |
519 | } |
520 | |
521 | //! Create callback closure (function) |
522 | template <typename TFunc, typename... TArgs, typename> |
523 | typename Callback<typename CallbackTraits<TFunc>::ResultType>::Pointer |
524 | Callback<void>::New(TFunc &&impl, TArgs &&...args) { |
525 | return std::make_shared<CallbackImpl< |
526 | void, typename CallbackTraits<TFunc>::ResultType, decltype(impl)>>( |
527 | std::forward<TFunc>(impl), std::forward<TArgs>(args)...); |
528 | } |
529 | |
530 | //! Callback Handler |
531 | template <typename R> |
532 | using CallbackHandler = typename Callback<R>::Pointer; |
533 | |
534 | //! Closure |
535 | using Closure = Callback<void>; |
536 | |
537 | //! Closure Handler |
538 | using ClosureHandler = Closure::Pointer; |
539 | |
540 | } // namespace ailego |
541 | |
542 | #endif // __AILEGO_PATTERN_CLOSURE_H__ |
543 | |