-
Notifications
You must be signed in to change notification settings - Fork 0
/
Callback.h
executable file
·134 lines (118 loc) · 3.52 KB
/
Callback.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#ifndef LIB_PINOCCIO_CALLBACK_H
#define LIB_PINOCCIO_CALLBACK_H
namespace pinoccio {
/**
* These classes provide easy and efficient lists of callbacks. To use
* them, declare a callback list, using the return type and any
* arguments to all callbacks as template parameters. For example, to
* store list of void func(bool, int) pointers:
*
* CallbackList<void, bool, int> fooCallbacks;
*
* Then, to add a callback to the list, first turn it into a Callback
* object using the create_callback function. The callback should be
* stored in a global or static variable, so it remains valid for as
* long as it is in the CallbackList.
*
* The resulting object can then be passed to CallbackList::append() (or
* prepend). For example, you could have:
*
* void doFoo(bool, int);
*
* void setup() {
* static auto callback = create_callback(doFoo);
* fooCallbacks.append(callback);
*
* Note the use of the auto keyword to prevent having to type the full
* Callback<void, bool, int> type.
*
* Calling the callbacks in the list is simple:
*
* fooCallbacks.callAll(true, 10);
*/
/**
* An object wrapping a function, for easy insertion in a linked List
* (CallbackList). In particular, this combines the function pointer
* with the next pointer. By allocating a Callback object statically, it
* can be added to a list without needing any dynamic allocation.
*/
template<typename Ret, typename... Args>
struct Callback {
// The function type this callback wraps
typedef Ret (f_t)(Args...);
f_t * const f;
Callback *next;
// Do not add constructors, that prevents the compiler from completely
// initializing the object at compiletime.
};
/**
* Helper function to efficiently create a Callback object. Over a
* constructor, this serves two purposes:
* - Because it is a function, it can autodeduce template arguments.
* - Because it uses an explicit initializer, the compiler can
* completely resolve it at compile time. In particular, when storing
* the result in a static variable inside a function, the compiler
* can initialize it at compile time, instead of delaying that to the
* first function call.
*/
template<typename Ret, typename... Args>
constexpr Callback<Ret, Args...> build_callback(Ret (*f)(Args...)) {
return {f, NULL};
}
/**
* A list of callbacks.
*/
template<typename Ret, typename... Args>
class CallbackList {
public:
typedef Callback<Ret, Args...> C_t;
/**
* Call all callbacks in the list with the given arguments.
*/
void callAll(Args... args) {
C_t *c = _first;
while(c) {
c->f(args...);
c = c->next;
}
}
/**
* Prepend a callback to this list.
*
* A reference to the callback passed is stored, so it is up to the
* caller to ensure it stays valid.
*/
void prepend(C_t &c) {
prepend(&c);
}
void prepend(C_t *c) {
c->next = _first;
_first = c;
}
/**
* Append a callback to this list.
*
* A reference to the callback passed is stored, so it is up to the
* caller to ensure it stays valid.
*/
void append(C_t &c) {
append(&c);
}
void append(C_t *c) {
C_t **i = &_first;
while(*i) {
i = &((*i)->next);
}
c->next = NULL;
*i = c;
}
/**
* Return the first callback in the list. Loop over the rest using
* the Callback's next pointer.
*/
const C_t* first() { return _first; }
private:
C_t *_first = NULL;
};
} // namespace pinoccio
#endif // LIB_PINOCCIO_CALLBACK_H