From f396e3165f8fe0c802840d93b6f39b5584e9c259 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 6 Apr 2016 08:01:28 -0500 Subject: [PATCH] Added improved FuncPtr type FuncPtr provides a more flexible templated function class as a replacement for FunctionPointer. FuncPtr provides an intuitive template interface: void doit(int, char *); FuncPtr doit_ptr(doit); doit_ptr(10, "hi!"); FuncPtr places memory management on the user, only supporting storing an extra pointer for pointers to externally stored objects that can be passed to the function. Additional binding can be supplied by an external class. FuncPtr hello(&object, &Object::method); Additionally FuncPtr provides a copy constructor, allowing FuncPtrs themselves to be passed to existing interfaces. FuncPtr hello(doit); ticker.attach(hello, 1000); --- hal/api/FunctionPointer.h | 799 ++++++++++++++++++++++++++++++++++---- 1 file changed, 722 insertions(+), 77 deletions(-) diff --git a/hal/api/FunctionPointer.h b/hal/api/FunctionPointer.h index 2d49ba035e..32853fe877 100644 --- a/hal/api/FunctionPointer.h +++ b/hal/api/FunctionPointer.h @@ -21,38 +21,566 @@ namespace mbed { -/* If we had variaditic templates, this wouldn't be a problem, but until C++11 is enabled, we are stuck with multiple classes... */ +// Reusable FuncPtr class based on template specialization +template +class FuncPtr; /** A class for storing and calling a pointer to a static or member function */ -template -class FunctionPointerArg1{ +template +class FuncPtr { public: - /** Create a FunctionPointer, attaching a static function + /** Create a FuncPtr, attaching a static function * * @param function The static function to attach (default is none) */ - FunctionPointerArg1(R (*function)(A1) = 0) { + FuncPtr(R (*function)(A1, A2, A3, A4) = 0) { attach(function); } - /** Create a FunctionPointer, attaching a member function + /** Create a FuncPtr, attaching a static function with bound pointer + * + * @param object Pointer to object to bind to function + * @param function The static function to attach + */ + template + FuncPtr(T *object, R (*function)(T*, A1, A2, A3, A4)) { + attach(object, function); + } + + /** Create a FuncPtr, attaching a member function * * @param object The object pointer to invoke the member function on (i.e. the this pointer) * @param function The address of the member function to attach */ template - FunctionPointerArg1(T *object, R (T::*member)(A1)) { + FuncPtr(T *object, R (T::*member)(A1, A2, A3, A4)) { attach(object, member); } + /** Create a FuncPtr, attaching a function object + * + * @param object Pointer to a function object to attach + */ + template + FuncPtr(T *object) { + attach(object, &T::operator()); + } + + /** Create a FuncPtr from another FuncPtr + * + * @param func The func to attach + */ + FuncPtr(const FuncPtr &func) { + attach(func); + } + + /** Attach a static function + * + * @param function The static function to attach (default is none) + */ + void attach(R (*function)(A1, A2, A3, A4)) { + _object = 0; + memcpy(&_function, &function, sizeof function); + _thunk = &FuncPtr::staticthunk; + } + + /** Attach a static function with bound pointer + * + * @param object Pointer to object to bind to function + * @param function The static function to attach + */ + template + void attach(T *object, R (*function)(T*, A1, A2, A3, A4)) { + _object = static_cast(object); + memcpy(&_function, &function, sizeof function); + _thunk = &FuncPtr::boundthunk; + } + + /** Attach a member function + * + * @param object The object pointer to invoke the member function on (i.e. the this pointer) + * @param function The address of the member function to attach + */ + template + void attach(T *object, R (T::*method)(A1, A2, A3, A4)) { + _object = static_cast(object); + memcpy(&_function, &method, sizeof method); + _thunk = &FuncPtr::methodthunk; + } + + /** Attach a function object + * + * @param object Pointer to a function object to attach + */ + template + void attach(T *object) { + attach(object, &T::operator()); + } + + /** Attach a FuncPtr + * + * @param func The func to attach + */ + void attach(const FuncPtr &func) { + _object = func._object; + memcpy(&_function, &func._function, sizeof _function); + _thunk = func._thunk; + } + + /** Call the attached static or member function + */ + R call(A1 a1, A2 a2, A3 a3, A4 a4) { + return _thunk(_object, _function, a1, a2, a3, a4); + } + + /** Get registered static function + */ + R (*get_function(A1, A2, A3, A4))() { + return reinterpret_cast(_object ? 0 : _function); + } + +#ifdef MBED_OPERATORS + R operator ()(A1 a1, A2 a2, A3 a3, A4 a4) { + return call(a1, a2, a3, a4); + } + operator bool(void) const { + return static_cast(_function); + } +#endif +private: + // Static thunks for various function types + static R staticthunk(void*, void *func, A1 a1, A2 a2, A3 a3, A4 a4) { + R (*f)(A1, A2, A3, A4) = *reinterpret_cast(func); + return f(a1, a2, a3, a4); + } + + template + static R boundthunk(void *object, void *func, A1 a1, A2 a2, A3 a3, A4 a4) { + T *o = static_cast(object); + R (*f)(T*, A1, A2, A3, A4) = *reinterpret_cast(func); + return f(o, a1); + } + + template + static R methodthunk(void *object, void *member, A1 a1, A2 a2, A3 a3, A4 a4) { + T* o = static_cast(object); + R (T::*m)(A1, A2, A3, A4) = *reinterpret_cast(member); + return (o->*m)(a1, a2, a3, a4); + } + + // Forward declaration of an unknown class + // this kind of declaration is authorized by the standard (see 8.3.3/2 of C++ 03 standard). + // As a result, the compiler will allocate for UnknownFunctionMember_t the biggest size + // and biggest alignment possible for member function. + // This type can be used inside unions, it will help to provide the storage + // with the proper size and alignment guarantees + class UnknownClass; + + // object this pointer + void *_object; + + // aligned raw member function pointer storage - converted back by registered thunk + char _function[sizeof(void (UnknownClass::*)())]; + + // registered function to convert back and call _m.member on _object + R (*_thunk)(void*, void*, A1, A2, A3, A4); +}; + +/** A class for storing and calling a pointer to a static or member function + */ +template +class FuncPtr { +public: + /** Create a FuncPtr, attaching a static function + * + * @param function The static function to attach (default is none) + */ + FuncPtr(R (*function)(A1, A2, A3) = 0) { + attach(function); + } + + /** Create a FuncPtr, attaching a static function with bound pointer + * + * @param object Pointer to object to bind to function + * @param function The static function to attach + */ + template + FuncPtr(T *object, R (*function)(T*, A1, A2, A3)) { + attach(object, function); + } + + /** Create a FuncPtr, attaching a member function + * + * @param object The object pointer to invoke the member function on (i.e. the this pointer) + * @param function The address of the member function to attach + */ + template + FuncPtr(T *object, R (T::*member)(A1, A2, A3)) { + attach(object, member); + } + + /** Create a FuncPtr, attaching a function object + * + * @param object Pointer to a function object to attach + */ + template + FuncPtr(T *object) { + attach(object, &T::operator()); + } + + /** Create a FuncPtr from another FuncPtr + * + * @param func The func to attach + */ + FuncPtr(const FuncPtr &func) { + attach(func); + } + + /** Attach a static function + * + * @param function The static function to attach (default is none) + */ + void attach(R (*function)(A1, A2, A3)) { + _object = 0; + memcpy(&_function, &function, sizeof function); + _thunk = &FuncPtr::staticthunk; + } + + /** Attach a static function with bound pointer + * + * @param object Pointer to object to bind to function + * @param function The static function to attach + */ + template + void attach(T *object, R (*function)(T*, A1, A2, A3)) { + _object = static_cast(object); + memcpy(&_function, &function, sizeof function); + _thunk = &FuncPtr::boundthunk; + } + + /** Attach a member function + * + * @param object The object pointer to invoke the member function on (i.e. the this pointer) + * @param function The address of the member function to attach + */ + template + void attach(T *object, R (T::*method)(A1, A2, A3)) { + _object = static_cast(object); + memcpy(&_function, &method, sizeof method); + _thunk = &FuncPtr::methodthunk; + } + + /** Attach a function object + * + * @param object Pointer to a function object to attach + */ + template + void attach(T *object) { + attach(object, &T::operator()); + } + + /** Attach a FuncPtr + * + * @param func The func to attach + */ + void attach(const FuncPtr &func) { + _object = func._object; + memcpy(&_function, &func._function, sizeof _function); + _thunk = func._thunk; + } + + /** Call the attached static or member function + */ + R call(A1 a1, A2 a2, A3 a3) { + return _thunk(_object, _function, a1, a2, a3); + } + + /** Get registered static function + */ + R (*get_function(A1, A2, A3))() { + return reinterpret_cast(_object ? 0 : _function); + } + +#ifdef MBED_OPERATORS + R operator ()(A1 a1, A2 a2, A3 a3) { + return call(a1, a2, a3); + } + operator bool(void) const { + return static_cast(_function); + } +#endif +private: + // Static thunks for various function types + static R staticthunk(void*, void *func, A1 a1, A2 a2, A3 a3) { + R (*f)(A1, A2, A3) = *reinterpret_cast(func); + return f(a1, a2, a3); + } + + template + static R boundthunk(void *object, void *func, A1 a1, A2 a2, A3 a3) { + T *o = static_cast(object); + R (*f)(T*, A1, A2, A3) = *reinterpret_cast(func); + return f(o, a1); + } + + template + static R methodthunk(void *object, void *member, A1 a1, A2 a2, A3 a3) { + T* o = static_cast(object); + R (T::*m)(A1, A2, A3) = *reinterpret_cast(member); + return (o->*m)(a1, a2, a3); + } + + // Forward declaration of an unknown class + // this kind of declaration is authorized by the standard (see 8.3.3/2 of C++ 03 standard). + // As a result, the compiler will allocate for UnknownFunctionMember_t the biggest size + // and biggest alignment possible for member function. + // This type can be used inside unions, it will help to provide the storage + // with the proper size and alignment guarantees + class UnknownClass; + + // object this pointer + void *_object; + + // aligned raw member function pointer storage - converted back by registered thunk + char _function[sizeof(void (UnknownClass::*)())]; + + // registered function to convert back and call _m.member on _object + R (*_thunk)(void*, void*, A1, A2, A3); +}; + +/** A class for storing and calling a pointer to a static or member function + */ +template +class FuncPtr { +public: + /** Create a FuncPtr, attaching a static function + * + * @param function The static function to attach (default is none) + */ + FuncPtr(R (*function)(A1, A2) = 0) { + attach(function); + } + + /** Create a FuncPtr, attaching a static function with bound pointer + * + * @param object Pointer to object to bind to function + * @param function The static function to attach + */ + template + FuncPtr(T *object, R (*function)(T*, A1, A2)) { + attach(object, function); + } + + /** Create a FuncPtr, attaching a member function + * + * @param object The object pointer to invoke the member function on (i.e. the this pointer) + * @param function The address of the member function to attach + */ + template + FuncPtr(T *object, R (T::*member)(A1, A2)) { + attach(object, member); + } + + /** Create a FuncPtr, attaching a function object + * + * @param object Pointer to a function object to attach + */ + template + FuncPtr(T *object) { + attach(object, &T::operator()); + } + + /** Create a FuncPtr from another FuncPtr + * + * @param func The func to attach + */ + FuncPtr(const FuncPtr &func) { + attach(func); + } + + /** Attach a static function + * + * @param function The static function to attach (default is none) + */ + void attach(R (*function)(A1, A2)) { + _object = 0; + memcpy(&_function, &function, sizeof function); + _thunk = &FuncPtr::staticthunk; + } + + /** Attach a static function with bound pointer + * + * @param object Pointer to object to bind to function + * @param function The static function to attach + */ + template + void attach(T *object, R (*function)(T*, A1, A2)) { + _object = static_cast(object); + memcpy(&_function, &function, sizeof function); + _thunk = &FuncPtr::boundthunk; + } + + /** Attach a member function + * + * @param object The object pointer to invoke the member function on (i.e. the this pointer) + * @param function The address of the member function to attach + */ + template + void attach(T *object, R (T::*method)(A1, A2)) { + _object = static_cast(object); + memcpy(&_function, &method, sizeof method); + _thunk = &FuncPtr::methodthunk; + } + + /** Attach a function object + * + * @param object Pointer to a function object to attach + */ + template + void attach(T *object) { + attach(object, &T::operator()); + } + + /** Attach a FuncPtr + * + * @param func The func to attach + */ + void attach(const FuncPtr &func) { + _object = func._object; + memcpy(&_function, &func._function, sizeof _function); + _thunk = func._thunk; + } + + /** Call the attached static or member function + */ + R call(A1 a1, A2 a2) { + return _thunk(_object, _function, a1, a2); + } + + /** Get registered static function + */ + R (*get_function(A1, A2))() { + return reinterpret_cast(_object ? 0 : _function); + } + +#ifdef MBED_OPERATORS + R operator ()(A1 a1, A2 a2) { + return call(a1, a2); + } + operator bool(void) const { + return static_cast(_function); + } +#endif +private: + // Static thunks for various function types + static R staticthunk(void*, void *func, A1 a1, A2 a2) { + R (*f)(A1, A2) = *reinterpret_cast(func); + return f(a1, a2); + } + + template + static R boundthunk(void *object, void *func, A1 a1, A2 a2) { + T *o = static_cast(object); + R (*f)(T*, A1, A2) = *reinterpret_cast(func); + return f(o, a1); + } + + template + static R methodthunk(void *object, void *member, A1 a1, A2 a2) { + T* o = static_cast(object); + R (T::*m)(A1, A2) = *reinterpret_cast(member); + return (o->*m)(a1, a2); + } + + // Forward declaration of an unknown class + // this kind of declaration is authorized by the standard (see 8.3.3/2 of C++ 03 standard). + // As a result, the compiler will allocate for UnknownFunctionMember_t the biggest size + // and biggest alignment possible for member function. + // This type can be used inside unions, it will help to provide the storage + // with the proper size and alignment guarantees + class UnknownClass; + + // object this pointer + void *_object; + + // aligned raw member function pointer storage - converted back by registered thunk + char _function[sizeof(void (UnknownClass::*)())]; + + // registered function to convert back and call _m.member on _object + R (*_thunk)(void*, void*, A1, A2); +}; + +/** A class for storing and calling a pointer to a static or member function + */ +template +class FuncPtr { +public: + /** Create a FuncPtr, attaching a static function + * + * @param function The static function to attach (default is none) + */ + FuncPtr(R (*function)(A1) = 0) { + attach(function); + } + + /** Create a FuncPtr, attaching a static function with bound pointer + * + * @param object Pointer to object to bind to function + * @param function The static function to attach + */ + template + FuncPtr(T *object, R (*function)(T*, A1)) { + attach(object, function); + } + + /** Create a FuncPtr, attaching a member function + * + * @param object The object pointer to invoke the member function on (i.e. the this pointer) + * @param function The address of the member function to attach + */ + template + FuncPtr(T *object, R (T::*member)(A1)) { + attach(object, member); + } + + /** Create a FuncPtr, attaching a function object + * + * @param object Pointer to a function object to attach + */ + template + FuncPtr(T *object) { + attach(object, &T::operator()); + } + + /** Create a FuncPtr from another FuncPtr + * + * @param func The func to attach + */ + FuncPtr(const FuncPtr &func) { + attach(func); + } + /** Attach a static function * * @param function The static function to attach (default is none) */ void attach(R (*function)(A1)) { - _p.function = function; - _membercaller = 0; + _object = 0; + memcpy(&_function, &function, sizeof function); + _thunk = &FuncPtr::staticthunk; + } + + /** Attach a static function with bound pointer + * + * @param object Pointer to object to bind to function + * @param function The static function to attach + */ + template + void attach(T *object, R (*function)(T*, A1)) { + _object = static_cast(object); + memcpy(&_function, &function, sizeof function); + _thunk = &FuncPtr::boundthunk; } /** Attach a member function @@ -61,141 +589,258 @@ public: * @param function The address of the member function to attach */ template - void attach(T *object, R (T::*member)(A1)) { - _p.object = static_cast(object); - *reinterpret_cast(_member) = member; - _membercaller = &FunctionPointerArg1::membercaller; + void attach(T *object, R (T::*method)(A1)) { + _object = static_cast(object); + memcpy(&_function, &method, sizeof method); + _thunk = &FuncPtr::methodthunk; + } + + /** Attach a function object + * + * @param object Pointer to a function object to attach + */ + template + void attach(T *object) { + attach(object, &T::operator()); + } + + /** Attach a FuncPtr + * + * @param func The func to attach + */ + void attach(const FuncPtr &func) { + _object = func._object; + memcpy(&_function, &func._function, sizeof _function); + _thunk = func._thunk; } /** Call the attached static or member function */ - R call(A1 a) { - if (_membercaller == 0 && _p.function) { - return _p.function(a); - } else if (_membercaller && _p.object) { - return _membercaller(_p.object, _member, a); - } - return (R)0; + R call(A1 a1) { + return _thunk(_object, _function, a1); } /** Get registered static function */ - R(*get_function(A1))() { - return _membercaller ? (R(*)(A1))0 : (R(*)(A1))_p.function; + R (*get_function(A1))() { + return reinterpret_cast(_object ? 0 : _function); } #ifdef MBED_OPERATORS - R operator ()(A1 a) { - return call(a); + R operator ()(A1 a1) { + return call(a1); } operator bool(void) const { - return (_membercaller != NULL ? _p.object : (void*)_p.function) != NULL; + return static_cast(_function); } #endif private: - template - static R membercaller(void *object, uintptr_t *member, A1 a) { - T* o = static_cast(object); - R (T::**m)(A1) = reinterpret_cast(member); - return (o->**m)(a); + // Static thunks for various function types + static R staticthunk(void*, void *func, A1 a1) { + R (*f)(A1) = *reinterpret_cast(func); + return f(a1); } - union { - R (*function)(A1); // static function pointer - void *object; // object this pointer - } _p; - uintptr_t _member[4]; // aligned raw member function pointer storage - converted back by registered _membercaller - R (*_membercaller)(void*, uintptr_t*, A1); // registered membercaller function to convert back and call _m.member on _object + template + static R boundthunk(void *object, void *func, A1 a1) { + T *o = static_cast(object); + R (*f)(T*, A1) = *reinterpret_cast(func); + return f(o, a1); + } + + template + static R methodthunk(void *object, void *member, A1 a1) { + T* o = static_cast(object); + R (T::*m)(A1) = *reinterpret_cast(member); + return (o->*m)(a1); + } + + // Forward declaration of an unknown class + // this kind of declaration is authorized by the standard (see 8.3.3/2 of C++ 03 standard). + // As a result, the compiler will allocate for UnknownFunctionMember_t the biggest size + // and biggest alignment possible for member function. + // This type can be used inside unions, it will help to provide the storage + // with the proper size and alignment guarantees + class UnknownClass; + + // object this pointer + void *_object; + + // aligned raw member function pointer storage - converted back by registered thunk + char _function[sizeof(void (UnknownClass::*)())]; + + // registered function to convert back and call _m.member on _object + R (*_thunk)(void*, void*, A1); }; -/** A class for storing and calling a pointer to a static or member function (R ()(void)) +/** A class for storing and calling a pointer to a static or member function */ template -class FunctionPointerArg1{ +class FuncPtr { public: - /** Create a FunctionPointer, attaching a static function + /** Create a FuncPtr, attaching a static function * * @param function The static function to attach (default is none) */ - FunctionPointerArg1(R (*function)(void) = 0) { + FuncPtr(R (*function)() = 0) { attach(function); } - /** Create a FunctionPointer, attaching a member function + /** Create a FuncPtr, attaching a static function with bound pointer * - * @param object The object pointer to invoke the member function on (i.e. the this pointer) - * @param function The address of the void member function to attach + * @param object Pointer to object to bind to function + * @param function The static function to attach */ template - FunctionPointerArg1(T *object, R (T::*member)(void)) { + FuncPtr(T *object, R (*function)(T*)) { + attach(object, function); + } + + /** Create a FuncPtr, attaching a member function + * + * @param object The object pointer to invoke the member function on (i.e. the this pointer) + * @param function The address of the member function to attach + */ + template + FuncPtr(T *object, R (T::*member)()) { attach(object, member); } + /** Create a FuncPtr, attaching a function object + * + * @param object Pointer to a function object to attach + */ + template + FuncPtr(T *object) { + attach(object, &T::operator()); + } + + /** Create a FuncPtr from another FuncPtr + * + * @param func The func to attach + */ + FuncPtr(const FuncPtr &func) { + attach(func); + } + /** Attach a static function * - * @param function The void static function to attach (default is none) + * @param function The static function to attach (default is none) */ - void attach(R (*function)(void)) { - _p.function = function; - _membercaller = 0; + void attach(R (*function)()) { + _object = 0; + memcpy(&_function, &function, sizeof function); + _thunk = &FuncPtr::staticthunk; + } + + /** Attach a static function with bound pointer + * + * @param object Pointer to object to bind to function + * @param function The static function to attach + */ + template + void attach(T *object, R (*function)(T*)) { + _object = static_cast(object); + memcpy(&_function, &function, sizeof function); + _thunk = &FuncPtr::boundthunk; } /** Attach a member function * * @param object The object pointer to invoke the member function on (i.e. the this pointer) - * @param function The address of the void member function to attach + * @param function The address of the member function to attach */ template - void attach(T *object, R (T::*member)(void)) { - _p.object = static_cast(object); - *reinterpret_cast(_member) = member; - _membercaller = &FunctionPointerArg1::membercaller; + void attach(T *object, R (T::*method)()) { + _object = static_cast(object); + memcpy(&_function, &method, sizeof method); + _thunk = &FuncPtr::methodthunk; + } + + /** Attach a function object + * + * @param object Pointer to a function object to attach + */ + template + void attach(T *object) { + attach(object, &T::operator()); + } + + /** Attach a FuncPtr + * + * @param func The func to attach + */ + void attach(const FuncPtr &func) { + _object = func._object; + memcpy(&_function, &func._function, sizeof _function); + _thunk = func._thunk; } /** Call the attached static or member function */ - R call(){ - if (_membercaller == 0 && _p.function) { - return _p.function(); - } else if (_membercaller && _p.object) { - return _membercaller(_p.object, _member); - } - return (R)0; + R call() { + return _thunk(_object, _function); } /** Get registered static function */ - R(*get_function())() { - return _membercaller ? (R(*)())0 : (R(*)())_p.function; + R (*get_function())() { + return reinterpret_cast(_object ? 0 : _function); } #ifdef MBED_OPERATORS - R operator ()(void) { + R operator ()() { return call(); } operator bool(void) const { - return (_membercaller != NULL ? _p.object : (void*)_p.function) != NULL; + return static_cast(_function); } #endif - private: - template - static R membercaller(void *object, uintptr_t *member) { - T* o = static_cast(object); - R (T::**m)(void) = reinterpret_cast(member); - return (o->**m)(); + // Static thunks for various function types + static R staticthunk(void*, void *func) { + R (*f)() = *reinterpret_cast(func); + return f(); } + template + static R boundthunk(void *object, void *func) { + T *o = static_cast(object); + R (*f)(T*) = *reinterpret_cast(func); + return f(o); + } + + template + static R methodthunk(void *object, void *member) { + T* o = static_cast(object); + R (T::*m)() = *reinterpret_cast(member); + return (o->*m)(); + } + + // Forward declaration of an unknown class + // this kind of declaration is authorized by the standard (see 8.3.3/2 of C++ 03 standard). + // As a result, the compiler will allocate for UnknownFunctionMember_t the biggest size + // and biggest alignment possible for member function. + // This type can be used inside unions, it will help to provide the storage + // with the proper size and alignment guarantees + class UnknownClass; + + // object this pointer + void *_object; + + // aligned raw member function pointer storage - converted back by registered thunk union { - R (*function)(void); // static function pointer - void *object; // object this pointer - } _p; - uintptr_t _member[4]; // aligned raw member function pointer storage - converted back by registered _membercaller - R (*_membercaller)(void*, uintptr_t*); // registered membercaller function to convert back and call _m.member on _object + char _function[sizeof(void (UnknownClass::*)())]; + void (UnknownClass::*_unknownMethod)(); + }; + + // registered function to convert back and call _m.member on _object + R (*_thunk)(void*, void*); }; -typedef FunctionPointerArg1 FunctionPointer; -typedef FunctionPointerArg1 event_callback_t; +// Overloads for backwards compatibility +typedef FuncPtr FunctionPointer; +typedef FuncPtr event_callback_t; } // namespace mbed