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