2016-07-20 21:10:36 +00:00
|
|
|
/* 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"
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* @addtogroup ble
|
|
|
|
* @{
|
|
|
|
* @addtogroup common
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function like object adapter over freestanding and member functions.
|
|
|
|
*
|
2017-11-07 22:10:29 +00:00
|
|
|
* 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
|
2017-10-23 23:50:20 +00:00
|
|
|
* copied, called and produce a result.
|
|
|
|
*
|
2017-11-07 22:10:29 +00:00
|
|
|
* To solve incompatibilities, this class adapts freestanding and member functions
|
2017-10-23 23:50:20 +00:00
|
|
|
* to a common interface. The interface chosen is similar to the freestanding
|
|
|
|
* function pointers interface:
|
2017-11-07 22:10:29 +00:00
|
|
|
* - Copyable.
|
|
|
|
* - Nullable.
|
|
|
|
* - Callable.
|
2017-10-23 23:50:20 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
2017-12-13 16:14:16 +00:00
|
|
|
* @attention freestanding or member function adapted must accept a single
|
2017-11-07 22:10:29 +00:00
|
|
|
* argument, and this argument is a pointer to ContextType. Adapted
|
|
|
|
* primitives do not return anything.
|
2017-10-23 23:50:20 +00:00
|
|
|
*
|
|
|
|
* @tparam ContextType Type of the argument pointee.
|
2016-07-20 21:10:36 +00:00
|
|
|
*/
|
|
|
|
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);
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* Create a FunctionPointerWithContext from a pointer to a freestanding
|
|
|
|
* function.
|
2016-07-20 21:10:36 +00:00
|
|
|
*
|
2017-10-23 23:50:20 +00:00
|
|
|
* @param[in] function The freestanding function to attach.
|
2016-07-20 21:10:36 +00:00
|
|
|
*/
|
|
|
|
FunctionPointerWithContext(void (*function)(ContextType context) = NULL) :
|
2017-10-23 23:50:20 +00:00
|
|
|
_memberFunctionAndPointer(), _caller(NULL), _next(NULL)
|
|
|
|
{
|
2016-07-20 21:10:36 +00:00
|
|
|
attach(function);
|
|
|
|
}
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
2017-11-07 22:10:29 +00:00
|
|
|
* Create a FunctionPointerWithContext from a pointer to a member function
|
|
|
|
* and the instance which is used to call it.
|
2016-07-20 21:10:36 +00:00
|
|
|
*
|
2017-11-07 22:10:29 +00:00
|
|
|
* @param[in] object Pointer to the instance which is used to invoke @p
|
2017-10-23 23:50:20 +00:00
|
|
|
* member.
|
2017-12-13 18:08:53 +00:00
|
|
|
* @param[in] member Pointer to the member function to adapt.
|
2016-07-20 21:10:36 +00:00
|
|
|
*/
|
|
|
|
template<typename T>
|
|
|
|
FunctionPointerWithContext(T *object, void (T::*member)(ContextType context)) :
|
2017-10-23 23:50:20 +00:00
|
|
|
_memberFunctionAndPointer(), _caller(NULL), _next(NULL)
|
|
|
|
{
|
2016-07-20 21:10:36 +00:00
|
|
|
attach(object, member);
|
|
|
|
}
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* Copy construction.
|
|
|
|
*
|
|
|
|
* @param[in] that The FunctionPointerWithContext instance used to create
|
|
|
|
* this.
|
|
|
|
*/
|
|
|
|
FunctionPointerWithContext(const FunctionPointerWithContext &that) :
|
|
|
|
_memberFunctionAndPointer(that._memberFunctionAndPointer),
|
|
|
|
_caller(that._caller), _next(NULL) {
|
2016-07-20 21:10:36 +00:00
|
|
|
}
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* Copy assignment.
|
|
|
|
*
|
|
|
|
* @param[in] that The FunctionPointerWithContext instance copied into this.
|
|
|
|
*/
|
|
|
|
FunctionPointerWithContext &operator=(const FunctionPointerWithContext &that)
|
|
|
|
{
|
2016-07-20 21:10:36 +00:00
|
|
|
_memberFunctionAndPointer = that._memberFunctionAndPointer;
|
2017-10-23 23:50:20 +00:00
|
|
|
_caller = that._caller;
|
2016-07-20 21:10:36 +00:00
|
|
|
_next = NULL;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* Adapt a freestanding function.
|
|
|
|
*
|
2017-11-07 22:10:29 +00:00
|
|
|
* Previous content adapted is discarded while @p function replaces it.
|
2016-07-20 21:10:36 +00:00
|
|
|
*
|
2017-10-23 23:50:20 +00:00
|
|
|
* @note This function is equivalent to a call to the copy assignment
|
|
|
|
* operator.
|
|
|
|
*
|
|
|
|
* @param[in] function The freestanding function to attach.
|
2016-07-20 21:10:36 +00:00
|
|
|
*/
|
2017-10-23 23:50:20 +00:00
|
|
|
void attach(void (*function)(ContextType context) = NULL)
|
|
|
|
{
|
2016-07-20 21:10:36 +00:00
|
|
|
_function = function;
|
|
|
|
_caller = functioncaller;
|
|
|
|
}
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* Adapt a pointer to member function and the instance to use to call it.
|
2016-07-20 21:10:36 +00:00
|
|
|
*
|
2017-11-07 22:10:29 +00:00
|
|
|
* Previous content adapted is discarded while the adaptation
|
|
|
|
* of the pair @p object and @p member replaces it.
|
2017-10-23 23:50:20 +00:00
|
|
|
*
|
|
|
|
* @note This function is equivalent to a call to the copy assignment
|
|
|
|
* operator.
|
|
|
|
*
|
2017-11-07 22:10:29 +00:00
|
|
|
* @param[in] object Pointer to the instance is used to invoke @p member.
|
2017-12-13 18:08:53 +00:00
|
|
|
* @param[in] member Pointer to the member function to adapt.
|
2016-07-20 21:10:36 +00:00
|
|
|
*/
|
|
|
|
template<typename T>
|
2017-10-23 23:50:20 +00:00
|
|
|
void attach(T *object, void (T::*member)(ContextType context))
|
|
|
|
{
|
2016-07-20 21:10:36 +00:00
|
|
|
_memberFunctionAndPointer._object = static_cast<void *>(object);
|
2017-10-23 23:50:20 +00:00
|
|
|
memcpy(
|
|
|
|
_memberFunctionAndPointer._memberFunction,
|
|
|
|
(char*) &member,
|
|
|
|
sizeof(member)
|
|
|
|
);
|
2016-07-20 21:10:36 +00:00
|
|
|
_caller = &FunctionPointerWithContext::membercaller<T>;
|
|
|
|
}
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
{
|
2016-07-20 21:10:36 +00:00
|
|
|
_caller(this, context);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-10-23 23:50:20 +00:00
|
|
|
* Call the adapted function and functions chained to the instance.
|
|
|
|
*
|
|
|
|
* @param[in] context parameter to pass to chain of adapted functions.
|
2016-07-20 21:10:36 +00:00
|
|
|
*/
|
2017-10-23 23:50:20 +00:00
|
|
|
void call(ContextType context)
|
|
|
|
{
|
|
|
|
((const FunctionPointerWithContext*) this)->call(context);
|
2016-07-20 21:10:36 +00:00
|
|
|
}
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* 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);
|
2016-07-20 21:10:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef void (FunctionPointerWithContext::*bool_type)() const;
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* Indicate if a callable object is being adapted.
|
|
|
|
*
|
2017-11-07 22:10:29 +00:00
|
|
|
* @note implementation of safe bool operator.
|
2017-10-23 23:50:20 +00:00
|
|
|
*
|
|
|
|
* @return true if the content of the instance can be invoked and false
|
|
|
|
* otherwise.
|
2016-07-20 21:10:36 +00:00
|
|
|
*/
|
2017-10-23 23:50:20 +00:00
|
|
|
bool toBool() const
|
|
|
|
{
|
2016-07-20 21:10:36 +00:00
|
|
|
return (_function || _memberFunctionAndPointer._object);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-10-23 23:50:20 +00:00
|
|
|
* Set a FunctionPointer instance as the next element in the chain of
|
|
|
|
* callable objects.
|
|
|
|
*
|
2017-11-07 22:10:29 +00:00
|
|
|
* @note Invoking call() on the head FunctionPointer invokes all
|
2016-07-20 21:10:36 +00:00
|
|
|
* chained callbacks.
|
|
|
|
*
|
2017-10-23 23:50:20 +00:00
|
|
|
* @note Refer to CallChainOfFunctionPointerWithContext as an alternative.
|
|
|
|
*
|
|
|
|
* @param next The instance to set as the next element in the chain of
|
|
|
|
* callable objects.
|
2016-07-20 21:10:36 +00:00
|
|
|
*/
|
2017-10-23 23:50:20 +00:00
|
|
|
void chainAsNext(pFunctionPointerWithContext_t next)
|
|
|
|
{
|
2016-07-20 21:10:36 +00:00
|
|
|
_next = next;
|
|
|
|
}
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
{
|
2016-07-20 21:10:36 +00:00
|
|
|
return _next;
|
|
|
|
}
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
{
|
2016-07-20 21:10:36 +00:00
|
|
|
return (pvoidfcontext_t)_function;
|
|
|
|
}
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
) {
|
2016-07-20 21:10:36 +00:00
|
|
|
return rhs._caller == lhs._caller &&
|
|
|
|
memcmp(
|
2017-10-23 23:50:20 +00:00
|
|
|
&rhs._memberFunctionAndPointer,
|
|
|
|
&lhs._memberFunctionAndPointer,
|
2016-07-20 21:10:36 +00:00
|
|
|
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
|
2017-11-07 22:10:29 +00:00
|
|
|
* function, it always uses the biggest size and the biggest alignment
|
2016-07-20 21:10:36 +00:00
|
|
|
* 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. */
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2017-10-23 23:50:20 +00:00
|
|
|
* Factory of adapted member function pointers.
|
|
|
|
*
|
2017-10-30 15:37:59 +00:00
|
|
|
* This factory eliminates the need to invoke the qualified constructor of
|
2017-10-23 23:50:20 +00:00
|
|
|
* FunctionPointerWithContext by using automatic type deduction of function
|
2017-10-30 15:37:59 +00:00
|
|
|
* templates.
|
2017-10-23 23:50:20 +00:00
|
|
|
*
|
|
|
|
* @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.
|
2016-07-20 21:10:36 +00:00
|
|
|
*/
|
|
|
|
template<typename T, typename ContextType>
|
2017-10-23 23:50:20 +00:00
|
|
|
FunctionPointerWithContext<ContextType> makeFunctionPointer(
|
|
|
|
T *object,
|
|
|
|
void (T::*member)(ContextType context)
|
|
|
|
) {
|
2016-07-20 21:10:36 +00:00
|
|
|
return FunctionPointerWithContext<ContextType>(object, member);
|
|
|
|
}
|
|
|
|
|
2017-10-23 23:50:20 +00:00
|
|
|
/**
|
|
|
|
* @}
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
2016-07-20 21:10:36 +00:00
|
|
|
#endif // ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H
|