Flexible templated function class and related utilities that avoid dynamic memory allocation without limiting functionality
FuncPtr provides a flexible templated function class and related utilities while avoiding dynamic memory allocation and avoiding limited functionality.
FuncPtr provides an intuitive template interface:
FuncPtr<void(const char *)> func(puts); func("hello!\n"); // prints hello!
Several function types are supported by FuncPtr:
// Simple C functions void func(); FuncPtr<void()> fp(func); // C++ Methods struct Thing { void func(); }; Thing thing; FuncPtr<void()> fp(&thing, &Thing::func); // C functions with context void func(Thing *); FuncPtr<void()> fp(&thing, func); // Function objects struct Thing { void operator()(); }; Thing thing; FuncPtr<void()> fp(&thing);
There is no dynamic memory allocation, managing memory is placed entirely on the user. More advanced function manipulation can be accomplished with statically allocated classes:
// Function binding Binder<void(const char *), const char *> bind(putc, "hi!"); bind(); // prints hi! // Function composition Composer<int(const char *), const char *(int)> comp(puts, itoa); comp(10); // prints 10 // Function chaining Chainer<void(const char *), 2> chain; chain.attach(puts); chain.attach(puts); chain("hi!\n"); // prints hi! twice
FuncPtr allows easy support of a large range of function types in C++ APIs with very few lines of code:
class Thing { public: // The following two methods are sufficient for supporting // every supported function type void attach(FuncPtr<void()> func) { _func.attach(func); } template<typename T, typename M> void attach(T *obj, M method) { attach(FuncPtr<void()>(obj, method)); } private: FuncPtr<void()> _func; }
Additionally, FuncPtrs have several utilities for easy integration with C APIs:
// C style callbacks void register_callback(void (*callback)(void *), void *data); register_callback(&FuncPtr<void()>::thunk, &func); // C style functions without context void register_callback(void (*callback)()); Thunker thunk(func); register_callback(thunk); // mbed style callbacks void register_callback(T *obj, void (T::*M)()); register_callback(&func, &FuncPtr<void()>::call);
Diff: FuncPtr.h
- Revision:
- 18:a0fde14b6c39
- Parent:
- 14:79be4e700cc9
--- a/FuncPtr.h Wed Apr 20 02:43:14 2016 -0500 +++ b/FuncPtr.h Sun Apr 17 23:38:04 2016 -0500 @@ -17,6 +17,160 @@ /** Flexible templated function class */ +template <typename R, typename A0, typename A1, typename A2, typename A3, typename A4> +class FuncPtr<R(A0, A1, A2, A3, A4)> { +public: + /** Create a FuncPtr with a static function + * @param func Static function to attach + */ + FuncPtr(R (*func)(A0, A1, A2, A3, A4) = 0) { + attach(func); + } + + /** Create a FuncPtr with a static function and bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template<typename T> + FuncPtr(T *obj, R (*func)(T*, A0, A1, A2, A3, A4)) { + attach(obj, func); + } + + /** Create a FuncPtr with a method + * @param obj Pointer to object to invoke method on + * @param func Method to attach + */ + template<typename T> + FuncPtr(T *obj, R (T::*func)(A0, A1, A2, A3, A4)) { + attach(obj, func); + } + + /** Create a FuncPtr with a function object + * @param func Function object to attach + */ + template<typename T> + FuncPtr(T *obj) { + attach(obj, &T::operator()); + } + + /** Create a FuncPtr with another FuncPtr + * @param func FuncPtr to attach + */ + FuncPtr(const FuncPtr<R(A0, A1, A2, A3, A4)> &func) { + attach(func); + } + + /** Attach a static function + * @param func Static function to attach + */ + void attach(R (*func)(A0, A1, A2, A3, A4)) { + memcpy(&_func, &func, sizeof func); + _thunk = func ? &FuncPtr::_staticthunk : 0; + } + + /** Attach a static function with a bound pointer + * @param obj Pointer to object to bind to function + * @param func Static function to attach + */ + template <typename T> + void attach(T *obj, R (*func)(T*, A0, A1, A2, A3, A4)) { + _obj = static_cast<void*>(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &FuncPtr::_boundthunk<T>; + } + + /** Attach a method + * @param obj Pointer to object to invoke method on + * @param func Method to attach + */ + template<typename T> + void attach(T *obj, R (T::*func)(A0, A1, A2, A3, A4)) { + _obj = static_cast<void*>(obj); + memcpy(&_func, &func, sizeof func); + _thunk = &FuncPtr::_methodthunk<T>; + } + + /** Attach a function object + * @param func Function object to attach + */ + template<typename T> + void attach(T *func) { + attach(func, &T::operator()); + } + + /** Attach a FuncPtr + * @param func The FuncPtr to attach + */ + void attach(const FuncPtr<R(A0, A1, A2, A3, A4)> &func) { + _obj = func._obj; + memcpy(&_func, &func._func, sizeof _func); + _thunk = func._thunk; + } + + /** Call the attached function + */ + R call(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return _thunk(_obj, &_func, a0, a1, a2, a3, a4); + } + + /** Call the attached function + */ + R operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call(a0, a1, a2, a3, a4); + } + + /** Test if function has been attached + */ + operator bool() const { + return _thunk; + } + + /** Static thunk for passing as C-style function + * @param func FuncPtr to call passed as void pointer + */ + static R thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return static_cast<FuncPtr<R(A0, A1, A2, A3, A4)>*>(func) + ->call(a0, a1, a2, a3, a4); + } + +private: + // Internal thunks for various function types + static R _staticthunk(void*, void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return (*reinterpret_cast<R (**)(A0, A1, A2, A3, A4)>(func)) + (a0, a1, a2, a3, a4); + } + + template<typename T> + static R _boundthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return (*reinterpret_cast<R (**)(T*, A0, A1, A2, A3, A4)>(func)) + (static_cast<T*>(obj), a0, a1, a2, a3, a4); + } + + template<typename T> + static R _methodthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return (static_cast<T*>(obj)->* + (*reinterpret_cast<R (T::**)(A0, A1, A2, A3, A4)>(func))) + (a0, a1, a2, a3, a4); + } + + // Stored as pointer to function and pointer to optional object + // Function pointer is stored as union of possible function types + // to garuntee proper size and alignment + struct _class; + union { + void (*_staticfunc)(); + void (*_boundfunc)(_class *); + void (_class::*_methodfunc)(); + } _func; + + void *_obj; + + // Thunk registered on attach to dispatch calls + R (*_thunk)(void*, void*, A0, A1, A2, A3, A4); +}; + +/** Flexible templated function class + */ template <typename R, typename A0, typename A1, typename A2, typename A3> class FuncPtr<R(A0, A1, A2, A3)> { public: