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