Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
FunctionPointerWithContext.h
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2013 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H 00018 #define MBED_FUNCTIONPOINTER_WITH_CONTEXT_H 00019 00020 #include <string.h> 00021 #include "SafeBool.h " 00022 00023 /** 00024 * @file 00025 * @addtogroup ble 00026 * @{ 00027 * @addtogroup common 00028 * @{ 00029 */ 00030 00031 /** 00032 * Function like object adapter over freestanding and member functions. 00033 * 00034 * Freestanding and member functions are two distinct types in C++. One is 00035 * not convertible into the other, and the call syntax between the two is 00036 * different even if conceptually they are similar: Both primitives can be 00037 * copied, called and produce a result. 00038 * 00039 * To solve incompatibilities, this class adapts freestanding and member functions 00040 * to a common interface. The interface chosen is similar to the freestanding 00041 * function pointers interface: 00042 * - Copyable. 00043 * - Nullable. 00044 * - Callable. 00045 * 00046 * This class also offers a mechanism to chain other instances to it. When an 00047 * instance is called, all the instances being part of the chain are called. 00048 * 00049 * @attention freestanding or member function adapted must accept a single 00050 * argument, and this argument is a pointer to ContextType. Adapted 00051 * primitives do not return anything. 00052 * 00053 * @tparam ContextType Type of the argument pointee. 00054 */ 00055 template <typename ContextType> 00056 class FunctionPointerWithContext : public SafeBool<FunctionPointerWithContext<ContextType> > { 00057 public: 00058 typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t; 00059 typedef const FunctionPointerWithContext<ContextType> *cpFunctionPointerWithContext_t; 00060 typedef void (*pvoidfcontext_t)(ContextType context); 00061 00062 /** 00063 * Create a FunctionPointerWithContext from a pointer to a freestanding 00064 * function. 00065 * 00066 * @param[in] function The freestanding function to attach. 00067 */ 00068 FunctionPointerWithContext(void (*function)(ContextType context) = NULL) : 00069 _memberFunctionAndPointer(), _caller(NULL), _next(NULL) 00070 { 00071 attach(function); 00072 } 00073 00074 /** 00075 * Create a FunctionPointerWithContext from a pointer to a member function 00076 * and the instance which is used to call it. 00077 * 00078 * @param[in] object Pointer to the instance which is used to invoke @p 00079 * member. 00080 * @param[in] member Pointer to the member function to adapt. 00081 */ 00082 template<typename T> 00083 FunctionPointerWithContext(T *object, void (T::*member)(ContextType context)) : 00084 _memberFunctionAndPointer(), _caller(NULL), _next(NULL) 00085 { 00086 attach(object, member); 00087 } 00088 00089 /** 00090 * Copy construction. 00091 * 00092 * @param[in] that The FunctionPointerWithContext instance used to create 00093 * this. 00094 */ 00095 FunctionPointerWithContext(const FunctionPointerWithContext &that) : 00096 _memberFunctionAndPointer(that._memberFunctionAndPointer), 00097 _caller(that._caller), _next(NULL) { 00098 } 00099 00100 /** 00101 * Copy assignment. 00102 * 00103 * @param[in] that The FunctionPointerWithContext instance copied into this. 00104 */ 00105 FunctionPointerWithContext &operator=(const FunctionPointerWithContext &that) 00106 { 00107 _memberFunctionAndPointer = that._memberFunctionAndPointer; 00108 _caller = that._caller; 00109 _next = NULL; 00110 return *this; 00111 } 00112 00113 /** 00114 * Adapt a freestanding function. 00115 * 00116 * Previous content adapted is discarded while @p function replaces it. 00117 * 00118 * @note This function is equivalent to a call to the copy assignment 00119 * operator. 00120 * 00121 * @param[in] function The freestanding function to attach. 00122 */ 00123 void attach(void (*function)(ContextType context) = NULL) 00124 { 00125 _function = function; 00126 _caller = functioncaller; 00127 } 00128 00129 /** 00130 * Adapt a pointer to member function and the instance to use to call it. 00131 * 00132 * Previous content adapted is discarded while the adaptation 00133 * of the pair @p object and @p member replaces it. 00134 * 00135 * @note This function is equivalent to a call to the copy assignment 00136 * operator. 00137 * 00138 * @param[in] object Pointer to the instance is used to invoke @p member. 00139 * @param[in] member Pointer to the member function to adapt. 00140 */ 00141 template<typename T> 00142 void attach(T *object, void (T::*member)(ContextType context)) 00143 { 00144 _memberFunctionAndPointer._object = static_cast<void *>(object); 00145 memcpy( 00146 _memberFunctionAndPointer._memberFunction, 00147 (char*) &member, 00148 sizeof(member) 00149 ); 00150 _caller = &FunctionPointerWithContext::membercaller<T>; 00151 } 00152 00153 /** 00154 * Call the adapted function and functions chained to the instance. 00155 * 00156 * @param[in] context parameter to pass to chain of adapted functions. 00157 */ 00158 void call(ContextType context) const 00159 { 00160 _caller(this, context); 00161 } 00162 00163 /** 00164 * Call the adapted function and functions chained to the instance. 00165 * 00166 * @param[in] context parameter to pass to chain of adapted functions. 00167 */ 00168 void call(ContextType context) 00169 { 00170 ((const FunctionPointerWithContext*) this)->call(context); 00171 } 00172 00173 /** 00174 * Call the adapted function and functions chained to the instance. 00175 * 00176 * @param[in] context parameter to pass to chain of adapted functions. 00177 */ 00178 void operator()(ContextType context) const 00179 { 00180 call(context); 00181 } 00182 00183 typedef void (FunctionPointerWithContext::*bool_type)() const; 00184 00185 /** 00186 * Indicate if a callable object is being adapted. 00187 * 00188 * @note implementation of safe bool operator. 00189 * 00190 * @return true if the content of the instance can be invoked and false 00191 * otherwise. 00192 */ 00193 bool toBool() const 00194 { 00195 return (_function || _memberFunctionAndPointer._object); 00196 } 00197 00198 /** 00199 * Set a FunctionPointer instance as the next element in the chain of 00200 * callable objects. 00201 * 00202 * @note Invoking call() on the head FunctionPointer invokes all 00203 * chained callbacks. 00204 * 00205 * @note Refer to CallChainOfFunctionPointerWithContext as an alternative. 00206 * 00207 * @param next The instance to set as the next element in the chain of 00208 * callable objects. 00209 */ 00210 void chainAsNext(pFunctionPointerWithContext_t next) 00211 { 00212 _next = next; 00213 } 00214 00215 /** 00216 * Access the next element in the call chain. 00217 * 00218 * If there is no next element in the chain, this function returns NULL. 00219 * 00220 * @return A pointer to the next FunctionPointerWithContext instance in the 00221 * chain. 00222 */ 00223 pFunctionPointerWithContext_t getNext(void) const 00224 { 00225 return _next; 00226 } 00227 00228 /** 00229 * Access the next element in the call chain. 00230 * 00231 * If there is no next element in the chain, this function returns NULL. 00232 * 00233 * @return A pointer to the next FunctionPointerWithContext instance in the 00234 * chain. 00235 */ 00236 pvoidfcontext_t get_function() const 00237 { 00238 return (pvoidfcontext_t)_function; 00239 } 00240 00241 /** 00242 * Equal to operator between two FunctionPointerWithContext instances. 00243 * 00244 * @param[in] lhs Left hand side of the expression. 00245 * @param[in] rhs Right hand side of the expression. 00246 * 00247 * @return true if lhs and rhs adapt the same object and false otherwise. 00248 */ 00249 friend bool operator==( 00250 const FunctionPointerWithContext &lhs, 00251 const FunctionPointerWithContext &rhs 00252 ) { 00253 return rhs._caller == lhs._caller && 00254 memcmp( 00255 &rhs._memberFunctionAndPointer, 00256 &lhs._memberFunctionAndPointer, 00257 sizeof(rhs._memberFunctionAndPointer) 00258 ) == 0; 00259 } 00260 00261 private: 00262 template<typename T> 00263 static void membercaller(cpFunctionPointerWithContext_t self, ContextType context) { 00264 if (self->_memberFunctionAndPointer._object) { 00265 T *o = static_cast<T *>(self->_memberFunctionAndPointer._object); 00266 void (T::*m)(ContextType); 00267 memcpy((char*) &m, self->_memberFunctionAndPointer._memberFunction, sizeof(m)); 00268 (o->*m)(context); 00269 } 00270 } 00271 00272 static void functioncaller(cpFunctionPointerWithContext_t self, ContextType context) { 00273 if (self->_function) { 00274 self->_function(context); 00275 } 00276 } 00277 00278 struct MemberFunctionAndPtr { 00279 /* 00280 * Forward declaration of a class and a member function to this class. 00281 * Because the compiler doesn't know anything about the forwarded member 00282 * function, it always uses the biggest size and the biggest alignment 00283 * that a member function can take for objects of type UndefinedMemberFunction. 00284 */ 00285 class UndefinedClass; 00286 typedef void (UndefinedClass::*UndefinedMemberFunction)(ContextType); 00287 00288 void* _object; 00289 union { 00290 char _memberFunction[sizeof(UndefinedMemberFunction)]; 00291 UndefinedMemberFunction _alignment; 00292 }; 00293 }; 00294 00295 union { 00296 pvoidfcontext_t _function; /**< Static function pointer - NULL if none attached */ 00297 /** 00298 * object this pointer and pointer to member - 00299 * _memberFunctionAndPointer._object will be NULL if none attached 00300 */ 00301 mutable MemberFunctionAndPtr _memberFunctionAndPointer; 00302 }; 00303 00304 void (*_caller)(const FunctionPointerWithContext*, ContextType); 00305 00306 pFunctionPointerWithContext_t _next; /**< Optional link to make a chain out of functionPointers. This 00307 * allows chaining function pointers without requiring 00308 * external memory to manage the chain. Refer to 00309 * 'CallChain' as an alternative. */ 00310 }; 00311 00312 /** 00313 * Factory of adapted member function pointers. 00314 * 00315 * This factory eliminates the need to invoke the qualified constructor of 00316 * FunctionPointerWithContext by using automatic type deduction of function 00317 * templates. 00318 * 00319 * @code 00320 * 00321 * struct ReadHandler { 00322 * void on_data_read(const GattReadCallbackParams*); 00323 * }; 00324 * 00325 * ReadHandler read_handler; 00326 * 00327 * GattClient& client; 00328 * 00329 * client.onDataRead( 00330 * makeFunctionPointer(&read_handler, &ReadHandler::on_data_read) 00331 * ); 00332 * 00333 * // instead of 00334 * 00335 * client.onDataRead( 00336 * FunctionPointerWithContext<const GattReadCallbackParams*>( 00337 * &read_handler, 00338 * &ReadHandler::on_data_read 00339 * ) 00340 * ); 00341 * @endcode 00342 * 00343 * 00344 * @param[in] object Instance to bound with @p member. 00345 * @param member The member being adapted. 00346 * 00347 * @return Adaptation of the parameters in a FunctionPointerWithContext instance. 00348 */ 00349 template<typename T, typename ContextType> 00350 FunctionPointerWithContext<ContextType> makeFunctionPointer( 00351 T *object, 00352 void (T::*member)(ContextType context) 00353 ) { 00354 return FunctionPointerWithContext<ContextType>(object, member); 00355 } 00356 00357 /** 00358 * @} 00359 * @} 00360 */ 00361 00362 #endif // ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H
Generated on Tue Jul 12 2022 13:30:06 by
