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:
- 7:9a62ba2d3d68
- Child:
- 8:71037a47492d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Chainer.h Sun Apr 17 15:30:34 2016 -0500 @@ -0,0 +1,366 @@ +/* Chainer + * Static function chaining + */ +#ifndef CHAINER_H +#define CHAINER_H + +#include "FuncPtr.h" + + +/** Static function chaining + */ +template <int N, typename F> +class Chainer; + +/** Static function composition + */ +template <int N, typename A0, typename A1, typename A2, typename A3> +class Chainer<N, void(A0, A1, A2, A3)> { +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(void) 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<N, void(A0, A1, A2, A3)>*>(func) + ->call(a0, a1, a2, a3); + } + +private: + FuncPtr<void(A0, A1, A2, A3)> _funcs[N]; +}; + +/** Static function composition + */ +template <int N, typename A0, typename A1, typename A2> +class Chainer<N, void(A0, A1, A2)> { +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(void) 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<N, void(A0, A1, A2)>*>(func) + ->call(a0, a1, a2); + } + +private: + FuncPtr<void(A0, A1, A2)> _funcs[N]; +}; + +/** Static function composition + */ +template <int N, typename A0, typename A1> +class Chainer<N, void(A0, A1)> { +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(void) 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<N, void(A0, A1)>*>(func) + ->call(a0, a1); + } + +private: + FuncPtr<void(A0, A1)> _funcs[N]; +}; + +/** Static function composition + */ +template <int N, typename A0> +class Chainer<N, void(A0)> { +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(void) 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<N, void(A0)>*>(func) + ->call(a0); + } + +private: + FuncPtr<void(A0)> _funcs[N]; +}; + +/** Static function composition + */ +template <int N> +class Chainer<N, void()> { +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(void) 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<N, void()>*>(func) + ->call(); + } + +private: + FuncPtr<void()> _funcs[N]; +}; + + +#endif