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
33namespace ailego {
34
35/*! Callback Validator (declaration)
36 */
37template <typename TFunc>
38struct CallbackValidator;
39
40/*! Callback Validator (function pointer)
41 */
42template <typename R, typename... TParams>
43struct CallbackValidator<R (*)(TParams...)> {
44 enum { Value = true };
45};
46
47/*! Callback Validator (function)
48 */
49template <typename R, typename... TParams>
50struct CallbackValidator<R(TParams...)> : CallbackValidator<R (*)(TParams...)> {
51};
52
53/*! Callback Validator (member function pointer)
54 */
55template <typename T, typename R, typename... TParams>
56struct CallbackValidator<R (T::*)(TParams...)>
57 : CallbackValidator<R (*)(TParams...)> {};
58
59/*! Callback Validator (constable member function pointer)
60 */
61template <typename T, typename R, typename... TParams>
62struct CallbackValidator<R (T::*)(TParams...) const>
63 : CallbackValidator<R (*)(TParams...)> {};
64
65/*! Callback Validator (volatile member function pointer)
66 */
67template <typename T, typename R, typename... TParams>
68struct CallbackValidator<R (T::*)(TParams...) volatile>
69 : CallbackValidator<R (*)(TParams...)> {};
70
71/*! Callback Validator (constable volatile member function pointer)
72 */
73template <typename T, typename R, typename... TParams>
74struct CallbackValidator<R (T::*)(TParams...) const volatile>
75 : CallbackValidator<R (*)(TParams...)> {};
76
77/*! Callback Validator
78 */
79template <typename TFunc>
80struct 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 */
99template <typename TFunc>
100struct CallbackValidator<TFunc &> : CallbackValidator<TFunc> {};
101
102/*! Callback Validator (right reference)
103 */
104template <typename TFunc>
105struct CallbackValidator<TFunc &&> : CallbackValidator<TFunc> {};
106
107/*! Callback Traits (declaration)
108 */
109template <typename TFunc>
110struct CallbackTraits;
111
112/*! Callback Traits (function pointer)
113 */
114template <typename R, typename... TParams>
115struct 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 */
132template <typename R, typename... TParams>
133struct CallbackTraits<R(TParams...)> : CallbackTraits<R (*)(TParams...)> {
134 using Type = R (*)(TParams...);
135};
136
137/*! Callback Traits (member function pointer)
138 */
139template <typename T, typename R, typename... TParams>
140struct CallbackTraits<R (T::*)(TParams...)>
141 : CallbackTraits<R (*)(TParams...)> {
142 using Type = R (T::*)(TParams...);
143};
144
145/*! Callback Traits (constable member function pointer)
146 */
147template <typename T, typename R, typename... TParams>
148struct 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 */
155template <typename T, typename R, typename... TParams>
156struct 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 */
163template <typename T, typename R, typename... TParams>
164struct CallbackTraits<R (T::*)(TParams...) const volatile>
165 : CallbackTraits<R (*)(TParams...)> {
166 using Type = R (T::*)(TParams...) const volatile;
167};
168
169/*! Callback Traits
170 */
171template <typename TFunc>
172struct CallbackTraits : CallbackTraits<decltype(&TFunc::operator())> {
173 using Type = TFunc;
174};
175
176/*! Callback Traits (left reference)
177 */
178template <typename TFunc>
179struct CallbackTraits<TFunc &> : CallbackTraits<TFunc> {};
180
181/*! Callback Traits (right reference)
182 */
183template <typename TFunc>
184struct CallbackTraits<TFunc &&> : CallbackTraits<TFunc> {};
185
186/*! Callback Functor
187 */
188template <typename TFunc>
189struct 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 */
240template <typename T>
241struct CallbackObject {
242 using Type = typename std::remove_reference<T>::type;
243};
244
245/*! Callback (declaration)
246 */
247template <typename R>
248class Callback;
249
250/*! Callback (void)
251 */
252template <>
253class 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 */
302template <typename R>
303class 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 */
328template <typename T, typename R, typename TFunc>
329class 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 */
373template <typename T, typename TFunc>
374class 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 */
413template <typename R, typename TFunc>
414class 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 */
452template <typename TFunc>
453class 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)
485template <typename T, typename R, typename... TParams, typename... TArgs>
486typename 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)
494template <typename T, typename R, typename... TParams, typename... TArgs>
495typename 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)
504template <typename T, typename R, typename... TParams, typename... TArgs>
505typename 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)
512template <typename T, typename R, typename... TParams, typename... TArgs>
513typename 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)
522template <typename TFunc, typename... TArgs, typename>
523typename Callback<typename CallbackTraits<TFunc>::ResultType>::Pointer
524Callback<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
531template <typename R>
532using CallbackHandler = typename Callback<R>::Pointer;
533
534//! Closure
535using Closure = Callback<void>;
536
537//! Closure Handler
538using ClosureHandler = Closure::Pointer;
539
540} // namespace ailego
541
542#endif // __AILEGO_PATTERN_CLOSURE_H__
543