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: Chainer.h
- Revision:
- 18:a0fde14b6c39
- Parent:
- 15:0c3d1c4a050b
--- a/Chainer.h Wed Apr 20 02:43:14 2016 -0500 +++ b/Chainer.h Sun Apr 17 23:38:04 2016 -0500 @@ -14,6 +14,76 @@ /** 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: