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: Binder.h
- Revision:
- 18:a0fde14b6c39
- Parent:
- 14:79be4e700cc9
--- a/Binder.h Wed Apr 20 02:43:14 2016 -0500 +++ b/Binder.h Sun Apr 17 23:38:04 2016 -0500 @@ -9,11 +9,346 @@ /** Static function binding */ -template <typename F, typename B0=void, typename B1=void, typename B2=void, typename B3=void> +template <typename F, typename B0=void, typename B1=void, typename B2=void, typename B3=void, typename B4=void> class Binder; /** Static function binding */ +template <typename R, typename B0, typename B1, typename B2, typename B3, typename B4> +class Binder<R(B0, B1, B2, B3, B4), B0, B1, B2, B3, B4> { +public: + /** Create an unbound Binder + */ + Binder() {} + + /** Create a Binder, binding arguments to a function + */ + Binder(FuncPtr<R(B0, B1, B2, B3, B4)> func, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + attach(func, b0, b1, b2, b3, b4); + } + + /** Create a Binder, binding arguments to a method + */ + template <typename T, typename M> + Binder(T *obj, M method, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + attach(obj, method, b0, b1, b2, b3, b4); + } + + /** Bind arguments to a function + */ + void attach(FuncPtr<R(B0, B1, B2, B3, B4)> func, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + _func.attach(func); + _b0 = b0; _b1 = b1; _b2 = b2; _b3 = b3; _b4 = b4; + } + + /** Bind arguments to a method + */ + template <typename T, typename M> + void attach(T *obj, M method, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + attach(FuncPtr<R(B0, B1, B2, B3, B4)>(obj, method), b0, b1, b2, b3, b4); + } + + /** Call the bound function + */ + R call() { + return _func(_b0, _b1, _b2, _b3, _b4); + } + + /** Call the bound function + */ + R operator()() { + return call(); + } + + /** Test if function has been bound + */ + operator bool() const { + return _func; + } + + /** Static thunk for passing as C-style function + * @param func Binder to call passed as void pointer + */ + static R thunk(void *func) { + return static_cast<Binder<R(B0, B1, B2, B3, B4), B0, B1, B2, B3, B4>*>(func) + ->call(); + } + +private: + FuncPtr<R(B0, B1, B2, B3, B4)> _func; + B0 _b0; B1 _b1; B2 _b2; B3 _b3; B4 _b4; +}; + +/** Static function binding + */ +template <typename R, typename B0, typename B1, typename B2, typename B3, typename A0> +class Binder<R(B0, B1, B2, B3, A0), B0, B1, B2, B3> { +public: + /** Create an unbound Binder + */ + Binder() {} + + /** Create a Binder, binding arguments to a function + */ + Binder(FuncPtr<R(B0, B1, B2, B3, A0)> func, B0 b0, B1 b1, B2 b2, B3 b3) { + attach(func, b0, b1, b2, b3); + } + + /** Create a Binder, binding arguments to a method + */ + template <typename T, typename M> + Binder(T *obj, M method, B0 b0, B1 b1, B2 b2, B3 b3) { + attach(obj, method, b0, b1, b2, b3); + } + + /** Bind arguments to a function + */ + void attach(FuncPtr<R(B0, B1, B2, B3, A0)> func, B0 b0, B1 b1, B2 b2, B3 b3) { + _func.attach(func); + _b0 = b0; _b1 = b1; _b2 = b2; _b3 = b3; + } + + /** Bind arguments to a method + */ + template <typename T, typename M> + void attach(T *obj, M method, B0 b0, B1 b1, B2 b2, B3 b3) { + attach(FuncPtr<R(B0, B1, B2, B3, A0)>(obj, method), b0, b1, b2, b3); + } + + /** Call the bound function + */ + R call(A0 a0) { + return _func(_b0, _b1, _b2, _b3, a0); + } + + /** Call the bound function + */ + R operator()(A0 a0) { + return call(a0); + } + + /** Test if function has been bound + */ + operator bool() const { + return _func; + } + + /** Static thunk for passing as C-style function + * @param func Binder to call passed as void pointer + */ + static R thunk(void *func, A0 a0) { + return static_cast<Binder<R(B0, B1, B2, B3, A0), B0, B1, B2, B3>*>(func) + ->call(a0); + } + +private: + FuncPtr<R(B0, B1, B2, B3, A0)> _func; + B0 _b0; B1 _b1; B2 _b2; B3 _b3; +}; + +/** Static function binding + */ +template <typename R, typename B0, typename B1, typename B2, typename A0, typename A1> +class Binder<R(B0, B1, B2, A0, A1), B0, B1, B2> { +public: + /** Create an unbound Binder + */ + Binder() {} + + /** Create a Binder, binding arguments to a function + */ + Binder(FuncPtr<R(B0, B1, B2, A0, A1)> func, B0 b0, B1 b1, B2 b2) { + attach(func, b0, b1, b2); + } + + /** Create a Binder, binding arguments to a method + */ + template <typename T, typename M> + Binder(T *obj, M method, B0 b0, B1 b1, B2 b2) { + attach(obj, method, b0, b1, b2); + } + + /** Bind arguments to a function + */ + void attach(FuncPtr<R(B0, B1, B2, A0, A1)> func, B0 b0, B1 b1, B2 b2) { + _func.attach(func); + _b0 = b0; _b1 = b1; _b2 = b2; + } + + /** Bind arguments to a method + */ + template <typename T, typename M> + void attach(T *obj, M method, B0 b0, B1 b1, B2 b2) { + attach(FuncPtr<R(B0, B1, B2, A0, A1)>(obj, method), b0, b1, b2); + } + + /** Call the bound function + */ + R call(A0 a0, A1 a1) { + return _func(_b0, _b1, _b2, a0, a1); + } + + /** Call the bound function + */ + R operator()(A0 a0, A1 a1) { + return call(a0, a1); + } + + /** Test if function has been bound + */ + operator bool() const { + return _func; + } + + /** Static thunk for passing as C-style function + * @param func Binder to call passed as void pointer + */ + static R thunk(void *func, A0 a0, A1 a1) { + return static_cast<Binder<R(B0, B1, B2, A0, A1), B0, B1, B2>*>(func) + ->call(a0, a1); + } + +private: + FuncPtr<R(B0, B1, B2, A0, A1)> _func; + B0 _b0; B1 _b1; B2 _b2; +}; + +/** Static function binding + */ +template <typename R, typename B0, typename B1, typename A0, typename A1, typename A2> +class Binder<R(B0, B1, A0, A1, A2), B0, B1> { +public: + /** Create an unbound Binder + */ + Binder() {} + + /** Create a Binder, binding arguments to a function + */ + Binder(FuncPtr<R(B0, B1, A0, A1, A2)> func, B0 b0, B1 b1) { + attach(func, b0, b1); + } + + /** Create a Binder, binding arguments to a method + */ + template <typename T, typename M> + Binder(T *obj, M method, B0 b0, B1 b1) { + attach(obj, method, b0, b1); + } + + /** Bind arguments to a function + */ + void attach(FuncPtr<R(B0, B1, A0, A1, A2)> func, B0 b0, B1 b1) { + _func.attach(func); + _b0 = b0; _b1 = b1; + } + + /** Bind arguments to a method + */ + template <typename T, typename M> + void attach(T *obj, M method, B0 b0, B1 b1) { + attach(FuncPtr<R(B0, B1, A0, A1, A2)>(obj, method), b0, b1); + } + + /** Call the bound function + */ + R call(A0 a0, A1 a1, A2 a2) { + return _func(_b0, _b1, a0, a1, a2); + } + + /** Call the bound function + */ + R operator()(A0 a0, A1 a1, A2 a2) { + return call(a0, a1, a2); + } + + /** Test if function has been bound + */ + operator bool() const { + return _func; + } + + /** Static thunk for passing as C-style function + * @param func Binder to call passed as void pointer + */ + static R thunk(void *func, A0 a0, A1 a1, A2 a2) { + return static_cast<Binder<R(B0, B1, A0, A1, A2), B0, B1>*>(func) + ->call(a0, a1, a2); + } + +private: + FuncPtr<R(B0, B1, A0, A1, A2)> _func; + B0 _b0; B1 _b1; +}; + +/** Static function binding + */ +template <typename R, typename B0, typename A0, typename A1, typename A2, typename A3> +class Binder<R(B0, A0, A1, A2, A3), B0> { +public: + /** Create an unbound Binder + */ + Binder() {} + + /** Create a Binder, binding arguments to a function + */ + Binder(FuncPtr<R(B0, A0, A1, A2, A3)> func, B0 b0) { + attach(func, b0); + } + + /** Create a Binder, binding arguments to a method + */ + template <typename T, typename M> + Binder(T *obj, M method, B0 b0) { + attach(obj, method, b0); + } + + /** Bind arguments to a function + */ + void attach(FuncPtr<R(B0, A0, A1, A2, A3)> func, B0 b0) { + _func.attach(func); + _b0 = b0; + } + + /** Bind arguments to a method + */ + template <typename T, typename M> + void attach(T *obj, M method, B0 b0) { + attach(FuncPtr<R(B0, A0, A1, A2, A3)>(obj, method), b0); + } + + /** Call the bound function + */ + R call(A0 a0, A1 a1, A2 a2, A3 a3) { + return _func(_b0, a0, a1, a2, a3); + } + + /** Call the bound function + */ + R operator()(A0 a0, A1 a1, A2 a2, A3 a3) { + return call(a0, a1, a2, a3); + } + + /** Test if function has been bound + */ + operator bool() const { + return _func; + } + + /** Static thunk for passing as C-style function + * @param func Binder to call passed as void pointer + */ + static R thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3) { + return static_cast<Binder<R(B0, A0, A1, A2, A3), B0>*>(func) + ->call(a0, a1, a2, a3); + } + +private: + FuncPtr<R(B0, A0, A1, A2, A3)> _func; + B0 _b0; +}; + +/** Static function binding + */ template <typename R, typename B0, typename B1, typename B2, typename B3> class Binder<R(B0, B1, B2, B3), B0, B1, B2, B3> { public: