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);
Chainer.h
- Committer:
- Christopher Haster
- Date:
- 2016-04-17
- Revision:
- 18:a0fde14b6c39
- Parent:
- 15:0c3d1c4a050b
File content as of revision 18:a0fde14b6c39:
/* Chainer * Static function chaining */ #ifndef CHAINER_H #define CHAINER_H #include "FuncPtr.h" /** Static function chaining */ template <typename F, int N> class Chainer; /** Static function composition */ template <typename A0, typename A1, typename A2, typename A3, typename A4, int N> class Chainer<void(A0, A1, A2, A3, A4), N> { public: /** Access a function in the chain */ FuncPtr<void(A0, A1, A2, A3, A4)> &operator[](int i) { return _funcs[i]; } /** Attach a function to the chain */ bool attach(FuncPtr<void(A0, A1, A2, A3, A4)> func) { for (int i = 0; i < N; i++) { if (!_funcs[i]) { _funcs[i].attach(func); return true; } } return false; } /** Attach a function to the chain */ template <typename T, typename M> bool attach(T *obj, M method) { return attach(FuncPtr<void(A0, A1, A2, A3, A4)>(obj, method)); } /** Call each function in the chain */ void call(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { for (int i = 0; i < N; i++) { if (_funcs[i]) { _funcs[i](a0, a1, a2, a3, a4); } } } /** Call each function in the chain */ void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { return call(a0, a1, a2, a3, a4); } /** Test if any functions have been attached */ operator bool() const { for (int i = 0; i < N; i++) { if (_funcs[i]) { return true; } } return false; } /** Static thunk for passing as C-style function * @param func Chainer to call passed as void pointer */ static void thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { return static_cast<Chainer<void(A0, A1, A2, A3, A4), N>*>(func) ->call(a0, a1, a2, a3, a4); } private: FuncPtr<void(A0, A1, A2, A3, A4)> _funcs[N]; }; /** Static function composition */ template <typename A0, typename A1, typename A2, typename A3, int N> class Chainer<void(A0, A1, A2, A3), N> { public: /** Access a function in the chain */ FuncPtr<void(A0, A1, A2, A3)> &operator[](int i) { return _funcs[i]; } /** Attach a function to the chain */ bool attach(FuncPtr<void(A0, A1, A2, A3)> func) { for (int i = 0; i < N; i++) { if (!_funcs[i]) { _funcs[i].attach(func); return true; } } return false; } /** Attach a function to the chain */ template <typename T, typename M> bool attach(T *obj, M method) { return attach(FuncPtr<void(A0, A1, A2, A3)>(obj, method)); } /** Call each function in the chain */ void call(A0 a0, A1 a1, A2 a2, A3 a3) { for (int i = 0; i < N; i++) { if (_funcs[i]) { _funcs[i](a0, a1, a2, a3); } } } /** Call each function in the chain */ void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { return call(a0, a1, a2, a3); } /** Test if any functions have been attached */ operator bool() const { for (int i = 0; i < N; i++) { if (_funcs[i]) { return true; } } return false; } /** Static thunk for passing as C-style function * @param func Chainer to call passed as void pointer */ static void thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3) { return static_cast<Chainer<void(A0, A1, A2, A3), N>*>(func) ->call(a0, a1, a2, a3); } private: FuncPtr<void(A0, A1, A2, A3)> _funcs[N]; }; /** Static function composition */ template <typename A0, typename A1, typename A2, int N> class Chainer<void(A0, A1, A2), N> { public: /** Access a function in the chain */ FuncPtr<void(A0, A1, A2)> &operator[](int i) { return _funcs[i]; } /** Attach a function to the chain */ bool attach(FuncPtr<void(A0, A1, A2)> func) { for (int i = 0; i < N; i++) { if (!_funcs[i]) { _funcs[i].attach(func); return true; } } return false; } /** Attach a function to the chain */ template <typename T, typename M> bool attach(T *obj, M method) { return attach(FuncPtr<void(A0, A1, A2)>(obj, method)); } /** Call each function in the chain */ void call(A0 a0, A1 a1, A2 a2) { for (int i = 0; i < N; i++) { if (_funcs[i]) { _funcs[i](a0, a1, a2); } } } /** Call each function in the chain */ void operator()(A0 a0, A1 a1, A2 a2) { return call(a0, a1, a2); } /** Test if any functions have been attached */ operator bool() const { for (int i = 0; i < N; i++) { if (_funcs[i]) { return true; } } return false; } /** Static thunk for passing as C-style function * @param func Chainer to call passed as void pointer */ static void thunk(void *func, A0 a0, A1 a1, A2 a2) { return static_cast<Chainer<void(A0, A1, A2), N>*>(func) ->call(a0, a1, a2); } private: FuncPtr<void(A0, A1, A2)> _funcs[N]; }; /** Static function composition */ template <typename A0, typename A1, int N> class Chainer<void(A0, A1), N> { public: /** Access a function in the chain */ FuncPtr<void(A0, A1)> &operator[](int i) { return _funcs[i]; } /** Attach a function to the chain */ bool attach(FuncPtr<void(A0, A1)> func) { for (int i = 0; i < N; i++) { if (!_funcs[i]) { _funcs[i].attach(func); return true; } } return false; } /** Attach a function to the chain */ template <typename T, typename M> bool attach(T *obj, M method) { return attach(FuncPtr<void(A0, A1)>(obj, method)); } /** Call each function in the chain */ void call(A0 a0, A1 a1) { for (int i = 0; i < N; i++) { if (_funcs[i]) { _funcs[i](a0, a1); } } } /** Call each function in the chain */ void operator()(A0 a0, A1 a1) { return call(a0, a1); } /** Test if any functions have been attached */ operator bool() const { for (int i = 0; i < N; i++) { if (_funcs[i]) { return true; } } return false; } /** Static thunk for passing as C-style function * @param func Chainer to call passed as void pointer */ static void thunk(void *func, A0 a0, A1 a1) { return static_cast<Chainer<void(A0, A1), N>*>(func) ->call(a0, a1); } private: FuncPtr<void(A0, A1)> _funcs[N]; }; /** Static function composition */ template <typename A0, int N> class Chainer<void(A0), N> { public: /** Access a function in the chain */ FuncPtr<void(A0)> &operator[](int i) { return _funcs[i]; } /** Attach a function to the chain */ bool attach(FuncPtr<void(A0)> func) { for (int i = 0; i < N; i++) { if (!_funcs[i]) { _funcs[i].attach(func); return true; } } return false; } /** Attach a function to the chain */ template <typename T, typename M> bool attach(T *obj, M method) { return attach(FuncPtr<void(A0)>(obj, method)); } /** Call each function in the chain */ void call(A0 a0) { for (int i = 0; i < N; i++) { if (_funcs[i]) { _funcs[i](a0); } } } /** Call each function in the chain */ void operator()(A0 a0) { return call(a0); } /** Test if any functions have been attached */ operator bool() const { for (int i = 0; i < N; i++) { if (_funcs[i]) { return true; } } return false; } /** Static thunk for passing as C-style function * @param func Chainer to call passed as void pointer */ static void thunk(void *func, A0 a0) { return static_cast<Chainer<void(A0), N>*>(func) ->call(a0); } private: FuncPtr<void(A0)> _funcs[N]; }; /** Static function composition */ template <int N> class Chainer<void(), N> { public: /** Access a function in the chain */ FuncPtr<void()> &operator[](int i) { return _funcs[i]; } /** Attach a function to the chain */ bool attach(FuncPtr<void()> func) { for (int i = 0; i < N; i++) { if (!_funcs[i]) { _funcs[i].attach(func); return true; } } return false; } /** Attach a function to the chain */ template <typename T, typename M> bool attach(T *obj, M method) { return attach(FuncPtr<void()>(obj, method)); } /** Call each function in the chain */ void call() { for (int i = 0; i < N; i++) { if (_funcs[i]) { _funcs[i](); } } } /** Call each function in the chain */ void operator()() { return call(); } /** Test if any functions have been attached */ operator bool() const { for (int i = 0; i < N; i++) { if (_funcs[i]) { return true; } } return false; } /** Static thunk for passing as C-style function * @param func Chainer to call passed as void pointer */ static void thunk(void *func) { return static_cast<Chainer<void(), N>*>(func) ->call(); } private: FuncPtr<void()> _funcs[N]; }; #endif