Nuria Framework - Core
Core module of the NuriaProject Framework
 All Classes Functions Typedefs Enumerations Enumerator Groups
callback.hpp
1 /* Copyright (c) 2014, The Nuria Project
2  * This software is provided 'as-is', without any express or implied
3  * warranty. In no event will the authors be held liable for any damages
4  * arising from the use of this software.
5  * Permission is granted to anyone to use this software for any purpose,
6  * including commercial applications, and to alter it and redistribute it
7  * freely, subject to the following restrictions:
8  * 1. The origin of this software must not be misrepresented; you must not
9  * claim that you wrote the original software. If you use this software
10  * in a product, an acknowledgment in the product documentation would be
11  * appreciated but is not required.
12  * 2. Altered source versions must be plainly marked as such, and must not be
13  * misrepresented as being the original software.
14  * 3. This notice may not be removed or altered from any source
15  * distribution.
16  */
17 
18 #ifndef NURIA_CALLBACK_HPP
19 #define NURIA_CALLBACK_HPP
20 
21 #include <type_traits>
22 #include <functional>
23 
24 #include <QSharedData>
25 #include <QMetaType>
26 #include <QVariant>
27 #include <QList>
28 
29 #include "essentials.hpp"
30 #include "variant.hpp"
31 
32 namespace Nuria {
33 class CallbackPrivate;
34 
36 namespace CallbackHelper {
37  template< int ... Index >
38  struct IndexTuple {
39  template< int N >
40  using append = IndexTuple< Index ..., N >;
41  };
42 
43  template< int Size >
45  typedef typename CreateIndexTuple< Size - 1 >::type::template append< Size - 1 > type;
46  };
47 
48  template< >
49  struct CreateIndexTuple< 1 > {
50  typedef IndexTuple< > type;
51  };
52 
53  template< typename... Types >
54  using buildIndexTuple = typename CreateIndexTuple< sizeof...(Types) + 1 >::type;
55 
56  // qMetaTypeId wrapper, which returns 0 for T = void.
57  template< typename T >
58  constexpr int typeId () { return qMetaTypeId< T > (); }
59 
60  template< >
61  constexpr int typeId< void > () { return 0; }
62 
63  // Creates a raw list of type ids and values from 'args'
64  template< typename T >
65  void getArguments (void **list, int *types, int idx, T *cur) {
66  list[idx] = cur;
67  types[idx] = qMetaTypeId< typename std::remove_const< T >::type > ();
68  }
69 
70  template< typename T, typename T2, typename ... Args >
71  void getArguments (void **list, int *types, int idx,
72  T *cur, T2 *next, Args * ... args) {
73  getArguments (list, types, idx, cur);
74  getArguments (list, types, idx + 1, next, args ...);
75  }
76 
77 }
78 
141 class NURIA_CORE_EXPORT Callback {
142 
143  // Forward declare helper structures
144  struct TrampolineBase;
145  template< typename Ret, typename ... Args > struct MethodHelper;
146  template< typename Class, typename Ret, typename ... Args > struct MemberMethodHelper;
147  template< typename FullType, typename Ret, typename ... Args > struct LambdaHelper;
148 
149 public:
150 
154  enum Type {
155  Invalid = 0,
156  StaticMethod = 1,
157  MemberMethod = 2,
158  Slot = 3,
159  Lambda = 4
160  };
161 
165  enum Placeholder {
166  _1 = 0,
167  _2,
168  _3,
169  _4,
170  _5,
171  _6,
172  _7,
173  _8,
174  _9,
175  _10
176  };
177 
179  Callback ();
180 
182  explicit Callback (QObject *receiver, const char *slot, bool variadic = false);
183 
185  Callback (const Callback &other);
186 
188  template< typename Ret, typename ... Args >
189  Callback (Ret (*func)(Args ...), bool variadic = false)
190  : d (0) { setCallback (func); setVariadic (variadic); }
191 
193  template< typename Class, typename Ret, typename ... Args >
194  Callback (Class *instance, Ret (Class::*func)(Args ...), bool variadic = false)
195  : d (0) { setCallback (instance, func); setVariadic (variadic); }
196 
197  template< typename Ret, typename ... Args >
198  Callback (const std::function< Ret(Args ...) > &func, bool variadic = false)
199  : d (0) { setCallback (func); setVariadic (variadic); }
200 
202  template< typename Lambda >
203  static Callback fromLambda (Lambda l, bool variadic = false) {
204  Callback cb = fromLambdaImpl (l, &Lambda::operator());
205  cb.setVariadic (variadic);
206  return cb;
207  }
208 
210  ~Callback ();
211 
213  Callback &operator= (const Callback &other);
214 
224  bool operator== (const Callback &other) const;
225 
227  bool isValid () const;
228 
230  Type type () const;
231 
233  bool isVariadic () const;
234 
236  void setVariadic (bool variadic);
237 
239  int returnType () const;
240 
242  QList< int > argumentTypes () const;
243 
248  //
249  template< typename Ret, typename ... Args >
250  bool setCallback (Ret (*func)(Args ...)) {
251  QList< int > args;
252  buildArgList< Args ... > (args);
253  return initBase (new MethodHelper< Ret, Args ... > (func),
254  CallbackHelper::typeId< Ret > (), args);
255  }
256 
257  // Member methods
258  template< typename Class, typename Ret, typename ... Args >
259  bool setCallback (Class *instance, Ret (Class::*func)(Args ...)) {
260  QList< int > args;
261  buildArgList< Args ... > (args);
262  return initBase (new MemberMethodHelper< Class, Ret, Args ... > (instance, func),
263  CallbackHelper::typeId< Ret > (), args);
264  }
265 
266  // std::function
267  template< typename Ret, typename ... Args >
268  bool setCallback (std::function< Ret(Args ...) > func) {
269  QList< int > args;
270  buildArgList< Args ... > (args);
271  return initBase (new LambdaHelper< std::function< Ret(Args ...) >, Ret, Args ... > (func),
272  CallbackHelper::typeId< Ret > (), args);
273  }
274 
275  // QObject slot
276  bool setCallback (QObject *receiver, const char *slot);
277 
278  // Convenience assignment operators
279  template< typename Ret, typename ... Args >
280  Callback &operator= (Ret (*func)(Args ...)) { setCallback (func); return *this; }
281 
291  void bindList (const QVariantList &arguments = QVariantList());
292 
296  template< typename Lambda, typename ... Args >
297  static Callback boundLambda (Lambda func, const Args &... args) {
298  Callback cb = fromLambdaImpl (func, &Lambda::operator());
299  cb.bind (args ...);
300  return cb;
301  }
302 
308  template< typename ... Args >
309  inline Callback &bind (const Args &... args) {
310  bindList (Variant::buildList (args ...));
311  return *this;
312  }
313 
319  QVariant invoke (const QVariantList &arguments) const;
320 
324  template< typename ... Args >
325  QVariant operator() (const Args &... args) const {
326  void *list[sizeof... (Args)];
327  int types[sizeof... (Args)];
328  CallbackHelper::getArguments (list, types, 0, const_cast< Args * > (&args) ...);
329  return invoke (sizeof... (Args), list, types);
330  }
331 
333  inline QVariant operator() () {
334  return invoke (0, 0, 0);
335  }
336 
337 private:
338 
339  friend class CallbackPrivate;
340 
341  QVariant invoke (int count, void **args, int *types) const;
342  QVariant invokePrepared (const QVariantList &arguments) const;
343 
345  QVariant invokeInternal (int count, void **args, int *types) const;
346 
348  // If you have a error on line struct removeRef< T & >:
349  // T& is not allowed for values. Use const T & or just T instead.
350  template< typename T > struct removeRef { typedef T type; };
351  template< typename T > struct removeRef< T & >; // Not allowed!
352  template< typename T > struct removeRef< const T & > { typedef T type; };
353 
357  template< typename Lambda, typename Ret, typename ... Args >
358  inline static Callback fromLambdaImpl (Lambda l, Ret (Lambda::*)(Args ...) const) {
359  return Callback (std::function< Ret(Args ...) > (l));
360  }
361 
366  bool initBase (TrampolineBase *base, int retType, const QList< int > &args);
367 
368  template< typename T1, typename ... T2 >
369  inline void buildArgListDo (QList< int > &list, T1 cur, T2 ... next) {
370  list.append (cur);
371  buildArgListDo (list, next ...);
372  }
373 
374  template< typename T >
375  inline void buildArgListDo (QList< int > &list, T cur)
376  { list.append (cur); }
377 
379  inline void buildArgListDo (QList< int > &) { }
380 
386  template< typename ... Args >
387  inline void buildArgList (QList< int > &list) {
388  buildArgListDo (list, qMetaTypeId< typename removeRef< Args >::type > () ...);
389  }
390 
396  struct TrampolineBase {
397  Type type;
398  TrampolineBase (Type t) : type (t) {}
399 
400  virtual ~TrampolineBase () {}
401  virtual void trampoline (void **) = 0;
402  };
403 
404  struct MemberTrampolineBase : TrampolineBase {
405  MemberTrampolineBase (void *inst) : TrampolineBase (MemberMethod), instance (inst) {}
406  void *instance;
407  };
408 
409  // Static methods
410  template< typename Ret, typename ... Args >
411  struct MethodHelper : public TrampolineBase {
412  typedef Ret (*Prototype)(Args ...);
413  Prototype func;
414 
415  MethodHelper (Prototype f) : TrampolineBase (StaticMethod), func (f) {}
416 
417  template< int ... Index >
418  inline void trampolineImpl (void **args, CallbackHelper::IndexTuple< Index... >) {
419  (*reinterpret_cast< typename removeRef< Ret >::type * > (args[0])) =
420  func (*reinterpret_cast< typename removeRef< Args >::type * >(args[Index]) ...);
421  }
422 
423  void trampoline (void **args)
424  { trampolineImpl (args, CallbackHelper::buildIndexTuple< Args ... > ()); }
425 
426  };
427 
428  template< typename ... Args >
429  struct MethodHelper< void, Args ... > : public TrampolineBase {
430  typedef void (*Prototype)(Args ...);
431  Prototype func;
432 
433  MethodHelper (Prototype f) : TrampolineBase (StaticMethod), func (f) {}
434 
435  template< int ... Index >
436  inline void trampolineImpl (void **args, CallbackHelper::IndexTuple< Index... >) {
437  Q_UNUSED(args);
438  func (*reinterpret_cast< typename removeRef< Args >::type * >(args[Index]) ...);
439  }
440 
441  void trampoline (void **args)
442  { trampolineImpl (args, CallbackHelper::buildIndexTuple< Args ... > ()); }
443 
444  };
445 
446  // Member methods
447  template< typename Class, typename Ret, typename ... Args >
448  struct MemberMethodHelper : public MemberTrampolineBase {
449  typedef Ret (Class::*Prototype)(Args ...);
450  Prototype func;
451 
452  MemberMethodHelper (Class *inst, Prototype f) : MemberTrampolineBase (inst), func (f) {}
453 
454  template< int ... Index >
455  inline void trampolineImpl (void **args, CallbackHelper::IndexTuple< Index... >) {
456  (*reinterpret_cast< typename removeRef< Ret >::type * > (args[0])) =
457  (reinterpret_cast< Class * > (instance)->*func)
458  (*reinterpret_cast< typename removeRef< Args >::type * >(args[Index]) ...);
459  }
460 
461  void trampoline (void **args)
462  { trampolineImpl (args, CallbackHelper::buildIndexTuple< Args ... > ()); }
463 
464  };
465 
466  template< typename Class, typename ... Args >
467  struct MemberMethodHelper< Class, void, Args ... > : public MemberTrampolineBase {
468  typedef void (Class::*Prototype)(Args ...);
469  Prototype func;
470 
471  MemberMethodHelper (Class *inst, Prototype f) : MemberTrampolineBase (inst), func (f) {}
472 
473  template< int ... Index >
474  inline void trampolineImpl (void **args, CallbackHelper::IndexTuple< Index... >) {
475  Q_UNUSED(args);
476  (reinterpret_cast< Class * > (instance)->*func)
477  (*reinterpret_cast< typename removeRef< Args >::type * >(args[Index]) ...);
478  }
479 
480  void trampoline (void **args)
481  { trampolineImpl (args, CallbackHelper::buildIndexTuple< Args ... > ()); }
482 
483  };
484 
485  // std::function< ... >
486  template< typename FullType, typename Ret, typename ... Args >
487  struct LambdaHelper : public TrampolineBase {
488  FullType func;
489 
490  LambdaHelper (const FullType &f) : TrampolineBase (Lambda), func (f) {}
491 
492  template< int ... Index >
493  inline void trampolineImpl (void **args, CallbackHelper::IndexTuple< Index... >) {
494  (*reinterpret_cast< typename removeRef< Ret >::type * > (args[0])) =
495  func (*reinterpret_cast< typename removeRef< Args >::type * >(args[Index]) ...);
496  }
497 
498  void trampoline (void **args)
499  { trampolineImpl (args, CallbackHelper::buildIndexTuple< Args ... > ()); }
500 
501  };
502 
503  template< typename FullType, typename ... Args >
504  struct LambdaHelper< FullType, void, Args ... > : public TrampolineBase {
505  FullType func;
506 
507  LambdaHelper (const FullType &f) : TrampolineBase (Lambda), func (f) {}
508 
509  template< int ... Index >
510  inline void trampolineImpl (void **args, CallbackHelper::IndexTuple< Index... >) {
511  Q_UNUSED(args);
512  func (*reinterpret_cast< typename removeRef< Args >::type * >(args[Index]) ...);
513  }
514 
515  void trampoline (void **args)
516  { trampolineImpl (args, CallbackHelper::buildIndexTuple< Args ... > ()); }
517 
518  };
519 
520  // d-ptr
521  CallbackPrivate *d;
522 
523 };
524 }
525 
526 //
527 Q_DECLARE_METATYPE(Nuria::Callback)
528 Q_DECLARE_METATYPE(Nuria::Callback::Placeholder)
529 
530 #endif // NURIA_CALLBACK_HPP
A modern style callback mechanism which can be bound to various method types including slots...
Definition: callback.hpp:141
Callback(Ret(*func)(Args...), bool variadic=false)
Definition: callback.hpp:189
Placeholder
Definition: callback.hpp:165
static QVariantList buildList(const Items &...items)
Definition: variant.hpp:547
Callback & bind(const Args &...args)
Definition: callback.hpp:309
static Callback boundLambda(Lambda func, const Args &...args)
Definition: callback.hpp:297
Callback(Class *instance, Ret(Class::*func)(Args...), bool variadic=false)
Definition: callback.hpp:194
Definition: callback.hpp:44
Type
Definition: callback.hpp:154
void setVariadic(bool variadic)
static Callback fromLambda(Lambda l, bool variadic=false)
Definition: callback.hpp:203
Definition: callback.hpp:38