From 804a6212313ca0f7cdafc68e1812780e329ae710 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 27 Sep 2016 13:27:17 -0500 Subject: [PATCH] callback - Moved internal dispatch mechanism to generated op-table This allows additional attributes to be attached to the internally generated type such as move and destructor operations with no increase in RAM footprint. The current overloads can't take advantage of this, but it does open the possibility for more powerful overloads that can provide these additional attributes. Changes to mbed-os memory consumption: .text .data .bss before 57887 2292 7692 after 57842 2292 7691 --- hal/api/Callback.h | 2607 +++++++++++++++++--------------------------- 1 file changed, 989 insertions(+), 1618 deletions(-) diff --git a/hal/api/Callback.h b/hal/api/Callback.h index 6b1158d4e0..f8089ed70a 100644 --- a/hal/api/Callback.h +++ b/hal/api/Callback.h @@ -18,6 +18,7 @@ #include #include +#include #include "mbed_assert.h" #include "toolchain.h" @@ -42,7 +43,21 @@ public: * @param func Static function to attach */ Callback(R (*func)() = 0) { - attach(func); + if (!func) { + _ops = 0; + } else { + generate(func); + } + } + + /** Attach a Callback + * @param func The Callback to attach + */ + Callback(const Callback &func) { + if (func._ops) { + func._ops->move(this, &func); + } + _ops = func._ops; } /** Create a Callback with a member function @@ -51,7 +66,7 @@ public: */ template Callback(T *obj, R (T::*method)()) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -60,7 +75,7 @@ public: */ template Callback(const T *obj, R (T::*method)() const) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -69,7 +84,7 @@ public: */ template Callback(volatile T *obj, R (T::*method)() volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -78,7 +93,7 @@ public: */ template Callback(const volatile T *obj, R (T::*method)() const volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a static function and bound pointer @@ -86,7 +101,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(void*), void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -94,7 +109,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const void*), const void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -102,7 +117,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(volatile void*), volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -110,7 +125,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const volatile void*), const volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -119,7 +134,7 @@ public: */ template Callback(R (*func)(T*), T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -128,7 +143,7 @@ public: */ template Callback(R (*func)(const T*), const T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -137,7 +152,7 @@ public: */ template Callback(R (*func)(volatile T*), volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -146,7 +161,7 @@ public: */ template Callback(R (*func)(const volatile T*), const volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -158,7 +173,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(void *obj, R (*func)(void*)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -170,7 +185,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const void *obj, R (*func)(const void*)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -182,7 +197,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile void *obj, R (*func)(volatile void*)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -194,7 +209,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile void *obj, R (*func)(const volatile void*)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -207,7 +222,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(T *obj, R (*func)(T*)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -220,7 +235,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const T *obj, R (*func)(const T*)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -233,7 +248,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile T *obj, R (*func)(volatile T*)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -246,34 +261,31 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile T *obj, R (*func)(const volatile T*)) { - attach(func, obj); + new (this) Callback(func, obj); + } + + /** Destroy a callback + */ + ~Callback() { + if (_ops) { + _ops->dtor(this); + } } /** Attach a static function * @param func Static function to attach */ void attach(R (*func)()) { - struct local { - static R _thunk(void*, const void *func) { - return (*static_cast(func))( - ); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = 0; - _thunk = func ? &local::_thunk : 0; + this->~Callback(); + new (this) Callback(func); } /** Attach a Callback * @param func The Callback to attach */ void attach(const Callback &func) { - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func._func, sizeof func); - _obj = func._obj; - _thunk = func._thunk; + this->~Callback(); + new (this) Callback(func); } /** Attach a member function @@ -282,18 +294,8 @@ public: */ template void attach(T *obj, R (T::*method)()) { - struct local { - static R _thunk(void *obj, const void *method) { - return (((T*)obj)->* - (*static_cast(method)))( - ); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -302,18 +304,8 @@ public: */ template void attach(const T *obj, R (T::*method)() const) { - struct local { - static R _thunk(void *obj, const void *method) { - return (((const T*)obj)->* - (*static_cast(method)))( - ); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -322,18 +314,8 @@ public: */ template void attach(volatile T *obj, R (T::*method)() volatile) { - struct local { - static R _thunk(void *obj, const void *method) { - return (((volatile T*)obj)->* - (*static_cast(method)))( - ); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -342,18 +324,8 @@ public: */ template void attach(const volatile T *obj, R (T::*method)() const volatile) { - struct local { - static R _thunk(void *obj, const void *method) { - return (((const volatile T*)obj)->* - (*static_cast(method)))( - ); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a static function with a bound pointer @@ -361,17 +333,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(void*), void *arg) { - struct local { - static R _thunk(void *arg, const void *func) { - return (*static_cast(func))( - (void*)arg); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -379,17 +342,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const void*), const void *arg) { - struct local { - static R _thunk(void *arg, const void *func) { - return (*static_cast(func))( - (const void*)arg); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -397,17 +351,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(volatile void*), volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func) { - return (*static_cast(func))( - (volatile void*)arg); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -415,17 +360,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const volatile void*), const volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func) { - return (*static_cast(func))( - (const volatile void*)arg); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -434,17 +370,8 @@ public: */ template void attach(R (*func)(T*), T *arg) { - struct local { - static R _thunk(void *arg, const void *func) { - return (*static_cast(func))( - (T*)arg); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -453,17 +380,8 @@ public: */ template void attach(R (*func)(const T*), const T *arg) { - struct local { - static R _thunk(void *arg, const void *func) { - return (*static_cast(func))( - (const T*)arg); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -472,17 +390,8 @@ public: */ template void attach(R (*func)(volatile T*), volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func) { - return (*static_cast(func))( - (volatile T*)arg); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -491,17 +400,8 @@ public: */ template void attach(R (*func)(const volatile T*), const volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func) { - return (*static_cast(func))( - (const volatile T*)arg); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -513,17 +413,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(void *obj, R (*func)(void*)) { - struct local { - static R _thunk(void *obj, const void *func) { - return (*static_cast(func))( - (void*)obj); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -535,17 +426,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const void *obj, R (*func)(const void*)) { - struct local { - static R _thunk(void *obj, const void *func) { - return (*static_cast(func))( - (const void*)obj); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -557,17 +439,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile void *obj, R (*func)(volatile void*)) { - struct local { - static R _thunk(void *obj, const void *func) { - return (*static_cast(func))( - (volatile void*)obj); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -579,17 +452,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile void *obj, R (*func)(const volatile void*)) { - struct local { - static R _thunk(void *obj, const void *func) { - return (*static_cast(func))( - (const volatile void*)obj); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -602,17 +466,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(T *obj, R (*func)(T*)) { - struct local { - static R _thunk(void *obj, const void *func) { - return (*static_cast(func))( - (T*)obj); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -625,17 +480,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const T *obj, R (*func)(const T*)) { - struct local { - static R _thunk(void *obj, const void *func) { - return (*static_cast(func))( - (const T*)obj); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -648,17 +494,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile T *obj, R (*func)(volatile T*)) { - struct local { - static R _thunk(void *obj, const void *func) { - return (*static_cast(func))( - (volatile T*)obj); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -671,24 +508,26 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile T *obj, R (*func)(const volatile T*)) { - struct local { - static R _thunk(void *obj, const void *func) { - return (*static_cast(func))( - (const volatile T*)obj); - } - }; + this->~Callback(); + new (this) Callback(func, obj); + } - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + /** Assign a callback + */ + Callback &operator=(const Callback &that) { + if (this != &that) { + this->~Callback(); + new (this) Callback(that); + } + + return *this; } /** Call the attached function */ R call() const { - MBED_ASSERT(_thunk); - return _thunk(_obj, &_func); + MBED_ASSERT(_ops); + return _ops->call(this); } /** Call the attached function @@ -700,7 +539,7 @@ public: /** Test if function has been attached */ operator bool() const { - return _thunk; + return _ops; } /** Test for equality @@ -719,8 +558,7 @@ public: * @param func Callback to call passed as void pointer */ static R thunk(void *func) { - return static_cast*>(func)->call( - ); + return static_cast(func)->call(); } private: @@ -730,14 +568,72 @@ private: struct _class; union { void (*_staticfunc)(); - void (*_boundfunc)(_class *); + void (*_boundfunc)(_class*); void (_class::*_methodfunc)(); } _func; - void *_obj; - // Thunk registered on attach to dispatch calls - R (*_thunk)(void*, const void*); + // Dynamically dispatched operations + const struct ops { + R (*call)(const void*); + void (*move)(void*, const void*); + void (*dtor)(void*); + } *_ops; + + // Generate operations for function object + template + void generate(const F &f) { + struct local { + static R call(const void *p) { + return (*(F*)p)(); + } + + static void move(void *d, const void *p) { + new (d) F(*(F*)p); + } + + static void dtor(void *p) { + ((F*)p)->~F(); + } + }; + + static const ops ops = { + &local::call, + &local::move, + &local::dtor, + }; + + MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F)); + new (this) F(f); + _ops = &ops; + } + + // Wrappers for functions with context + template + struct method_context { + M method; + O *obj; + + method_context(O *obj, M method) + : method(method), obj(obj) {} + + R operator()() const { + return (obj->*method)(); + } + }; + + template + struct function_context { + F func; + A *arg; + + function_context(F func, A *arg) + : func(func), arg(arg) {} + + R operator()() const { + return func(arg); + } + }; }; /** Callback class based on template specialization @@ -751,7 +647,21 @@ public: * @param func Static function to attach */ Callback(R (*func)(A0) = 0) { - attach(func); + if (!func) { + _ops = 0; + } else { + generate(func); + } + } + + /** Attach a Callback + * @param func The Callback to attach + */ + Callback(const Callback &func) { + if (func._ops) { + func._ops->move(this, &func); + } + _ops = func._ops; } /** Create a Callback with a member function @@ -760,7 +670,7 @@ public: */ template Callback(T *obj, R (T::*method)(A0)) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -769,7 +679,7 @@ public: */ template Callback(const T *obj, R (T::*method)(A0) const) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -778,7 +688,7 @@ public: */ template Callback(volatile T *obj, R (T::*method)(A0) volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -787,7 +697,7 @@ public: */ template Callback(const volatile T *obj, R (T::*method)(A0) const volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a static function and bound pointer @@ -795,7 +705,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(void*, A0), void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -803,7 +713,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const void*, A0), const void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -811,7 +721,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(volatile void*, A0), volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -819,7 +729,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const volatile void*, A0), const volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -828,7 +738,7 @@ public: */ template Callback(R (*func)(T*, A0), T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -837,7 +747,7 @@ public: */ template Callback(R (*func)(const T*, A0), const T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -846,7 +756,7 @@ public: */ template Callback(R (*func)(volatile T*, A0), volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -855,7 +765,7 @@ public: */ template Callback(R (*func)(const volatile T*, A0), const volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -867,7 +777,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(void *obj, R (*func)(void*, A0)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -879,7 +789,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const void *obj, R (*func)(const void*, A0)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -891,7 +801,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile void *obj, R (*func)(volatile void*, A0)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -903,7 +813,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile void *obj, R (*func)(const volatile void*, A0)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -916,7 +826,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(T *obj, R (*func)(T*, A0)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -929,7 +839,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const T *obj, R (*func)(const T*, A0)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -942,7 +852,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile T *obj, R (*func)(volatile T*, A0)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -955,34 +865,31 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile T *obj, R (*func)(const volatile T*, A0)) { - attach(func, obj); + new (this) Callback(func, obj); + } + + /** Destroy a callback + */ + ~Callback() { + if (_ops) { + _ops->dtor(this); + } } /** Attach a static function * @param func Static function to attach */ void attach(R (*func)(A0)) { - struct local { - static R _thunk(void*, const void *func, A0 a0) { - return (*static_cast(func))( - a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = 0; - _thunk = func ? &local::_thunk : 0; + this->~Callback(); + new (this) Callback(func); } /** Attach a Callback * @param func The Callback to attach */ void attach(const Callback &func) { - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func._func, sizeof func); - _obj = func._obj; - _thunk = func._thunk; + this->~Callback(); + new (this) Callback(func); } /** Attach a member function @@ -991,18 +898,8 @@ public: */ template void attach(T *obj, R (T::*method)(A0)) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0) { - return (((T*)obj)->* - (*static_cast(method)))( - a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -1011,18 +908,8 @@ public: */ template void attach(const T *obj, R (T::*method)(A0) const) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0) { - return (((const T*)obj)->* - (*static_cast(method)))( - a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -1031,18 +918,8 @@ public: */ template void attach(volatile T *obj, R (T::*method)(A0) volatile) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0) { - return (((volatile T*)obj)->* - (*static_cast(method)))( - a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -1051,18 +928,8 @@ public: */ template void attach(const volatile T *obj, R (T::*method)(A0) const volatile) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0) { - return (((const volatile T*)obj)->* - (*static_cast(method)))( - a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a static function with a bound pointer @@ -1070,17 +937,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(void*, A0), void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0) { - return (*static_cast(func))( - (void*)arg, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1088,17 +946,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const void*, A0), const void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0) { - return (*static_cast(func))( - (const void*)arg, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1106,17 +955,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(volatile void*, A0), volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0) { - return (*static_cast(func))( - (volatile void*)arg, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1124,17 +964,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const volatile void*, A0), const volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0) { - return (*static_cast(func))( - (const volatile void*)arg, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1143,17 +974,8 @@ public: */ template void attach(R (*func)(T*, A0), T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0) { - return (*static_cast(func))( - (T*)arg, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1162,17 +984,8 @@ public: */ template void attach(R (*func)(const T*, A0), const T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0) { - return (*static_cast(func))( - (const T*)arg, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1181,17 +994,8 @@ public: */ template void attach(R (*func)(volatile T*, A0), volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0) { - return (*static_cast(func))( - (volatile T*)arg, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1200,17 +1004,8 @@ public: */ template void attach(R (*func)(const volatile T*, A0), const volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0) { - return (*static_cast(func))( - (const volatile T*)arg, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1222,17 +1017,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(void *obj, R (*func)(void*, A0)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0) { - return (*static_cast(func))( - (void*)obj, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -1244,17 +1030,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const void *obj, R (*func)(const void*, A0)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0) { - return (*static_cast(func))( - (const void*)obj, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -1266,17 +1043,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile void *obj, R (*func)(volatile void*, A0)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0) { - return (*static_cast(func))( - (volatile void*)obj, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -1288,17 +1056,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile void *obj, R (*func)(const volatile void*, A0)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0) { - return (*static_cast(func))( - (const volatile void*)obj, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -1311,17 +1070,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(T *obj, R (*func)(T*, A0)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0) { - return (*static_cast(func))( - (T*)obj, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -1334,17 +1084,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const T *obj, R (*func)(const T*, A0)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0) { - return (*static_cast(func))( - (const T*)obj, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -1357,17 +1098,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile T *obj, R (*func)(volatile T*, A0)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0) { - return (*static_cast(func))( - (volatile T*)obj, a0); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -1380,24 +1112,26 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile T *obj, R (*func)(const volatile T*, A0)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0) { - return (*static_cast(func))( - (const volatile T*)obj, a0); - } - }; + this->~Callback(); + new (this) Callback(func, obj); + } - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + /** Assign a callback + */ + Callback &operator=(const Callback &that) { + if (this != &that) { + this->~Callback(); + new (this) Callback(that); + } + + return *this; } /** Call the attached function */ R call(A0 a0) const { - MBED_ASSERT(_thunk); - return _thunk(_obj, &_func, a0); + MBED_ASSERT(_ops); + return _ops->call(this, a0); } /** Call the attached function @@ -1409,7 +1143,7 @@ public: /** Test if function has been attached */ operator bool() const { - return _thunk; + return _ops; } /** Test for equality @@ -1428,8 +1162,7 @@ public: * @param func Callback to call passed as void pointer */ static R thunk(void *func, A0 a0) { - return static_cast*>(func)->call( - a0); + return static_cast(func)->call(a0); } private: @@ -1438,15 +1171,73 @@ private: // to garuntee proper size and alignment struct _class; union { - void (*_staticfunc)(); - void (*_boundfunc)(_class *); - void (_class::*_methodfunc)(); + void (*_staticfunc)(A0); + void (*_boundfunc)(_class*, A0); + void (_class::*_methodfunc)(A0); } _func; - void *_obj; - // Thunk registered on attach to dispatch calls - R (*_thunk)(void*, const void*, A0); + // Dynamically dispatched operations + const struct ops { + R (*call)(const void*, A0); + void (*move)(void*, const void*); + void (*dtor)(void*); + } *_ops; + + // Generate operations for function object + template + void generate(const F &f) { + struct local { + static R call(const void *p, A0 a0) { + return (*(F*)p)(a0); + } + + static void move(void *d, const void *p) { + new (d) F(*(F*)p); + } + + static void dtor(void *p) { + ((F*)p)->~F(); + } + }; + + static const ops ops = { + &local::call, + &local::move, + &local::dtor, + }; + + MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F)); + new (this) F(f); + _ops = &ops; + } + + // Wrappers for functions with context + template + struct method_context { + M method; + O *obj; + + method_context(O *obj, M method) + : method(method), obj(obj) {} + + R operator()(A0 a0) const { + return (obj->*method)(a0); + } + }; + + template + struct function_context { + F func; + A *arg; + + function_context(F func, A *arg) + : func(func), arg(arg) {} + + R operator()(A0 a0) const { + return func(arg, a0); + } + }; }; /** Callback class based on template specialization @@ -1460,7 +1251,21 @@ public: * @param func Static function to attach */ Callback(R (*func)(A0, A1) = 0) { - attach(func); + if (!func) { + _ops = 0; + } else { + generate(func); + } + } + + /** Attach a Callback + * @param func The Callback to attach + */ + Callback(const Callback &func) { + if (func._ops) { + func._ops->move(this, &func); + } + _ops = func._ops; } /** Create a Callback with a member function @@ -1469,7 +1274,7 @@ public: */ template Callback(T *obj, R (T::*method)(A0, A1)) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -1478,7 +1283,7 @@ public: */ template Callback(const T *obj, R (T::*method)(A0, A1) const) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -1487,7 +1292,7 @@ public: */ template Callback(volatile T *obj, R (T::*method)(A0, A1) volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -1496,7 +1301,7 @@ public: */ template Callback(const volatile T *obj, R (T::*method)(A0, A1) const volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a static function and bound pointer @@ -1504,7 +1309,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(void*, A0, A1), void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -1512,7 +1317,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const void*, A0, A1), const void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -1520,7 +1325,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(volatile void*, A0, A1), volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -1528,7 +1333,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const volatile void*, A0, A1), const volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -1537,7 +1342,7 @@ public: */ template Callback(R (*func)(T*, A0, A1), T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -1546,7 +1351,7 @@ public: */ template Callback(R (*func)(const T*, A0, A1), const T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -1555,7 +1360,7 @@ public: */ template Callback(R (*func)(volatile T*, A0, A1), volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -1564,7 +1369,7 @@ public: */ template Callback(R (*func)(const volatile T*, A0, A1), const volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -1576,7 +1381,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(void *obj, R (*func)(void*, A0, A1)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -1588,7 +1393,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const void *obj, R (*func)(const void*, A0, A1)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -1600,7 +1405,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile void *obj, R (*func)(volatile void*, A0, A1)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -1612,7 +1417,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile void *obj, R (*func)(const volatile void*, A0, A1)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -1625,7 +1430,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(T *obj, R (*func)(T*, A0, A1)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -1638,7 +1443,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const T *obj, R (*func)(const T*, A0, A1)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -1651,7 +1456,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile T *obj, R (*func)(volatile T*, A0, A1)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -1664,34 +1469,31 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile T *obj, R (*func)(const volatile T*, A0, A1)) { - attach(func, obj); + new (this) Callback(func, obj); + } + + /** Destroy a callback + */ + ~Callback() { + if (_ops) { + _ops->dtor(this); + } } /** Attach a static function * @param func Static function to attach */ void attach(R (*func)(A0, A1)) { - struct local { - static R _thunk(void*, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = 0; - _thunk = func ? &local::_thunk : 0; + this->~Callback(); + new (this) Callback(func); } /** Attach a Callback * @param func The Callback to attach */ void attach(const Callback &func) { - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func._func, sizeof func); - _obj = func._obj; - _thunk = func._thunk; + this->~Callback(); + new (this) Callback(func); } /** Attach a member function @@ -1700,18 +1502,8 @@ public: */ template void attach(T *obj, R (T::*method)(A0, A1)) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1) { - return (((T*)obj)->* - (*static_cast(method)))( - a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -1720,18 +1512,8 @@ public: */ template void attach(const T *obj, R (T::*method)(A0, A1) const) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1) { - return (((const T*)obj)->* - (*static_cast(method)))( - a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -1740,18 +1522,8 @@ public: */ template void attach(volatile T *obj, R (T::*method)(A0, A1) volatile) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1) { - return (((volatile T*)obj)->* - (*static_cast(method)))( - a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -1760,18 +1532,8 @@ public: */ template void attach(const volatile T *obj, R (T::*method)(A0, A1) const volatile) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1) { - return (((const volatile T*)obj)->* - (*static_cast(method)))( - a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a static function with a bound pointer @@ -1779,17 +1541,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(void*, A0, A1), void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (void*)arg, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1797,17 +1550,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const void*, A0, A1), const void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (const void*)arg, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1815,17 +1559,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(volatile void*, A0, A1), volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (volatile void*)arg, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1833,17 +1568,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const volatile void*, A0, A1), const volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (const volatile void*)arg, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1852,17 +1578,8 @@ public: */ template void attach(R (*func)(T*, A0, A1), T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (T*)arg, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1871,17 +1588,8 @@ public: */ template void attach(R (*func)(const T*, A0, A1), const T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (const T*)arg, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1890,17 +1598,8 @@ public: */ template void attach(R (*func)(volatile T*, A0, A1), volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (volatile T*)arg, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1909,17 +1608,8 @@ public: */ template void attach(R (*func)(const volatile T*, A0, A1), const volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (const volatile T*)arg, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -1931,17 +1621,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(void *obj, R (*func)(void*, A0, A1)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (void*)obj, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -1953,17 +1634,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const void *obj, R (*func)(const void*, A0, A1)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (const void*)obj, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -1975,17 +1647,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile void *obj, R (*func)(volatile void*, A0, A1)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (volatile void*)obj, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -1997,17 +1660,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile void *obj, R (*func)(const volatile void*, A0, A1)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (const volatile void*)obj, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -2020,17 +1674,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(T *obj, R (*func)(T*, A0, A1)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (T*)obj, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -2043,17 +1688,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const T *obj, R (*func)(const T*, A0, A1)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (const T*)obj, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -2066,17 +1702,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile T *obj, R (*func)(volatile T*, A0, A1)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (volatile T*)obj, a0, a1); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -2089,24 +1716,26 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile T *obj, R (*func)(const volatile T*, A0, A1)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1) { - return (*static_cast(func))( - (const volatile T*)obj, a0, a1); - } - }; + this->~Callback(); + new (this) Callback(func, obj); + } - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + /** Assign a callback + */ + Callback &operator=(const Callback &that) { + if (this != &that) { + this->~Callback(); + new (this) Callback(that); + } + + return *this; } /** Call the attached function */ R call(A0 a0, A1 a1) const { - MBED_ASSERT(_thunk); - return _thunk(_obj, &_func, a0, a1); + MBED_ASSERT(_ops); + return _ops->call(this, a0, a1); } /** Call the attached function @@ -2118,7 +1747,7 @@ public: /** Test if function has been attached */ operator bool() const { - return _thunk; + return _ops; } /** Test for equality @@ -2137,8 +1766,7 @@ public: * @param func Callback to call passed as void pointer */ static R thunk(void *func, A0 a0, A1 a1) { - return static_cast*>(func)->call( - a0, a1); + return static_cast(func)->call(a0, a1); } private: @@ -2147,15 +1775,73 @@ private: // to garuntee proper size and alignment struct _class; union { - void (*_staticfunc)(); - void (*_boundfunc)(_class *); - void (_class::*_methodfunc)(); + void (*_staticfunc)(A0, A1); + void (*_boundfunc)(_class*, A0, A1); + void (_class::*_methodfunc)(A0, A1); } _func; - void *_obj; - // Thunk registered on attach to dispatch calls - R (*_thunk)(void*, const void*, A0, A1); + // Dynamically dispatched operations + const struct ops { + R (*call)(const void*, A0, A1); + void (*move)(void*, const void*); + void (*dtor)(void*); + } *_ops; + + // Generate operations for function object + template + void generate(const F &f) { + struct local { + static R call(const void *p, A0 a0, A1 a1) { + return (*(F*)p)(a0, a1); + } + + static void move(void *d, const void *p) { + new (d) F(*(F*)p); + } + + static void dtor(void *p) { + ((F*)p)->~F(); + } + }; + + static const ops ops = { + &local::call, + &local::move, + &local::dtor, + }; + + MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F)); + new (this) F(f); + _ops = &ops; + } + + // Wrappers for functions with context + template + struct method_context { + M method; + O *obj; + + method_context(O *obj, M method) + : method(method), obj(obj) {} + + R operator()(A0 a0, A1 a1) const { + return (obj->*method)(a0, a1); + } + }; + + template + struct function_context { + F func; + A *arg; + + function_context(F func, A *arg) + : func(func), arg(arg) {} + + R operator()(A0 a0, A1 a1) const { + return func(arg, a0, a1); + } + }; }; /** Callback class based on template specialization @@ -2169,7 +1855,21 @@ public: * @param func Static function to attach */ Callback(R (*func)(A0, A1, A2) = 0) { - attach(func); + if (!func) { + _ops = 0; + } else { + generate(func); + } + } + + /** Attach a Callback + * @param func The Callback to attach + */ + Callback(const Callback &func) { + if (func._ops) { + func._ops->move(this, &func); + } + _ops = func._ops; } /** Create a Callback with a member function @@ -2178,7 +1878,7 @@ public: */ template Callback(T *obj, R (T::*method)(A0, A1, A2)) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -2187,7 +1887,7 @@ public: */ template Callback(const T *obj, R (T::*method)(A0, A1, A2) const) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -2196,7 +1896,7 @@ public: */ template Callback(volatile T *obj, R (T::*method)(A0, A1, A2) volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -2205,7 +1905,7 @@ public: */ template Callback(const volatile T *obj, R (T::*method)(A0, A1, A2) const volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a static function and bound pointer @@ -2213,7 +1913,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(void*, A0, A1, A2), void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2221,7 +1921,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const void*, A0, A1, A2), const void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2229,7 +1929,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(volatile void*, A0, A1, A2), volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2237,7 +1937,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const volatile void*, A0, A1, A2), const volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2246,7 +1946,7 @@ public: */ template Callback(R (*func)(T*, A0, A1, A2), T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2255,7 +1955,7 @@ public: */ template Callback(R (*func)(const T*, A0, A1, A2), const T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2264,7 +1964,7 @@ public: */ template Callback(R (*func)(volatile T*, A0, A1, A2), volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2273,7 +1973,7 @@ public: */ template Callback(R (*func)(const volatile T*, A0, A1, A2), const volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2285,7 +1985,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(void *obj, R (*func)(void*, A0, A1, A2)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -2297,7 +1997,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const void *obj, R (*func)(const void*, A0, A1, A2)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -2309,7 +2009,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile void *obj, R (*func)(volatile void*, A0, A1, A2)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -2321,7 +2021,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile void *obj, R (*func)(const volatile void*, A0, A1, A2)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -2334,7 +2034,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(T *obj, R (*func)(T*, A0, A1, A2)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -2347,7 +2047,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const T *obj, R (*func)(const T*, A0, A1, A2)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -2360,7 +2060,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile T *obj, R (*func)(volatile T*, A0, A1, A2)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -2373,34 +2073,31 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile T *obj, R (*func)(const volatile T*, A0, A1, A2)) { - attach(func, obj); + new (this) Callback(func, obj); + } + + /** Destroy a callback + */ + ~Callback() { + if (_ops) { + _ops->dtor(this); + } } /** Attach a static function * @param func Static function to attach */ void attach(R (*func)(A0, A1, A2)) { - struct local { - static R _thunk(void*, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = 0; - _thunk = func ? &local::_thunk : 0; + this->~Callback(); + new (this) Callback(func); } /** Attach a Callback * @param func The Callback to attach */ void attach(const Callback &func) { - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func._func, sizeof func); - _obj = func._obj; - _thunk = func._thunk; + this->~Callback(); + new (this) Callback(func); } /** Attach a member function @@ -2409,18 +2106,8 @@ public: */ template void attach(T *obj, R (T::*method)(A0, A1, A2)) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2) { - return (((T*)obj)->* - (*static_cast(method)))( - a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -2429,18 +2116,8 @@ public: */ template void attach(const T *obj, R (T::*method)(A0, A1, A2) const) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2) { - return (((const T*)obj)->* - (*static_cast(method)))( - a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -2449,18 +2126,8 @@ public: */ template void attach(volatile T *obj, R (T::*method)(A0, A1, A2) volatile) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2) { - return (((volatile T*)obj)->* - (*static_cast(method)))( - a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -2469,18 +2136,8 @@ public: */ template void attach(const volatile T *obj, R (T::*method)(A0, A1, A2) const volatile) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2) { - return (((const volatile T*)obj)->* - (*static_cast(method)))( - a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a static function with a bound pointer @@ -2488,17 +2145,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(void*, A0, A1, A2), void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (void*)arg, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -2506,17 +2154,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const void*, A0, A1, A2), const void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (const void*)arg, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -2524,17 +2163,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(volatile void*, A0, A1, A2), volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (volatile void*)arg, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -2542,17 +2172,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const volatile void*, A0, A1, A2), const volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (const volatile void*)arg, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -2561,17 +2182,8 @@ public: */ template void attach(R (*func)(T*, A0, A1, A2), T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (T*)arg, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -2580,17 +2192,8 @@ public: */ template void attach(R (*func)(const T*, A0, A1, A2), const T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (const T*)arg, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -2599,17 +2202,8 @@ public: */ template void attach(R (*func)(volatile T*, A0, A1, A2), volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (volatile T*)arg, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -2618,17 +2212,8 @@ public: */ template void attach(R (*func)(const volatile T*, A0, A1, A2), const volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (const volatile T*)arg, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -2640,17 +2225,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(void *obj, R (*func)(void*, A0, A1, A2)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (void*)obj, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -2662,17 +2238,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const void *obj, R (*func)(const void*, A0, A1, A2)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (const void*)obj, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -2684,17 +2251,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile void *obj, R (*func)(volatile void*, A0, A1, A2)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (volatile void*)obj, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -2706,17 +2264,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile void *obj, R (*func)(const volatile void*, A0, A1, A2)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (const volatile void*)obj, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -2729,17 +2278,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(T *obj, R (*func)(T*, A0, A1, A2)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (T*)obj, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -2752,17 +2292,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const T *obj, R (*func)(const T*, A0, A1, A2)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (const T*)obj, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -2775,17 +2306,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile T *obj, R (*func)(volatile T*, A0, A1, A2)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (volatile T*)obj, a0, a1, a2); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -2798,24 +2320,26 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile T *obj, R (*func)(const volatile T*, A0, A1, A2)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2) { - return (*static_cast(func))( - (const volatile T*)obj, a0, a1, a2); - } - }; + this->~Callback(); + new (this) Callback(func, obj); + } - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + /** Assign a callback + */ + Callback &operator=(const Callback &that) { + if (this != &that) { + this->~Callback(); + new (this) Callback(that); + } + + return *this; } /** Call the attached function */ R call(A0 a0, A1 a1, A2 a2) const { - MBED_ASSERT(_thunk); - return _thunk(_obj, &_func, a0, a1, a2); + MBED_ASSERT(_ops); + return _ops->call(this, a0, a1, a2); } /** Call the attached function @@ -2827,7 +2351,7 @@ public: /** Test if function has been attached */ operator bool() const { - return _thunk; + return _ops; } /** Test for equality @@ -2846,8 +2370,7 @@ public: * @param func Callback to call passed as void pointer */ static R thunk(void *func, A0 a0, A1 a1, A2 a2) { - return static_cast*>(func)->call( - a0, a1, a2); + return static_cast(func)->call(a0, a1, a2); } private: @@ -2856,15 +2379,73 @@ private: // to garuntee proper size and alignment struct _class; union { - void (*_staticfunc)(); - void (*_boundfunc)(_class *); - void (_class::*_methodfunc)(); + void (*_staticfunc)(A0, A1, A2); + void (*_boundfunc)(_class*, A0, A1, A2); + void (_class::*_methodfunc)(A0, A1, A2); } _func; - void *_obj; - // Thunk registered on attach to dispatch calls - R (*_thunk)(void*, const void*, A0, A1, A2); + // Dynamically dispatched operations + const struct ops { + R (*call)(const void*, A0, A1, A2); + void (*move)(void*, const void*); + void (*dtor)(void*); + } *_ops; + + // Generate operations for function object + template + void generate(const F &f) { + struct local { + static R call(const void *p, A0 a0, A1 a1, A2 a2) { + return (*(F*)p)(a0, a1, a2); + } + + static void move(void *d, const void *p) { + new (d) F(*(F*)p); + } + + static void dtor(void *p) { + ((F*)p)->~F(); + } + }; + + static const ops ops = { + &local::call, + &local::move, + &local::dtor, + }; + + MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F)); + new (this) F(f); + _ops = &ops; + } + + // Wrappers for functions with context + template + struct method_context { + M method; + O *obj; + + method_context(O *obj, M method) + : method(method), obj(obj) {} + + R operator()(A0 a0, A1 a1, A2 a2) const { + return (obj->*method)(a0, a1, a2); + } + }; + + template + struct function_context { + F func; + A *arg; + + function_context(F func, A *arg) + : func(func), arg(arg) {} + + R operator()(A0 a0, A1 a1, A2 a2) const { + return func(arg, a0, a1, a2); + } + }; }; /** Callback class based on template specialization @@ -2878,7 +2459,21 @@ public: * @param func Static function to attach */ Callback(R (*func)(A0, A1, A2, A3) = 0) { - attach(func); + if (!func) { + _ops = 0; + } else { + generate(func); + } + } + + /** Attach a Callback + * @param func The Callback to attach + */ + Callback(const Callback &func) { + if (func._ops) { + func._ops->move(this, &func); + } + _ops = func._ops; } /** Create a Callback with a member function @@ -2887,7 +2482,7 @@ public: */ template Callback(T *obj, R (T::*method)(A0, A1, A2, A3)) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -2896,7 +2491,7 @@ public: */ template Callback(const T *obj, R (T::*method)(A0, A1, A2, A3) const) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -2905,7 +2500,7 @@ public: */ template Callback(volatile T *obj, R (T::*method)(A0, A1, A2, A3) volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -2914,7 +2509,7 @@ public: */ template Callback(const volatile T *obj, R (T::*method)(A0, A1, A2, A3) const volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a static function and bound pointer @@ -2922,7 +2517,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(void*, A0, A1, A2, A3), void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2930,7 +2525,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const void*, A0, A1, A2, A3), const void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2938,7 +2533,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(volatile void*, A0, A1, A2, A3), volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2946,7 +2541,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const volatile void*, A0, A1, A2, A3), const volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2955,7 +2550,7 @@ public: */ template Callback(R (*func)(T*, A0, A1, A2, A3), T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2964,7 +2559,7 @@ public: */ template Callback(R (*func)(const T*, A0, A1, A2, A3), const T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2973,7 +2568,7 @@ public: */ template Callback(R (*func)(volatile T*, A0, A1, A2, A3), volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2982,7 +2577,7 @@ public: */ template Callback(R (*func)(const volatile T*, A0, A1, A2, A3), const volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -2994,7 +2589,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(void *obj, R (*func)(void*, A0, A1, A2, A3)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3006,7 +2601,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const void *obj, R (*func)(const void*, A0, A1, A2, A3)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3018,7 +2613,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile void *obj, R (*func)(volatile void*, A0, A1, A2, A3)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3030,7 +2625,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile void *obj, R (*func)(const volatile void*, A0, A1, A2, A3)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3043,7 +2638,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(T *obj, R (*func)(T*, A0, A1, A2, A3)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3056,7 +2651,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const T *obj, R (*func)(const T*, A0, A1, A2, A3)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3069,7 +2664,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile T *obj, R (*func)(volatile T*, A0, A1, A2, A3)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3082,34 +2677,31 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile T *obj, R (*func)(const volatile T*, A0, A1, A2, A3)) { - attach(func, obj); + new (this) Callback(func, obj); + } + + /** Destroy a callback + */ + ~Callback() { + if (_ops) { + _ops->dtor(this); + } } /** Attach a static function * @param func Static function to attach */ void attach(R (*func)(A0, A1, A2, A3)) { - struct local { - static R _thunk(void*, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = 0; - _thunk = func ? &local::_thunk : 0; + this->~Callback(); + new (this) Callback(func); } /** Attach a Callback * @param func The Callback to attach */ void attach(const Callback &func) { - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func._func, sizeof func); - _obj = func._obj; - _thunk = func._thunk; + this->~Callback(); + new (this) Callback(func); } /** Attach a member function @@ -3118,18 +2710,8 @@ public: */ template void attach(T *obj, R (T::*method)(A0, A1, A2, A3)) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2, A3 a3) { - return (((T*)obj)->* - (*static_cast(method)))( - a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -3138,18 +2720,8 @@ public: */ template void attach(const T *obj, R (T::*method)(A0, A1, A2, A3) const) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2, A3 a3) { - return (((const T*)obj)->* - (*static_cast(method)))( - a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -3158,18 +2730,8 @@ public: */ template void attach(volatile T *obj, R (T::*method)(A0, A1, A2, A3) volatile) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2, A3 a3) { - return (((volatile T*)obj)->* - (*static_cast(method)))( - a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -3178,18 +2740,8 @@ public: */ template void attach(const volatile T *obj, R (T::*method)(A0, A1, A2, A3) const volatile) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2, A3 a3) { - return (((const volatile T*)obj)->* - (*static_cast(method)))( - a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a static function with a bound pointer @@ -3197,17 +2749,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(void*, A0, A1, A2, A3), void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (void*)arg, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3215,17 +2758,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const void*, A0, A1, A2, A3), const void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (const void*)arg, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3233,17 +2767,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(volatile void*, A0, A1, A2, A3), volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (volatile void*)arg, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3251,17 +2776,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const volatile void*, A0, A1, A2, A3), const volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (const volatile void*)arg, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3270,17 +2786,8 @@ public: */ template void attach(R (*func)(T*, A0, A1, A2, A3), T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (T*)arg, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3289,17 +2796,8 @@ public: */ template void attach(R (*func)(const T*, A0, A1, A2, A3), const T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (const T*)arg, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3308,17 +2806,8 @@ public: */ template void attach(R (*func)(volatile T*, A0, A1, A2, A3), volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (volatile T*)arg, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3327,17 +2816,8 @@ public: */ template void attach(R (*func)(const volatile T*, A0, A1, A2, A3), const volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (const volatile T*)arg, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3349,17 +2829,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(void *obj, R (*func)(void*, A0, A1, A2, A3)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (void*)obj, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -3371,17 +2842,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const void *obj, R (*func)(const void*, A0, A1, A2, A3)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (const void*)obj, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -3393,17 +2855,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile void *obj, R (*func)(volatile void*, A0, A1, A2, A3)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (volatile void*)obj, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -3415,17 +2868,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile void *obj, R (*func)(const volatile void*, A0, A1, A2, A3)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (const volatile void*)obj, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -3438,17 +2882,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(T *obj, R (*func)(T*, A0, A1, A2, A3)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (T*)obj, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -3461,17 +2896,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const T *obj, R (*func)(const T*, A0, A1, A2, A3)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (const T*)obj, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -3484,17 +2910,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile T *obj, R (*func)(volatile T*, A0, A1, A2, A3)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (volatile T*)obj, a0, a1, a2, a3); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -3507,24 +2924,26 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile T *obj, R (*func)(const volatile T*, A0, A1, A2, A3)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return (*static_cast(func))( - (const volatile T*)obj, a0, a1, a2, a3); - } - }; + this->~Callback(); + new (this) Callback(func, obj); + } - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + /** Assign a callback + */ + Callback &operator=(const Callback &that) { + if (this != &that) { + this->~Callback(); + new (this) Callback(that); + } + + return *this; } /** Call the attached function */ R call(A0 a0, A1 a1, A2 a2, A3 a3) const { - MBED_ASSERT(_thunk); - return _thunk(_obj, &_func, a0, a1, a2, a3); + MBED_ASSERT(_ops); + return _ops->call(this, a0, a1, a2, a3); } /** Call the attached function @@ -3536,7 +2955,7 @@ public: /** Test if function has been attached */ operator bool() const { - return _thunk; + return _ops; } /** Test for equality @@ -3555,8 +2974,7 @@ public: * @param func Callback to call passed as void pointer */ static R thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3) { - return static_cast*>(func)->call( - a0, a1, a2, a3); + return static_cast(func)->call(a0, a1, a2, a3); } private: @@ -3565,15 +2983,73 @@ private: // to garuntee proper size and alignment struct _class; union { - void (*_staticfunc)(); - void (*_boundfunc)(_class *); - void (_class::*_methodfunc)(); + void (*_staticfunc)(A0, A1, A2, A3); + void (*_boundfunc)(_class*, A0, A1, A2, A3); + void (_class::*_methodfunc)(A0, A1, A2, A3); } _func; - void *_obj; - // Thunk registered on attach to dispatch calls - R (*_thunk)(void*, const void*, A0, A1, A2, A3); + // Dynamically dispatched operations + const struct ops { + R (*call)(const void*, A0, A1, A2, A3); + void (*move)(void*, const void*); + void (*dtor)(void*); + } *_ops; + + // Generate operations for function object + template + void generate(const F &f) { + struct local { + static R call(const void *p, A0 a0, A1 a1, A2 a2, A3 a3) { + return (*(F*)p)(a0, a1, a2, a3); + } + + static void move(void *d, const void *p) { + new (d) F(*(F*)p); + } + + static void dtor(void *p) { + ((F*)p)->~F(); + } + }; + + static const ops ops = { + &local::call, + &local::move, + &local::dtor, + }; + + MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F)); + new (this) F(f); + _ops = &ops; + } + + // Wrappers for functions with context + template + struct method_context { + M method; + O *obj; + + method_context(O *obj, M method) + : method(method), obj(obj) {} + + R operator()(A0 a0, A1 a1, A2 a2, A3 a3) const { + return (obj->*method)(a0, a1, a2, a3); + } + }; + + template + struct function_context { + F func; + A *arg; + + function_context(F func, A *arg) + : func(func), arg(arg) {} + + R operator()(A0 a0, A1 a1, A2 a2, A3 a3) const { + return func(arg, a0, a1, a2, a3); + } + }; }; /** Callback class based on template specialization @@ -3587,7 +3063,21 @@ public: * @param func Static function to attach */ Callback(R (*func)(A0, A1, A2, A3, A4) = 0) { - attach(func); + if (!func) { + _ops = 0; + } else { + generate(func); + } + } + + /** Attach a Callback + * @param func The Callback to attach + */ + Callback(const Callback &func) { + if (func._ops) { + func._ops->move(this, &func); + } + _ops = func._ops; } /** Create a Callback with a member function @@ -3596,7 +3086,7 @@ public: */ template Callback(T *obj, R (T::*method)(A0, A1, A2, A3, A4)) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -3605,7 +3095,7 @@ public: */ template Callback(const T *obj, R (T::*method)(A0, A1, A2, A3, A4) const) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -3614,7 +3104,7 @@ public: */ template Callback(volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a member function @@ -3623,7 +3113,7 @@ public: */ template Callback(const volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) const volatile) { - attach(obj, method); + generate(method_context(obj, method)); } /** Create a Callback with a static function and bound pointer @@ -3631,7 +3121,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(void*, A0, A1, A2, A3, A4), void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -3639,7 +3129,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const void*, A0, A1, A2, A3, A4), const void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -3647,7 +3137,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(volatile void*, A0, A1, A2, A3, A4), volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -3655,7 +3145,7 @@ public: * @param arg Pointer argument to function */ Callback(R (*func)(const volatile void*, A0, A1, A2, A3, A4), const volatile void *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -3664,7 +3154,7 @@ public: */ template Callback(R (*func)(T*, A0, A1, A2, A3, A4), T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -3673,7 +3163,7 @@ public: */ template Callback(R (*func)(const T*, A0, A1, A2, A3, A4), const T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -3682,7 +3172,7 @@ public: */ template Callback(R (*func)(volatile T*, A0, A1, A2, A3, A4), volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -3691,7 +3181,7 @@ public: */ template Callback(R (*func)(const volatile T*, A0, A1, A2, A3, A4), const volatile T *arg) { - attach(func, arg); + generate(function_context(func, arg)); } /** Create a Callback with a static function and bound pointer @@ -3703,7 +3193,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(void *obj, R (*func)(void*, A0, A1, A2, A3, A4)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3715,7 +3205,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const void *obj, R (*func)(const void*, A0, A1, A2, A3, A4)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3727,7 +3217,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile void *obj, R (*func)(volatile void*, A0, A1, A2, A3, A4)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3739,7 +3229,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile void *obj, R (*func)(const volatile void*, A0, A1, A2, A3, A4)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3752,7 +3242,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(T *obj, R (*func)(T*, A0, A1, A2, A3, A4)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3765,7 +3255,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const T *obj, R (*func)(const T*, A0, A1, A2, A3, A4)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3778,7 +3268,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(volatile T *obj, R (*func)(volatile T*, A0, A1, A2, A3, A4)) { - attach(func, obj); + new (this) Callback(func, obj); } /** Create a Callback with a static function and bound pointer @@ -3791,34 +3281,31 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to Callback(func, arg)") Callback(const volatile T *obj, R (*func)(const volatile T*, A0, A1, A2, A3, A4)) { - attach(func, obj); + new (this) Callback(func, obj); + } + + /** Destroy a callback + */ + ~Callback() { + if (_ops) { + _ops->dtor(this); + } } /** Attach a static function * @param func Static function to attach */ void attach(R (*func)(A0, A1, A2, A3, A4)) { - struct local { - static R _thunk(void*, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = 0; - _thunk = func ? &local::_thunk : 0; + this->~Callback(); + new (this) Callback(func); } /** Attach a Callback * @param func The Callback to attach */ void attach(const Callback &func) { - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func._func, sizeof func); - _obj = func._obj; - _thunk = func._thunk; + this->~Callback(); + new (this) Callback(func); } /** Attach a member function @@ -3827,18 +3314,8 @@ public: */ template void attach(T *obj, R (T::*method)(A0, A1, A2, A3, A4)) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (((T*)obj)->* - (*static_cast(method)))( - a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -3847,18 +3324,8 @@ public: */ template void attach(const T *obj, R (T::*method)(A0, A1, A2, A3, A4) const) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (((const T*)obj)->* - (*static_cast(method)))( - a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -3867,18 +3334,8 @@ public: */ template void attach(volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) volatile) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (((volatile T*)obj)->* - (*static_cast(method)))( - a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a member function @@ -3887,18 +3344,8 @@ public: */ template void attach(const volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) const volatile) { - struct local { - static R _thunk(void *obj, const void *method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (((const volatile T*)obj)->* - (*static_cast(method)))( - a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &method, sizeof method); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(obj, method); } /** Attach a static function with a bound pointer @@ -3906,17 +3353,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(void*, A0, A1, A2, A3, A4), void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (void*)arg, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3924,17 +3362,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const void*, A0, A1, A2, A3, A4), const void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (const void*)arg, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3942,17 +3371,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(volatile void*, A0, A1, A2, A3, A4), volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (volatile void*)arg, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3960,17 +3380,8 @@ public: * @param arg Pointer argument to function */ void attach(R (*func)(const volatile void*, A0, A1, A2, A3, A4), const volatile void *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (const volatile void*)arg, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3979,17 +3390,8 @@ public: */ template void attach(R (*func)(T*, A0, A1, A2, A3, A4), T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (T*)arg, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -3998,17 +3400,8 @@ public: */ template void attach(R (*func)(const T*, A0, A1, A2, A3, A4), const T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (const T*)arg, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -4017,17 +3410,8 @@ public: */ template void attach(R (*func)(volatile T*, A0, A1, A2, A3, A4), volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (volatile T*)arg, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -4036,17 +3420,8 @@ public: */ template void attach(R (*func)(const volatile T*, A0, A1, A2, A3, A4), const volatile T *arg) { - struct local { - static R _thunk(void *arg, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (const volatile T*)arg, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)arg; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, arg); } /** Attach a static function with a bound pointer @@ -4058,17 +3433,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(void *obj, R (*func)(void*, A0, A1, A2, A3, A4)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (void*)obj, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -4080,17 +3446,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const void *obj, R (*func)(const void*, A0, A1, A2, A3, A4)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (const void*)obj, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -4102,17 +3459,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile void *obj, R (*func)(volatile void*, A0, A1, A2, A3, A4)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (volatile void*)obj, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -4124,17 +3472,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile void *obj, R (*func)(const volatile void*, A0, A1, A2, A3, A4)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (const volatile void*)obj, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -4147,17 +3486,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(T *obj, R (*func)(T*, A0, A1, A2, A3, A4)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (T*)obj, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -4170,17 +3500,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const T *obj, R (*func)(const T*, A0, A1, A2, A3, A4)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (const T*)obj, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -4193,17 +3514,8 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(volatile T *obj, R (*func)(volatile T*, A0, A1, A2, A3, A4)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (volatile T*)obj, a0, a1, a2, a3, a4); - } - }; - - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + this->~Callback(); + new (this) Callback(func, obj); } /** Attach a static function with a bound pointer @@ -4216,24 +3528,26 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.1", "Arguments to callback have been reordered to attach(func, arg)") void attach(const volatile T *obj, R (*func)(const volatile T*, A0, A1, A2, A3, A4)) { - struct local { - static R _thunk(void *obj, const void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return (*static_cast(func))( - (const volatile T*)obj, a0, a1, a2, a3, a4); - } - }; + this->~Callback(); + new (this) Callback(func, obj); + } - memset(&_func, 0, sizeof _func); - memcpy(&_func, &func, sizeof func); - _obj = (void*)obj; - _thunk = &local::_thunk; + /** Assign a callback + */ + Callback &operator=(const Callback &that) { + if (this != &that) { + this->~Callback(); + new (this) Callback(that); + } + + return *this; } /** Call the attached function */ R call(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) const { - MBED_ASSERT(_thunk); - return _thunk(_obj, &_func, a0, a1, a2, a3, a4); + MBED_ASSERT(_ops); + return _ops->call(this, a0, a1, a2, a3, a4); } /** Call the attached function @@ -4245,7 +3559,7 @@ public: /** Test if function has been attached */ operator bool() const { - return _thunk; + return _ops; } /** Test for equality @@ -4264,8 +3578,7 @@ public: * @param func Callback to call passed as void pointer */ static R thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { - return static_cast*>(func)->call( - a0, a1, a2, a3, a4); + return static_cast(func)->call(a0, a1, a2, a3, a4); } private: @@ -4274,15 +3587,73 @@ private: // to garuntee proper size and alignment struct _class; union { - void (*_staticfunc)(); - void (*_boundfunc)(_class *); - void (_class::*_methodfunc)(); + void (*_staticfunc)(A0, A1, A2, A3, A4); + void (*_boundfunc)(_class*, A0, A1, A2, A3, A4); + void (_class::*_methodfunc)(A0, A1, A2, A3, A4); } _func; - void *_obj; - // Thunk registered on attach to dispatch calls - R (*_thunk)(void*, const void*, A0, A1, A2, A3, A4); + // Dynamically dispatched operations + const struct ops { + R (*call)(const void*, A0, A1, A2, A3, A4); + void (*move)(void*, const void*); + void (*dtor)(void*); + } *_ops; + + // Generate operations for function object + template + void generate(const F &f) { + struct local { + static R call(const void *p, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return (*(F*)p)(a0, a1, a2, a3, a4); + } + + static void move(void *d, const void *p) { + new (d) F(*(F*)p); + } + + static void dtor(void *p) { + ((F*)p)->~F(); + } + }; + + static const ops ops = { + &local::call, + &local::move, + &local::dtor, + }; + + MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F)); + new (this) F(f); + _ops = &ops; + } + + // Wrappers for functions with context + template + struct method_context { + M method; + O *obj; + + method_context(O *obj, M method) + : method(method), obj(obj) {} + + R operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) const { + return (obj->*method)(a0, a1, a2, a3, a4); + } + }; + + template + struct function_context { + F func; + A *arg; + + function_context(F func, A *arg) + : func(func), arg(arg) {} + + R operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) const { + return func(arg, a0, a1, a2, a3, a4); + } + }; }; // Internally used event type