Marco Zecchini
/
Example_RTOS
Rtos API example
Diff: mbed-os/features/FEATURE_BLE/ble/FunctionPointerWithContext.h
- Revision:
- 0:9fca2b23d0ba
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os/features/FEATURE_BLE/ble/FunctionPointerWithContext.h Sat Feb 23 12:13:36 2019 +0000 @@ -0,0 +1,362 @@ +/* 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