Mbed OS Reference
Loading...
Searching...
No Matches
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 */
57template <typename ContextType>
58class FunctionPointerWithContext : public SafeBool<FunctionPointerWithContext<ContextType> > {
59public:
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 */
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 */
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==(
258 ) {
259 return rhs._caller == lhs._caller &&
260 memcmp(
263 sizeof(rhs._memberFunctionAndPointer)
264 ) == 0;
265 }
266
267private:
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 */
354template<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
Function like object adapter over freestanding and member functions.
bool toBool() const
Indicate if a callable object is being adapted.
FunctionPointerWithContext(const FunctionPointerWithContext &that)
Copy construction.
pFunctionPointerWithContext_t getNext() const
Access the next element in the call chain.
pvoidfcontext_t _function
Static function pointer - NULL if none attached.
void call(ContextType context)
Call the adapted function and functions chained to the instance.
pvoidfcontext_t get_function() const
Access the next element in the call chain.
void attach(void(*function)(ContextType context)=NULL)
Adapt a freestanding function.
FunctionPointerWithContext & operator=(const FunctionPointerWithContext &that)
Copy assignment.
FunctionPointerWithContext(void(*function)(ContextType context)=NULL)
Create a FunctionPointerWithContext from a pointer to a freestanding function.
FunctionPointerWithContext(T *object, void(T::*member)(ContextType context))
Create a FunctionPointerWithContext from a pointer to a member function and the instance which is use...
MemberFunctionAndPtr _memberFunctionAndPointer
object this pointer and pointer to member - _memberFunctionAndPointer._object will be NULL if none at...
friend bool operator==(const FunctionPointerWithContext &lhs, const FunctionPointerWithContext &rhs)
Equal to operator between two FunctionPointerWithContext instances.
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.
void attach(T *object, void(T::*member)(ContextType context))
Adapt a pointer to member function and the instance to use to call it.
void operator()(ContextType context) const
Call the adapted function and functions chained to the instance.
Safe conversion of objects in boolean context.
FunctionPointerWithContext< ContextType > makeFunctionPointer(T *object, void(T::*member)(ContextType context))
Factory of adapted member function pointers.