Mistake on this page?
Report an issue in GitHub or email us
common/FunctionPointerWithContext.h
Go to the documentation of this file.
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_FUNCTIONPOINTER_WITH_CONTEXT_H
20 #define MBED_FUNCTIONPOINTER_WITH_CONTEXT_H
21 
22 #include <cstring>
23 #include "ble/common/SafeBool.h"
24 
25 /**
26  * @file
27  * @addtogroup ble
28  * @{
29  * @addtogroup common
30  * @{
31  */
32 
33 /**
34  * Function like object adapter over freestanding and member functions.
35  *
36  * Freestanding and member functions are two distinct types in C++. One is
37  * not convertible into the other, and the call syntax between the two is
38  * different even if conceptually they are similar: Both primitives can be
39  * copied, called and produce a result.
40  *
41  * To solve incompatibilities, this class adapts freestanding and member functions
42  * to a common interface. The interface chosen is similar to the freestanding
43  * function pointers interface:
44  * - Copyable.
45  * - Nullable.
46  * - Callable.
47  *
48  * This class also offers a mechanism to chain other instances to it. When an
49  * instance is called, all the instances being part of the chain are called.
50  *
51  * @attention freestanding or member function adapted must accept a single
52  * argument, and this argument is a pointer to ContextType. Adapted
53  * primitives do not return anything.
54  *
55  * @tparam ContextType Type of the argument pointee.
56  */
57 template <typename ContextType>
58 class FunctionPointerWithContext : public SafeBool<FunctionPointerWithContext<ContextType> > {
59 public:
62  typedef void (*pvoidfcontext_t)(ContextType context);
63 
64  /**
65  * Create a FunctionPointerWithContext from a pointer to a freestanding
66  * function.
67  *
68  * @param[in] function The freestanding function to attach.
69  */
70  FunctionPointerWithContext(void (*function)(ContextType context) = NULL) :
71  _memberFunctionAndPointer(), _caller(NULL), _next(NULL)
72  {
73  attach(function);
74  }
75 
76  /**
77  * Create a FunctionPointerWithContext from a pointer to a member function
78  * and the instance which is used to call it.
79  *
80  * @param[in] object Pointer to the instance which is used to invoke @p
81  * member.
82  * @param[in] member Pointer to the member function to adapt.
83  */
84  template<typename T>
85  FunctionPointerWithContext(T *object, void (T::*member)(ContextType context)) :
86  _memberFunctionAndPointer(), _caller(NULL), _next(NULL)
87  {
88  attach(object, member);
89  }
90 
91  /**
92  * Copy construction.
93  *
94  * @param[in] that The FunctionPointerWithContext instance used to create
95  * this.
96  */
99  _caller(that._caller), _next(NULL) {
100  }
101 
102  /**
103  * Copy assignment.
104  *
105  * @param[in] that The FunctionPointerWithContext instance copied into this.
106  */
108  {
109  if (&that == this) {
110  return *this;
111  }
112 
114  _caller = that._caller;
115  _next = NULL;
116  return *this;
117  }
118 
119  /**
120  * Adapt a freestanding function.
121  *
122  * Previous content adapted is discarded while @p function replaces it.
123  *
124  * @note This function is equivalent to a call to the copy assignment
125  * operator.
126  *
127  * @param[in] function The freestanding function to attach.
128  */
129  void attach(void (*function)(ContextType context) = NULL)
130  {
131  _function = function;
132  _caller = functioncaller;
133  }
134 
135  /**
136  * Adapt a pointer to member function and the instance to use to call it.
137  *
138  * Previous content adapted is discarded while the adaptation
139  * of the pair @p object and @p member replaces it.
140  *
141  * @note This function is equivalent to a call to the copy assignment
142  * operator.
143  *
144  * @param[in] object Pointer to the instance is used to invoke @p member.
145  * @param[in] member Pointer to the member function to adapt.
146  */
147  template<typename T>
148  void attach(T *object, void (T::*member)(ContextType context))
149  {
150  _memberFunctionAndPointer._object = static_cast<void *>(object);
151  memcpy(
152  _memberFunctionAndPointer._memberFunction,
153  (char*) &member,
154  sizeof(member)
155  );
156  _caller = &FunctionPointerWithContext::membercaller<T>;
157  }
158 
159  /**
160  * Call the adapted function and functions chained to the instance.
161  *
162  * @param[in] context parameter to pass to chain of adapted functions.
163  */
164  void call(ContextType context) const
165  {
166  _caller(this, context);
167  }
168 
169  /**
170  * Call the adapted function and functions chained to the instance.
171  *
172  * @param[in] context parameter to pass to chain of adapted functions.
173  */
174  void call(ContextType context)
175  {
176  ((const FunctionPointerWithContext*) this)->call(context);
177  }
178 
179  /**
180  * Call the adapted function and functions chained to the instance.
181  *
182  * @param[in] context parameter to pass to chain of adapted functions.
183  */
184  void operator()(ContextType context) const
185  {
186  call(context);
187  }
188 
189  typedef void (FunctionPointerWithContext::*bool_type)() const;
190 
191  /**
192  * Indicate if a callable object is being adapted.
193  *
194  * @note implementation of safe bool operator.
195  *
196  * @return true if the content of the instance can be invoked and false
197  * otherwise.
198  */
199  bool toBool() const
200  {
201  return (_function || _memberFunctionAndPointer._object);
202  }
203 
204  /**
205  * Set a FunctionPointer instance as the next element in the chain of
206  * callable objects.
207  *
208  * @note Invoking call() on the head FunctionPointer invokes all
209  * chained callbacks.
210  *
211  * @note Refer to CallChainOfFunctionPointerWithContext as an alternative.
212  *
213  * @param next The instance to set as the next element in the chain of
214  * callable objects.
215  */
216  void chainAsNext(pFunctionPointerWithContext_t next)
217  {
218  _next = next;
219  }
220 
221  /**
222  * Access the next element in the call chain.
223  *
224  * If there is no next element in the chain, this function returns NULL.
225  *
226  * @return A pointer to the next FunctionPointerWithContext instance in the
227  * chain.
228  */
229  pFunctionPointerWithContext_t getNext() const
230  {
231  return _next;
232  }
233 
234  /**
235  * Access the next element in the call chain.
236  *
237  * If there is no next element in the chain, this function returns NULL.
238  *
239  * @return A pointer to the next FunctionPointerWithContext instance in the
240  * chain.
241  */
242  pvoidfcontext_t get_function() const
243  {
244  return (pvoidfcontext_t)_function;
245  }
246 
247  /**
248  * Equal to operator between two FunctionPointerWithContext instances.
249  *
250  * @param[in] lhs Left hand side of the expression.
251  * @param[in] rhs Right hand side of the expression.
252  *
253  * @return true if lhs and rhs adapt the same object and false otherwise.
254  */
255  friend bool operator==(
256  const FunctionPointerWithContext &lhs,
257  const FunctionPointerWithContext &rhs
258  ) {
259  return rhs._caller == lhs._caller &&
260  memcmp(
263  sizeof(rhs._memberFunctionAndPointer)
264  ) == 0;
265  }
266 
267 private:
268  template<typename T>
269  static void membercaller(cpFunctionPointerWithContext_t self, ContextType context) {
270  if (self->_memberFunctionAndPointer._object) {
271  T *o = static_cast<T *>(self->_memberFunctionAndPointer._object);
272  void (T::*m)(ContextType);
273  memcpy((char*) &m, self->_memberFunctionAndPointer._memberFunction, sizeof(m));
274  (o->*m)(context);
275  }
276  }
277 
278  static void functioncaller(cpFunctionPointerWithContext_t self, ContextType context) {
279  if (self->_function) {
280  self->_function(context);
281  }
282  }
283 
284  struct MemberFunctionAndPtr {
285  /*
286  * Forward declaration of a class and a member function to this class.
287  * Because the compiler doesn't know anything about the forwarded member
288  * function, it always uses the biggest size and the biggest alignment
289  * that a member function can take for objects of type UndefinedMemberFunction.
290  */
291  class UndefinedClass;
292  typedef void (UndefinedClass::*UndefinedMemberFunction)(ContextType);
293 
294  void* _object;
295  union {
296  char _memberFunction[sizeof(UndefinedMemberFunction)];
297  UndefinedMemberFunction _alignment;
298  };
299  };
300 
301  union {
302  pvoidfcontext_t _function; /**< Static function pointer - NULL if none attached */
303  /**
304  * object this pointer and pointer to member -
305  * _memberFunctionAndPointer._object will be NULL if none attached
306  */
307  mutable MemberFunctionAndPtr _memberFunctionAndPointer;
308  };
309 
310  void (*_caller)(const FunctionPointerWithContext*, ContextType);
311 
312  pFunctionPointerWithContext_t _next; /**< Optional link to make a chain out of functionPointers. This
313  * allows chaining function pointers without requiring
314  * external memory to manage the chain.*/
315 };
316 
317 /**
318  * Factory of adapted member function pointers.
319  *
320  * This factory eliminates the need to invoke the qualified constructor of
321  * FunctionPointerWithContext by using automatic type deduction of function
322  * templates.
323  *
324  * @code
325  *
326  * struct ReadHandler {
327  * void on_data_read(const GattReadCallbackParams*);
328  * };
329  *
330  * ReadHandler read_handler;
331  *
332  * PalGattClient& client;
333  *
334  * client.onDataRead(
335  * makeFunctionPointer(&read_handler, &ReadHandler::on_data_read)
336  * );
337  *
338  * // instead of
339  *
340  * client.onDataRead(
341  * FunctionPointerWithContext<const GattReadCallbackParams*>(
342  * &read_handler,
343  * &ReadHandler::on_data_read
344  * )
345  * );
346  * @endcode
347  *
348  *
349  * @param[in] object Instance to bound with @p member.
350  * @param member The member being adapted.
351  *
352  * @return Adaptation of the parameters in a FunctionPointerWithContext instance.
353  */
354 template<typename T, typename ContextType>
356  T *object,
357  void (T::*member)(ContextType context)
358 )
359 {
360  return FunctionPointerWithContext<ContextType>(object, member);
361 }
362 
363 /**
364  * @}
365  * @}
366  */
367 
368 #endif // ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H
FunctionPointerWithContext(const FunctionPointerWithContext &that)
Copy construction.
Function like object adapter over freestanding and member functions.
MemberFunctionAndPtr _memberFunctionAndPointer
object this pointer and pointer to member - _memberFunctionAndPointer._object will be NULL if none at...
pFunctionPointerWithContext_t getNext() const
Access the next element in the call chain.
pvoidfcontext_t _function
Static function pointer - NULL if none attached.
void attach(void(*function)(ContextType context)=NULL)
Adapt a freestanding function.
FunctionPointerWithContext< ContextType > makeFunctionPointer(T *object, void(T::*member)(ContextType context))
Factory of adapted member function pointers.
void operator()(ContextType context) const
Call the adapted function and functions chained to the instance.
void call(ContextType context) const
Call the adapted function and functions chained to the instance.
void call(ContextType context)
Call the adapted function and functions chained to the instance.
FunctionPointerWithContext(void(*function)(ContextType context)=NULL)
Create a FunctionPointerWithContext from a pointer to a freestanding function.
Safe conversion of objects in boolean context.
pvoidfcontext_t get_function() const
Access the next element in the call chain.
bool toBool() const
Indicate if a callable object is being adapted.
FunctionPointerWithContext & operator=(const FunctionPointerWithContext &that)
Copy assignment.
friend bool operator==(const FunctionPointerWithContext &lhs, const FunctionPointerWithContext &rhs)
Equal to operator between two FunctionPointerWithContext instances.
void attach(T *object, void(T::*member)(ContextType context))
Adapt a pointer to member function and the instance to use to call it.
void chainAsNext(pFunctionPointerWithContext_t next)
Set a FunctionPointer instance as the next element in the chain of callable objects.
FunctionPointerWithContext(T *object, void(T::*member)(ContextType context))
Create a FunctionPointerWithContext from a pointer to a member function and the instance which is use...
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.