Mistake on this page?
Report an issue in GitHub or email us
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  */
84 template <typename ContextType>
86  public SafeBool<CallChainOfFunctionPointersWithContext<ContextType> > {
87 public:
88  /**
89  * Alias of the FunctionPointerWithContext type this object can store.
90  */
92 
93 public:
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  */
149  pFunctionPointerWithContext_t add(const FunctionPointerWithContext<ContextType> &func)
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  */
214  bool hasCallbacksAttached() const
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 
299 private:
300  /**
301  * Add a callback to the head of the callchain.
302  *
303  * @return A pointer to the head of the callchain.
304  */
305  pFunctionPointerWithContext_t common_add(pFunctionPointerWithContext_t pf)
306  {
307  if (chainHead == NULL) {
308  chainHead = pf;
309  } else {
310  pf->chainAsNext(chainHead);
311  chainHead = pf;
312  }
313 
314  return chainHead;
315  }
316 
317 private:
318  /**
319  * Pointer to the first callback of the callchain or NULL if the callchain
320  * is empty.
321  */
322  pFunctionPointerWithContext_t chainHead;
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
void clear()
Remove all functions registered in the chain.
Function like object adapter over freestanding and member functions.
bool toBool() const
Test if the callchain is empty or not.
void call(ContextType context) const
Call sequentially each member of the chain.
pFunctionPointerWithContext_t add(T *tptr, void(T::*mptr)(ContextType context))
Add a member function bound to its instance at the front of the chain.
pFunctionPointerWithContext_t getNext() const
Access the next element in the call chain.
pFunctionPointerWithContext_t add(const FunctionPointerWithContext< ContextType > &func)
Add a FunctionPointerWithContext at the front of the chain.
pFunctionPointerWithContext_t add(void(*function)(ContextType context))
Add a function pointer at the front of the chain.
FunctionPointerWithContext< ContextType > * pFunctionPointerWithContext_t
Alias of the FunctionPointerWithContext type this object can store.
void call(ContextType context) const
Call the adapted function and functions chained to the instance.
virtual ~CallChainOfFunctionPointersWithContext()
Destruction of the callchain.
void call(ContextType context)
Call sequentially each member of the chain.
bool detach(const FunctionPointerWithContext< ContextType > &toDetach)
Detach a function pointer from a callchain.
Function like object hosting a list of FunctionPointerWithContext.
void operator()(ContextType context) const
Call sequentially each member of the chain.
Safe conversion of objects in boolean context.
bool hasCallbacksAttached() const
Check whether the callchain contains any callbacks.
void chainAsNext(pFunctionPointerWithContext_t next)
Set a FunctionPointer instance as the next element in the chain of callable objects.
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.