Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers FunctionPointerWithContext.h Source File

FunctionPointerWithContext.h

Go to the documentation of this file.
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  * @important 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] 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] function 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