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);
Composer.h
- Committer:
- Christopher Haster
- Date:
- 2016-04-17
- Revision:
- 18:a0fde14b6c39
- Parent:
- 14:79be4e700cc9
File content as of revision 18:a0fde14b6c39:
/* Composer * Static function composition */ #ifndef COMPOSER_H #define COMPOSER_H #include "FuncPtr.h" /** Static function composition */ template <typename F, typename G> class Composer; /** Static function composition */ template <typename R, typename B0, typename A0, typename A1, typename A2, typename A3, typename A4> class Composer<R(B0), B0(A0, A1, A2, A3, A4)> { public: /** Create an uncomposed Composer */ Composer() {} /** Create a Composer, composing two functions */ Composer(FuncPtr<R(B0)> f, FuncPtr<B0(A0, A1, A2, A3, A4)> g) { attach(f, g); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM> Composer(FT *fobj, FM fmethod, FuncPtr<B0(A0, A1, A2, A3, A4)> g) { attach(fobj, fmethod, g); } /** Create a Composer, composing functions and methods */ template <typename GT, typename GM> Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, gobj, gmethod); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM, typename GT, typename GM> Composer(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(fobj, fmethod, gobj, gmethod); } /** Compose two functions */ void attach(FuncPtr<R(B0)> f, FuncPtr<B0(A0, A1, A2, A3, A4)> g) { _f.attach(f); _g.attach(g); } /** Compose functions and methods */ template <typename FT, typename FM> void attach(FT *fobj, FM fmethod, FuncPtr<B0(A0, A1, A2, A3, A4)> g) { attach(FuncPtr<R(B0)>(fobj, fmethod), g); } /** Compose functions and methods */ template <typename GT, typename GM> void attach(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, FuncPtr<B0(A0, A1, A2, A3, A4)>(gobj, gmethod)); } /** Compose functions and methods */ template <typename FT, typename FM, typename GT, typename GM> void attach(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(FuncPtr<R(B0)>(fobj, fmethod), FuncPtr<B0(A0, A1, A2, A3, A4)>(gobj, gmethod)); } /** Call the composed functions */ R call(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { return _f(_g(a0, a1, a2, a3, a4)); } /** Call the composed functions */ R operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { return call(a0, a1, a2, a3, a4); } /** Test if functions have been composed */ operator bool() const { return _f && _g; } /** Static thunk for passing as C-style function * @param func Composer to call passed as void pointer */ static R thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { return static_cast<Composer<R(B0), B0(A0, A1, A2, A3, A4)>*>(func) ->call(a0, a1, a2, a3, a4); } private: FuncPtr<R(B0)> _f; FuncPtr<B0(A0, A1, A2, A3, A4)> _g; }; /** Static function composition */ template <typename R, typename B0, typename A0, typename A1, typename A2, typename A3> class Composer<R(B0), B0(A0, A1, A2, A3)> { public: /** Create an uncomposed Composer */ Composer() {} /** Create a Composer, composing two functions */ Composer(FuncPtr<R(B0)> f, FuncPtr<B0(A0, A1, A2, A3)> g) { attach(f, g); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM> Composer(FT *fobj, FM fmethod, FuncPtr<B0(A0, A1, A2, A3)> g) { attach(fobj, fmethod, g); } /** Create a Composer, composing functions and methods */ template <typename GT, typename GM> Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, gobj, gmethod); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM, typename GT, typename GM> Composer(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(fobj, fmethod, gobj, gmethod); } /** Compose two functions */ void attach(FuncPtr<R(B0)> f, FuncPtr<B0(A0, A1, A2, A3)> g) { _f.attach(f); _g.attach(g); } /** Compose functions and methods */ template <typename FT, typename FM> void attach(FT *fobj, FM fmethod, FuncPtr<B0(A0, A1, A2, A3)> g) { attach(FuncPtr<R(B0)>(fobj, fmethod), g); } /** Compose functions and methods */ template <typename GT, typename GM> void attach(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, FuncPtr<B0(A0, A1, A2, A3)>(gobj, gmethod)); } /** Compose functions and methods */ template <typename FT, typename FM, typename GT, typename GM> void attach(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(FuncPtr<R(B0)>(fobj, fmethod), FuncPtr<B0(A0, A1, A2, A3)>(gobj, gmethod)); } /** Call the composed functions */ R call(A0 a0, A1 a1, A2 a2, A3 a3) { return _f(_g(a0, a1, a2, a3)); } /** Call the composed functions */ R operator()(A0 a0, A1 a1, A2 a2, A3 a3) { return call(a0, a1, a2, a3); } /** Test if functions have been composed */ operator bool() const { return _f && _g; } /** Static thunk for passing as C-style function * @param func Composer to call passed as void pointer */ static R thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3) { return static_cast<Composer<R(B0), B0(A0, A1, A2, A3)>*>(func) ->call(a0, a1, a2, a3); } private: FuncPtr<R(B0)> _f; FuncPtr<B0(A0, A1, A2, A3)> _g; }; /** Static function composition */ template <typename R, typename B0, typename A0, typename A1, typename A2> class Composer<R(B0), B0(A0, A1, A2)> { public: /** Create an uncomposed Composer */ Composer() {} /** Create a Composer, composing two functions */ Composer(FuncPtr<R(B0)> f, FuncPtr<B0(A0, A1, A2)> g) { attach(f, g); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM> Composer(FT *fobj, FM fmethod, FuncPtr<B0(A0, A1, A2)> g) { attach(fobj, fmethod, g); } /** Create a Composer, composing functions and methods */ template <typename GT, typename GM> Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, gobj, gmethod); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM, typename GT, typename GM> Composer(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(fobj, fmethod, gobj, gmethod); } /** Compose two functions */ void attach(FuncPtr<R(B0)> f, FuncPtr<B0(A0, A1, A2)> g) { _f.attach(f); _g.attach(g); } /** Compose functions and methods */ template <typename FT, typename FM> void attach(FT *fobj, FM fmethod, FuncPtr<B0(A0, A1, A2)> g) { attach(FuncPtr<R(B0)>(fobj, fmethod), g); } /** Compose functions and methods */ template <typename GT, typename GM> void attach(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, FuncPtr<B0(A0, A1, A2)>(gobj, gmethod)); } /** Compose functions and methods */ template <typename FT, typename FM, typename GT, typename GM> void attach(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(FuncPtr<R(B0)>(fobj, fmethod), FuncPtr<B0(A0, A1, A2)>(gobj, gmethod)); } /** Call the composed functions */ R call(A0 a0, A1 a1, A2 a2) { return _f(_g(a0, a1, a2)); } /** Call the composed functions */ R operator()(A0 a0, A1 a1, A2 a2) { return call(a0, a1, a2); } /** Test if functions have been composed */ operator bool() const { return _f && _g; } /** Static thunk for passing as C-style function * @param func Composer to call passed as void pointer */ static R thunk(void *func, A0 a0, A1 a1, A2 a2) { return static_cast<Composer<R(B0), B0(A0, A1, A2)>*>(func) ->call(a0, a1, a2); } private: FuncPtr<R(B0)> _f; FuncPtr<B0(A0, A1, A2)> _g; }; /** Static function composition */ template <typename R, typename B0, typename A0, typename A1> class Composer<R(B0), B0(A0, A1)> { public: /** Create an uncomposed Composer */ Composer() {} /** Create a Composer, composing two functions */ Composer(FuncPtr<R(B0)> f, FuncPtr<B0(A0, A1)> g) { attach(f, g); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM> Composer(FT *fobj, FM fmethod, FuncPtr<B0(A0, A1)> g) { attach(fobj, fmethod, g); } /** Create a Composer, composing functions and methods */ template <typename GT, typename GM> Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, gobj, gmethod); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM, typename GT, typename GM> Composer(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(fobj, fmethod, gobj, gmethod); } /** Compose two functions */ void attach(FuncPtr<R(B0)> f, FuncPtr<B0(A0, A1)> g) { _f.attach(f); _g.attach(g); } /** Compose functions and methods */ template <typename FT, typename FM> void attach(FT *fobj, FM fmethod, FuncPtr<B0(A0, A1)> g) { attach(FuncPtr<R(B0)>(fobj, fmethod), g); } /** Compose functions and methods */ template <typename GT, typename GM> void attach(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, FuncPtr<B0(A0, A1)>(gobj, gmethod)); } /** Compose functions and methods */ template <typename FT, typename FM, typename GT, typename GM> void attach(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(FuncPtr<R(B0)>(fobj, fmethod), FuncPtr<B0(A0, A1)>(gobj, gmethod)); } /** Call the composed functions */ R call(A0 a0, A1 a1) { return _f(_g(a0, a1)); } /** Call the composed functions */ R operator()(A0 a0, A1 a1) { return call(a0, a1); } /** Test if functions have been composed */ operator bool() const { return _f && _g; } /** Static thunk for passing as C-style function * @param func Composer to call passed as void pointer */ static R thunk(void *func, A0 a0, A1 a1) { return static_cast<Composer<R(B0), B0(A0, A1)>*>(func) ->call(a0, a1); } private: FuncPtr<R(B0)> _f; FuncPtr<B0(A0, A1)> _g; }; /** Static function composition */ template <typename R, typename B0, typename A0> class Composer<R(B0), B0(A0)> { public: /** Create an uncomposed Composer */ Composer() {} /** Create a Composer, composing two functions */ Composer(FuncPtr<R(B0)> f, FuncPtr<B0(A0)> g) { attach(f, g); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM> Composer(FT *fobj, FM fmethod, FuncPtr<B0(A0)> g) { attach(fobj, fmethod, g); } /** Create a Composer, composing functions and methods */ template <typename GT, typename GM> Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, gobj, gmethod); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM, typename GT, typename GM> Composer(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(fobj, fmethod, gobj, gmethod); } /** Compose two functions */ void attach(FuncPtr<R(B0)> f, FuncPtr<B0(A0)> g) { _f.attach(f); _g.attach(g); } /** Compose functions and methods */ template <typename FT, typename FM> void attach(FT *fobj, FM fmethod, FuncPtr<B0(A0)> g) { attach(FuncPtr<R(B0)>(fobj, fmethod), g); } /** Compose functions and methods */ template <typename GT, typename GM> void attach(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, FuncPtr<B0(A0)>(gobj, gmethod)); } /** Compose functions and methods */ template <typename FT, typename FM, typename GT, typename GM> void attach(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(FuncPtr<R(B0)>(fobj, fmethod), FuncPtr<B0(A0)>(gobj, gmethod)); } /** Call the composed functions */ R call(A0 a0) { return _f(_g(a0)); } /** Call the composed functions */ R operator()(A0 a0) { return call(a0); } /** Test if functions have been composed */ operator bool() const { return _f && _g; } /** Static thunk for passing as C-style function * @param func Composer to call passed as void pointer */ static R thunk(void *func, A0 a0) { return static_cast<Composer<R(B0), B0(A0)>*>(func) ->call(a0); } private: FuncPtr<R(B0)> _f; FuncPtr<B0(A0)> _g; }; /** Static function composition */ template <typename R, typename B0> class Composer<R(B0), B0()> { public: /** Create an uncomposed Composer */ Composer() {} /** Create a Composer, composing two functions */ Composer(FuncPtr<R(B0)> f, FuncPtr<B0()> g) { attach(f, g); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM> Composer(FT *fobj, FM fmethod, FuncPtr<B0()> g) { attach(fobj, fmethod, g); } /** Create a Composer, composing functions and methods */ template <typename GT, typename GM> Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, gobj, gmethod); } /** Create a Composer, composing functions and methods */ template <typename FT, typename FM, typename GT, typename GM> Composer(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(fobj, fmethod, gobj, gmethod); } /** Compose two functions */ void attach(FuncPtr<R(B0)> f, FuncPtr<B0()> g) { _f.attach(f); _g.attach(g); } /** Compose functions and methods */ template <typename FT, typename FM> void attach(FT *fobj, FM fmethod, FuncPtr<B0()> g) { attach(FuncPtr<R(B0)>(fobj, fmethod), g); } /** Compose functions and methods */ template <typename GT, typename GM> void attach(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) { attach(f, FuncPtr<B0()>(gobj, gmethod)); } /** Compose functions and methods */ template <typename FT, typename FM, typename GT, typename GM> void attach(FT *fobj, FM fmethod, GT *gobj, GM gmethod) { attach(FuncPtr<R(B0)>(fobj, fmethod), FuncPtr<B0()>(gobj, gmethod)); } /** Call the composed functions */ R call() { return _f(_g()); } /** Call the composed functions */ R operator()() { return call(); } /** Test if functions have been composed */ operator bool() const { return _f && _g; } /** Static thunk for passing as C-style function * @param func Composer to call passed as void pointer */ static R thunk(void *func) { return static_cast<Composer<R(B0), B0()>*>(func) ->call(); } private: FuncPtr<R(B0)> _f; FuncPtr<B0()> _g; }; #endif