Flexible templated function class and related utilities that avoid dynamic memory allocation without limiting functionality

Dependents:   SimpleHTTPExample

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:
14:79be4e700cc9
Parent:
13:4d8a50d4967e
Child:
18:a0fde14b6c39

File content as of revision 14:79be4e700cc9:

/*  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>
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<B0(A0, A1, A2, A3)> 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<B0(A0, A1, A2)> 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<B0(A0, A1)> 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<B0(A0)> 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<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