adaptation for book and plug demo

Dependents:   BookAndPlug

Fork of BLE_API by Bluetooth Low Energy

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers FunctionPointerWithContext.h Source File

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 /** A class for storing and calling a pointer to a static or member void function
00024  *  that takes a context.
00025  */
00026 template <typename ContextType>
00027 class FunctionPointerWithContext : public SafeBool<FunctionPointerWithContext<ContextType> > {
00028 public:
00029     typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t;
00030     typedef const FunctionPointerWithContext<ContextType> *cpFunctionPointerWithContext_t;
00031     typedef void (*pvoidfcontext_t)(ContextType context);
00032 
00033     /** Create a FunctionPointerWithContext, attaching a static function.
00034      *
00035      *  @param function The void static function to attach (default is none).
00036      */
00037     FunctionPointerWithContext(void (*function)(ContextType context) = NULL) :
00038         _memberFunctionAndPointer(), _caller(NULL), _next(NULL) {
00039         attach(function);
00040     }
00041 
00042     /** Create a FunctionPointerWithContext, attaching a member function.
00043      *
00044      *  @param object The object pointer to invoke the member function on (the "this" pointer).
00045      *  @param function The address of the void member function to attach.
00046      */
00047     template<typename T>
00048     FunctionPointerWithContext(T *object, void (T::*member)(ContextType context)) :
00049         _memberFunctionAndPointer(), _caller(NULL), _next(NULL) {
00050         attach(object, member);
00051     }
00052 
00053     FunctionPointerWithContext(const FunctionPointerWithContext& that) : 
00054         _memberFunctionAndPointer(that._memberFunctionAndPointer), _caller(that._caller), _next(NULL) {
00055     }
00056 
00057     FunctionPointerWithContext& operator=(const FunctionPointerWithContext& that) {
00058         _memberFunctionAndPointer = that._memberFunctionAndPointer;
00059         _caller = that._caller; 
00060         _next = NULL;
00061         return *this;
00062     }
00063 
00064     /** Attach a static function.
00065      *
00066      *  @param function The void static function to attach (default is none).
00067      */
00068     void attach(void (*function)(ContextType context) = NULL) {
00069         _function = function;
00070         _caller = functioncaller;
00071     }
00072 
00073     /** Attach a member function.
00074      *
00075      *  @param object The object pointer to invoke the member function on (the "this" pointer).
00076      *  @param function The address of the void member function to attach.
00077      */
00078     template<typename T>
00079     void attach(T *object, void (T::*member)(ContextType context)) {
00080         _memberFunctionAndPointer._object = static_cast<void *>(object);
00081         memcpy(_memberFunctionAndPointer._memberFunction, (char*) &member, sizeof(member));
00082         _caller = &FunctionPointerWithContext::membercaller<T>;
00083     }
00084 
00085     /** Call the attached static or member function; if there are chained
00086      *  FunctionPointers their callbacks are invoked as well.
00087      *  @Note: All chained callbacks stack up, so hopefully there won't be too
00088      *  many FunctionPointers in a chain. */
00089     void call(ContextType context) const {
00090         _caller(this, context);
00091     }
00092 
00093     /**
00094      * @brief Same as above
00095      */
00096     void operator()(ContextType context) const {
00097         call(context);
00098     }
00099 
00100     /** Same as above, workaround for mbed os FunctionPointer implementation. */
00101     void call(ContextType context) {
00102         ((const FunctionPointerWithContext*)  this)->call(context);
00103     }
00104 
00105     typedef void (FunctionPointerWithContext::*bool_type)() const;
00106 
00107     /** 
00108      * implementation of safe bool operator
00109      */
00110     bool toBool() const {
00111         return (_function || _memberFunctionAndPointer._object);
00112     }
00113 
00114     /**
00115      * Set up an external FunctionPointer as a next in the chain of related
00116      * callbacks. Invoking call() on the head FunctionPointer will invoke all
00117      * chained callbacks.
00118      *
00119      * Refer to 'CallChain' as an alternative.
00120      */
00121     void chainAsNext(pFunctionPointerWithContext_t  next) {
00122         _next = next;
00123     }
00124 
00125     pFunctionPointerWithContext_t getNext(void) const {
00126         return _next;
00127     }
00128 
00129     pvoidfcontext_t get_function() const {
00130         return (pvoidfcontext_t)_function;
00131     }
00132 
00133     friend bool operator==(const FunctionPointerWithContext& lhs, const FunctionPointerWithContext& rhs) {
00134         return rhs._caller == lhs._caller &&
00135                memcmp(
00136                    &rhs._memberFunctionAndPointer, 
00137                    &lhs._memberFunctionAndPointer, 
00138                    sizeof(rhs._memberFunctionAndPointer)
00139                ) == 0;
00140     }
00141 
00142 private:
00143     template<typename T>
00144     static void membercaller(cpFunctionPointerWithContext_t self, ContextType context) {
00145         if (self->_memberFunctionAndPointer._object) {
00146             T *o = static_cast<T *>(self->_memberFunctionAndPointer._object);
00147             void (T::*m)(ContextType);
00148             memcpy((char*) &m, self->_memberFunctionAndPointer._memberFunction, sizeof(m));
00149             (o->*m)(context);
00150         }
00151     }
00152 
00153     static void functioncaller(cpFunctionPointerWithContext_t self, ContextType context) {
00154         if (self->_function) {
00155             self->_function(context);
00156         }
00157     }
00158 
00159     struct MemberFunctionAndPtr {
00160         /*
00161          * Forward declaration of a class and a member function to this class.
00162          * Because the compiler doesn't know anything about the forwarded member
00163          * function, it will always use the biggest size and the biggest alignment
00164          * that a member function can take for objects of type UndefinedMemberFunction.
00165          */
00166         class UndefinedClass;
00167         typedef void (UndefinedClass::*UndefinedMemberFunction)(ContextType);
00168 
00169         void* _object;
00170         union {
00171             char _memberFunction[sizeof(UndefinedMemberFunction)];
00172             UndefinedMemberFunction _alignment;
00173         };
00174     };
00175 
00176     union {
00177         pvoidfcontext_t _function;                      /**< Static function pointer - NULL if none attached */
00178         /**
00179          * object this pointer and pointer to member -
00180          * _memberFunctionAndPointer._object will be NULL if none attached
00181          */
00182         mutable MemberFunctionAndPtr _memberFunctionAndPointer;
00183     };
00184 
00185     void (*_caller)(const FunctionPointerWithContext*, ContextType);
00186 
00187     pFunctionPointerWithContext_t _next;                /**< Optional link to make a chain out of functionPointers. This
00188                                                          *   allows chaining function pointers without requiring
00189                                                          *   external memory to manage the chain. Refer to
00190                                                          *   'CallChain' as an alternative. */
00191 };
00192 
00193 /**
00194  * @brief Create a new FunctionPointerWithContext which bind an instance and a  
00195  * a member function together.
00196  * @details This little helper is a just here to eliminate the need to write the
00197  * FunctionPointerWithContext type each time you want to create one by kicking 
00198  * automatic type deduction of function templates. With this function, it is easy 
00199  * to write only one entry point for functions which expect a FunctionPointer 
00200  * in parameters.
00201  * 
00202  * @param object to bound with member function
00203  * @param member The member function called
00204  * @return a new FunctionPointerWithContext
00205  */
00206 template<typename T, typename ContextType>
00207 FunctionPointerWithContext<ContextType> makeFunctionPointer(T *object, void (T::*member)(ContextType context)) 
00208 {
00209     return FunctionPointerWithContext<ContextType>(object, member);
00210 }
00211 
00212 #endif // ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H