Marco Zecchini
/
Example_RTOS
Rtos API example
mbed-os/features/FEATURE_BLE/ble/FunctionPointerWithContext.h
- Committer:
- marcozecchini
- Date:
- 2019-02-23
- Revision:
- 0:9fca2b23d0ba
File content as of revision 0:9fca2b23d0ba:
/* mbed Microcontroller Library * Copyright (c) 2006-2013 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H #define MBED_FUNCTIONPOINTER_WITH_CONTEXT_H #include <string.h> #include "SafeBool.h" /** * @file * @addtogroup ble * @{ * @addtogroup common * @{ */ /** * Function like object adapter over freestanding and member functions. * * Freestanding and member functions are two distinct types in C++. One is * not convertible into the other, and the call syntax between the two is * different even if conceptually they are similar: Both primitives can be * copied, called and produce a result. * * To solve incompatibilities, this class adapts freestanding and member functions * to a common interface. The interface chosen is similar to the freestanding * function pointers interface: * - Copyable. * - Nullable. * - Callable. * * This class also offers a mechanism to chain other instances to it. When an * instance is called, all the instances being part of the chain are called. * * @important freestanding or member function adapted must accept a single * argument, and this argument is a pointer to ContextType. Adapted * primitives do not return anything. * * @tparam ContextType Type of the argument pointee. */ template <typename ContextType> class FunctionPointerWithContext : public SafeBool<FunctionPointerWithContext<ContextType> > { public: typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t; typedef const FunctionPointerWithContext<ContextType> *cpFunctionPointerWithContext_t; typedef void (*pvoidfcontext_t)(ContextType context); /** * Create a FunctionPointerWithContext from a pointer to a freestanding * function. * * @param[in] function The freestanding function to attach. */ FunctionPointerWithContext(void (*function)(ContextType context) = NULL) : _memberFunctionAndPointer(), _caller(NULL), _next(NULL) { attach(function); } /** * Create a FunctionPointerWithContext from a pointer to a member function * and the instance which is used to call it. * * @param[in] object Pointer to the instance which is used to invoke @p * member. * @param[in] Pointer to the member function to adapt. */ template<typename T> FunctionPointerWithContext(T *object, void (T::*member)(ContextType context)) : _memberFunctionAndPointer(), _caller(NULL), _next(NULL) { attach(object, member); } /** * Copy construction. * * @param[in] that The FunctionPointerWithContext instance used to create * this. */ FunctionPointerWithContext(const FunctionPointerWithContext &that) : _memberFunctionAndPointer(that._memberFunctionAndPointer), _caller(that._caller), _next(NULL) { } /** * Copy assignment. * * @param[in] that The FunctionPointerWithContext instance copied into this. */ FunctionPointerWithContext &operator=(const FunctionPointerWithContext &that) { _memberFunctionAndPointer = that._memberFunctionAndPointer; _caller = that._caller; _next = NULL; return *this; } /** * Adapt a freestanding function. * * Previous content adapted is discarded while @p function replaces it. * * @note This function is equivalent to a call to the copy assignment * operator. * * @param[in] function The freestanding function to attach. */ void attach(void (*function)(ContextType context) = NULL) { _function = function; _caller = functioncaller; } /** * Adapt a pointer to member function and the instance to use to call it. * * Previous content adapted is discarded while the adaptation * of the pair @p object and @p member replaces it. * * @note This function is equivalent to a call to the copy assignment * operator. * * @param[in] object Pointer to the instance is used to invoke @p member. * @param[in] function Pointer to the member function to adapt. */ template<typename T> void attach(T *object, void (T::*member)(ContextType context)) { _memberFunctionAndPointer._object = static_cast<void *>(object); memcpy( _memberFunctionAndPointer._memberFunction, (char*) &member, sizeof(member) ); _caller = &FunctionPointerWithContext::membercaller<T>; } /** * Call the adapted function and functions chained to the instance. * * @param[in] context parameter to pass to chain of adapted functions. */ void call(ContextType context) const { _caller(this, context); } /** * Call the adapted function and functions chained to the instance. * * @param[in] context parameter to pass to chain of adapted functions. */ void call(ContextType context) { ((const FunctionPointerWithContext*) this)->call(context); } /** * Call the adapted function and functions chained to the instance. * * @param[in] context parameter to pass to chain of adapted functions. */ void operator()(ContextType context) const { call(context); } typedef void (FunctionPointerWithContext::*bool_type)() const; /** * Indicate if a callable object is being adapted. * * @note implementation of safe bool operator. * * @return true if the content of the instance can be invoked and false * otherwise. */ bool toBool() const { return (_function || _memberFunctionAndPointer._object); } /** * Set a FunctionPointer instance as the next element in the chain of * callable objects. * * @note Invoking call() on the head FunctionPointer invokes all * chained callbacks. * * @note Refer to CallChainOfFunctionPointerWithContext as an alternative. * * @param next The instance to set as the next element in the chain of * callable objects. */ void chainAsNext(pFunctionPointerWithContext_t next) { _next = next; } /** * Access the next element in the call chain. * * If there is no next element in the chain, this function returns NULL. * * @return A pointer to the next FunctionPointerWithContext instance in the * chain. */ pFunctionPointerWithContext_t getNext(void) const { return _next; } /** * Access the next element in the call chain. * * If there is no next element in the chain, this function returns NULL. * * @return A pointer to the next FunctionPointerWithContext instance in the * chain. */ pvoidfcontext_t get_function() const { return (pvoidfcontext_t)_function; } /** * Equal to operator between two FunctionPointerWithContext instances. * * @param[in] lhs Left hand side of the expression. * @param[in] rhs Right hand side of the expression. * * @return true if lhs and rhs adapt the same object and false otherwise. */ friend bool operator==( const FunctionPointerWithContext &lhs, const FunctionPointerWithContext &rhs ) { return rhs._caller == lhs._caller && memcmp( &rhs._memberFunctionAndPointer, &lhs._memberFunctionAndPointer, sizeof(rhs._memberFunctionAndPointer) ) == 0; } private: template<typename T> static void membercaller(cpFunctionPointerWithContext_t self, ContextType context) { if (self->_memberFunctionAndPointer._object) { T *o = static_cast<T *>(self->_memberFunctionAndPointer._object); void (T::*m)(ContextType); memcpy((char*) &m, self->_memberFunctionAndPointer._memberFunction, sizeof(m)); (o->*m)(context); } } static void functioncaller(cpFunctionPointerWithContext_t self, ContextType context) { if (self->_function) { self->_function(context); } } struct MemberFunctionAndPtr { /* * Forward declaration of a class and a member function to this class. * Because the compiler doesn't know anything about the forwarded member * function, it always uses the biggest size and the biggest alignment * that a member function can take for objects of type UndefinedMemberFunction. */ class UndefinedClass; typedef void (UndefinedClass::*UndefinedMemberFunction)(ContextType); void* _object; union { char _memberFunction[sizeof(UndefinedMemberFunction)]; UndefinedMemberFunction _alignment; }; }; union { pvoidfcontext_t _function; /**< Static function pointer - NULL if none attached */ /** * object this pointer and pointer to member - * _memberFunctionAndPointer._object will be NULL if none attached */ mutable MemberFunctionAndPtr _memberFunctionAndPointer; }; void (*_caller)(const FunctionPointerWithContext*, ContextType); pFunctionPointerWithContext_t _next; /**< Optional link to make a chain out of functionPointers. This * allows chaining function pointers without requiring * external memory to manage the chain. Refer to * 'CallChain' as an alternative. */ }; /** * Factory of adapted member function pointers. * * This factory eliminates the need to invoke the qualified constructor of * FunctionPointerWithContext by using automatic type deduction of function * templates. * * @code * * struct ReadHandler { * void on_data_read(const GattReadCallbackParams*); * }; * * ReadHandler read_handler; * * GattClient& client; * * client.onDataRead( * makeFunctionPointer(&read_handler, &ReadHandler::on_data_read) * ); * * // instead of * * client.onDataRead( * FunctionPointerWithContext<const GattReadCallbackParams*>( * &read_handler, * &ReadHandler::on_data_read * ) * ); * @endcode * * * @param[in] object Instance to bound with @p member. * @param member The member being adapted. * * @return Adaptation of the parameters in a FunctionPointerWithContext instance. */ template<typename T, typename ContextType> FunctionPointerWithContext<ContextType> makeFunctionPointer( T *object, void (T::*member)(ContextType context) ) { return FunctionPointerWithContext<ContextType>(object, member); } /** * @} * @} */ #endif // ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H