Mbed OS Reference
Loading...
Searching...
No Matches
common/CallChainOfFunctionPointersWithContext.h
1/* mbed Microcontroller Library
2 * Copyright (c) 2006-2020 ARM Limited
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#ifndef MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
20#define MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
21
22#include <cstring>
24#include "ble/common/SafeBool.h"
25
26/**
27 * @addtogroup ble
28 * @{
29 * @addtogroup common
30 * @{
31 */
32
33/**
34 * Function like object hosting a list of FunctionPointerWithContext.
35 *
36 * Upon call, each FunctionPointerWithContext instance present in the object will
37 * be called in sequence with the initial parameters.
38 *
39 * It can be seen as a variation of the observer pattern this object being the
40 * observable, instances of the FunctionPointerWithContext being the observable
41 * and the notify/update operation being the function call.
42 *
43 * Example:
44 * @code
45 *
46 * CallChainOfFunctionPointersWithContext<void *> chain;
47 *
48 * void first(void *context) {
49 * printf("'first' function.\n");
50 * }
51 *
52 * void second(void *context) {
53 * printf("'second' function.\n");
54 * }
55 *
56 * class Test {
57 * public:
58 * void f(void *context) {
59 * printf("A::f (class member).\n");
60 * }
61 * };
62 *
63 * int main() {
64 * Test test;
65 *
66 * chain.add(second);
67 * chain.add_front(first);
68 * chain.add(&test, &Test::f);
69 *
70 * // will print:
71 * // 'second' function.
72 * // 'first' function.
73 * // A::f (class member).
74 * chain.call();
75 * }
76 * @endcode
77 *
78 * @note memory allocation is used to add new function like objects into the
79 * call chain.
80 *
81 * @tparam ContextType Type of the parameter accepted by the callbacks hosted
82 * in the object.
83 */
84template <typename ContextType>
86 public SafeBool<CallChainOfFunctionPointersWithContext<ContextType> > {
87public:
88 /**
89 * Alias of the FunctionPointerWithContext type this object can store.
90 */
92
93public:
94 /**
95 * Create an empty callchain.
96 */
98
99 /* Disallow copy constructor and assignment operators. */
102 ) = delete;
105 ) = delete;
106
107 /**
108 * Destruction of the callchain.
109 */
111 {
112 clear();
113 }
114
115 /**
116 * Add a function pointer at the front of the chain.
117 *
118 * @param[in] function A pointer to a void function.
119 *
120 * @return The FunctionPointerWithContext object created from @p function.
121 */
122 pFunctionPointerWithContext_t add(void (*function)(ContextType context))
123 {
124 return common_add(new FunctionPointerWithContext<ContextType>(function));
125 }
126
127 /**
128 * Add a member function bound to its instance at the front of the chain.
129 *
130 * @param[in] tptr Pointer to the object to call the member function on.
131 * @param[in] mptr Pointer to the member function to be called.
132 *
133 * @return The FunctionPointerWithContext object created from @p tptr and
134 * @p mptr.
135 */
136 template<typename T>
137 pFunctionPointerWithContext_t add(T *tptr, void (T::*mptr)(ContextType context))
138 {
139 return common_add(new FunctionPointerWithContext<ContextType>(tptr, mptr));
140 }
141
142 /**
143 * Add a FunctionPointerWithContext at the front of the chain.
144 *
145 * @param[in] func The FunctionPointerWithContext to add.
146 *
147 * @return The function object created for @p func.
148 */
150 {
151 return common_add(new FunctionPointerWithContext<ContextType>(func));
152 }
153
154 /**
155 * Detach a function pointer from a callchain.
156 *
157 * @param[in] toDetach FunctionPointerWithContext instance to detach from
158 * this callchain.
159 *
160 * @return true if a function pointer has been detached and false otherwise.
161 *
162 * @note It is safe to remove a function pointer while
163 * call(ContextType) is traversing the chain.
164 */
166 {
167 pFunctionPointerWithContext_t current = chainHead;
168 pFunctionPointerWithContext_t previous = NULL;
169
170 while (current) {
171 if(*current == toDetach) {
172 if(previous == NULL) {
173 if(currentCalled == current) {
174 currentCalled = NULL;
175 }
176 chainHead = current->getNext();
177 } else {
178 if(currentCalled == current) {
179 currentCalled = previous;
180 }
181 previous->chainAsNext(current->getNext());
182 }
183 delete current;
184 return true;
185 }
186
187 previous = current;
188 current = current->getNext();
189 }
190
191 return false;
192 }
193
194 /**
195 * Remove all functions registered in the chain.
196 */
197 void clear()
198 {
199 pFunctionPointerWithContext_t fptr = chainHead;
200 while (fptr) {
201 pFunctionPointerWithContext_t deadPtr = fptr;
202 fptr = deadPtr->getNext();
203 delete deadPtr;
204 }
205
206 chainHead = NULL;
207 }
208
209 /**
210 * Check whether the callchain contains any callbacks.
211 *
212 * @return true if the callchain is not empty and false otherwise.
213 */
215 {
216 return (chainHead != NULL);
217 }
218
219 /**
220 * Call sequentially each member of the chain.
221 *
222 * @param[in] context Parameter to pass to the functions called.
223 */
224 void call(ContextType context)
225 {
226 ((const CallChainOfFunctionPointersWithContext*) this)->call(context);
227 }
228
229 /**
230 * Call sequentially each member of the chain.
231 *
232 * @param[in] context Parameter to pass to the functions called.
233 */
234 void call(ContextType context) const
235 {
236 currentCalled = chainHead;
237
238 while(currentCalled) {
239 currentCalled->call(context);
240 // if this was the head and the call removed the head
241 if(currentCalled == NULL) {
242 currentCalled = chainHead;
243 } else {
244 currentCalled = currentCalled->getNext();
245 }
246 }
247 }
248
249 /**
250 * Call sequentially each member of the chain.
251 *
252 * @param[in] context Parameter to pass to the functions called.
253 *
254 * @code
255 *
256 * void first(bool);
257 * void second(bool);
258 *
259 * CallChainOfFunctionPointerWithContext<bool> foo;
260 *
261 * foo.attach(first);
262 * foo.attach(second);
263 *
264 * // call the callchain like a function
265 * foo(true);
266 *
267 * @endcode
268 */
269 void operator()(ContextType context) const
270 {
271 call(context);
272 }
273
274 /**
275 * Test if the callchain is empty or not.
276 *
277 * @return true if the callchain is not empty and false otherwise.
278 *
279 * @note used by SafeBool to offer a safe boolean conversion.
280 *
281 * @code
282 * CallChainOfFunctionPointersWithContext<void *> chain;
283 *
284 * if (!chain) {
285 * // Do something if the chain is empty.
286 * }
287 *
288 * if (chain) {
289 * // Do something if the chain is not empty.
290 * }
291 * @endcode
292 *
293 */
294 bool toBool() const
295 {
296 return chainHead != NULL;
297 }
298
299private:
300 /**
301 * Add a callback to the head of the callchain.
302 *
303 * @return A pointer to the head of the callchain.
304 */
306 {
307 if (chainHead == NULL) {
308 chainHead = pf;
309 } else {
310 pf->chainAsNext(chainHead);
311 chainHead = pf;
312 }
313
314 return chainHead;
315 }
316
317private:
318 /**
319 * Pointer to the first callback of the callchain or NULL if the callchain
320 * is empty.
321 */
323
324 /**
325 * Pointer to the function being called.
326 *
327 * It is used to maintain the data structure integrity if a function is
328 * removed during the call() operation.
329 *
330 * @note It has to be mutable to accomodate the const version of call(). The
331 * iterator doesn't leak outside the object; therefore, it remains seen as
332 * const from an external standpoint.
333 */
334 mutable pFunctionPointerWithContext_t currentCalled;
335};
336
337/**
338 * @}
339 * @}
340 */
341
342#endif
Function like object hosting a list of FunctionPointerWithContext.
bool toBool() const
Test if the callchain is empty or not.
void call(ContextType context)
Call sequentially each member of the chain.
FunctionPointerWithContext< ContextType > * pFunctionPointerWithContext_t
Alias of the FunctionPointerWithContext type this object can store.
pFunctionPointerWithContext_t add(void(*function)(ContextType context))
Add a function pointer at the front of the chain.
bool detach(const FunctionPointerWithContext< ContextType > &toDetach)
Detach a function pointer from a callchain.
pFunctionPointerWithContext_t add(T *tptr, void(T::*mptr)(ContextType context))
Add a member function bound to its instance at the front of the chain.
virtual ~CallChainOfFunctionPointersWithContext()
Destruction of the callchain.
pFunctionPointerWithContext_t add(const FunctionPointerWithContext< ContextType > &func)
Add a FunctionPointerWithContext at the front of the chain.
void clear()
Remove all functions registered in the chain.
void call(ContextType context) const
Call sequentially each member of the chain.
bool hasCallbacksAttached() const
Check whether the callchain contains any callbacks.
void operator()(ContextType context) const
Call sequentially each member of the chain.
Function like object adapter over freestanding and member functions.
pFunctionPointerWithContext_t getNext() const
Access the next element in the call chain.
void call(ContextType context) const
Call the adapted function and functions chained to the instance.
void chainAsNext(pFunctionPointerWithContext_t next)
Set a FunctionPointer instance as the next element in the chain of callable objects.
Safe conversion of objects in boolean context.