Note! This project has moved to github.com/armmbed/mbed-events

Dependents:   SimpleHTTPExample

This repository has been superceded

This project has moved to mbed-events

Composable event loops combine the cheap synchronicity of event loops with the composability of preempted threads.

Two modular event queue classes are provided:

  • EventLoop - for loops coupled with a c++ managed thread
  • EventQueue - for manually managed event queues

The Event class takes advantage of the extensibility of FuncPtr to allow an event to be passed through APIs as a normal function.

More information on composable event loops.

Event.h

Committer:
Christopher Haster
Date:
2016-04-20
Revision:
3:6dccdc36651f
Parent:
2:11cda6bead99
Child:
4:30883e8633b4

File content as of revision 3:6dccdc36651f:

/*  Event
 *
 *  Pendable event
 */
#ifndef EVENT_H
#define EVENT_H

#include "EventQueue.h"
#include "FuncPtr.h"
#include "Binder.h"


/** Pendable event class
 */
template <typename F>
class Event;

/** Pendable event class
 */
template <typename A0, typename A1, typename A2, typename A3>
class Event<void(A0, A1, A2, A3)> {
public:
    /** Create an unbound event
     */
    Event() {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
    }

    /** Create an event bound to a queue
     */
    Event(EventQueue *queue, FuncPtr<void(A0, A1, A2, A3)> callback) {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
        attach(queue, callback);
    }

    /** Create an event bound to a queue
     */
    template <typename T, typename M>
    Event(EventQueue *queue, T *obj, M method) {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
        attach(queue, obj, method);
    }

    /** Safe lifetime management
     */
    ~Event() {
        cancel();
    }

    /** Attach an event to a queue
     */
    void attach(EventQueue *queue, FuncPtr<void(A0, A1, A2, A3)> callback) {
        _queue = queue;
        _callback.attach(callback);
    }

    /** Attach an event to a queue
     */
    template <typename T, typename M>
    void attach(EventQueue *queue, T *obj, M method) {
        _queue = queue;
        _callback.attach(FuncPtr<void(A0, A1, A2, A3)>(obj, method));
    }

    /** Set delay for when the event is dispatched after it is posted
     *  @param ms   Delay in milliseconds
     */
    void delay(int ms) {
        _event.delay = ms;
    }

    /** Set event to repeat periodically after it is posted
     *  @param ms   period in milliseconds
     */
    void period(int ms) {
        _event.period = ms;
    }

    /** Set tolerance hint on when the event must be called, defaults to 0
     *  @param ms   tolerance in milliseconds
     */
    void tolerance(int ms) {
        (void)ms; // currently ignored
    }

    /** Post the event onto the bound queue
     */
    void call(A0 a0, A1 a1, A2 a2, A3 a3) {
        _bind.attach(_callback, a0, a1, a2, a3);
        _event.callback = Binder<void(A0, A1, A2, A3), A0, A1, A2, A3>::thunk;
        _event.data = &_bind;
        _queue->event_register(&_event, _event.delay);
    }

    /** Post the event onto the bound queue
     */
    void operator()(A0 a0, A1 a1, A2 a2, A3 a3) {
        return call(a0, a1, a2, a3);
    }

    /** Test if event has been bound
     */
    operator bool() const {
        return _callback && _queue;
    }

    /** Static thunk for passing as C-style function
     *  @param data Event to dispatch passed as void pointer
     */
    static void thunk(void *data, A0 a0, A1 a1, A2 a2, A3 a3) {
        return static_cast<Event<void(A0, A1, A2, A3)>*>(data)
                ->call(a0, a1, a2, a3);
    }

    /** Cancel a pending event
     */
    void cancel() {
        _queue->event_unregister(&_event);
    }

private:
    EventQueue *_queue;
    EventQueue::event _event;
    FuncPtr<void(A0, A1, A2, A3)> _callback;
    Binder<void(A0, A1, A2, A3), A0, A1, A2, A3> _bind;
};

/** Pendable event class
 */
template <typename A0, typename A1, typename A2>
class Event<void(A0, A1, A2)> {
public:
    /** Create an unbound event
     */
    Event() {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
    }

    /** Create an event bound to a queue
     */
    Event(EventQueue *queue, FuncPtr<void(A0, A1, A2)> callback) {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
        attach(queue, callback);
    }

    /** Create an event bound to a queue
     */
    template <typename T, typename M>
    Event(EventQueue *queue, T *obj, M method) {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
        attach(queue, obj, method);
    }

    /** Safe lifetime management
     */
    ~Event() {
        cancel();
    }

    /** Attach an event to a queue
     */
    void attach(EventQueue *queue, FuncPtr<void(A0, A1, A2)> callback) {
        _queue = queue;
        _callback.attach(callback);
    }

    /** Attach an event to a queue
     */
    template <typename T, typename M>
    void attach(EventQueue *queue, T *obj, M method) {
        _queue = queue;
        _callback.attach(FuncPtr<void(A0, A1, A2)>(obj, method));
    }

    /** Set delay for when the event is dispatched after it is posted
     *  @param ms   Delay in milliseconds
     */
    void delay(int ms) {
        _event.delay = ms;
    }

    /** Set event to repeat periodically after it is posted
     *  @param ms   period in milliseconds
     */
    void period(int ms) {
        _event.period = ms;
    }

    /** Set tolerance hint on when the event must be called, defaults to 0
     *  @param ms   tolerance in milliseconds
     */
    void tolerance(int ms) {
        (void)ms; // currently ignored
    }

    /** Post the event onto the bound queue
     */
    void call(A0 a0, A1 a1, A2 a2) {
        _bind.attach(_callback, a0, a1, a2);
        _event.callback = Binder<void(A0, A1, A2), A0, A1, A2>::thunk;
        _event.data = &_bind;
        _queue->event_register(&_event, _event.delay);
    }

    /** Post the event onto the bound queue
     */
    void operator()(A0 a0, A1 a1, A2 a2) {
        return call(a0, a1, a2);
    }

    /** Test if event has been bound
     */
    operator bool() const {
        return _callback && _queue;
    }

    /** Static thunk for passing as C-style function
     *  @param data Event to dispatch passed as void pointer
     */
    static void thunk(void *data, A0 a0, A1 a1, A2 a2) {
        return static_cast<Event<void(A0, A1, A2)>*>(data)
                ->call(a0, a1, a2);
    }

    /** Cancel a pending event
     */
    void cancel() {
        _queue->event_unregister(&_event);
    }

private:
    EventQueue *_queue;
    EventQueue::event _event;
    FuncPtr<void(A0, A1, A2)> _callback;
    Binder<void(A0, A1, A2), A0, A1, A2> _bind;
};

/** Pendable event class
 */
template <typename A0, typename A1>
class Event<void(A0, A1)> {
public:
    /** Create an unbound event
     */
    Event() {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
    }

    /** Create an event bound to a queue
     */
    Event(EventQueue *queue, FuncPtr<void(A0, A1)> callback) {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
        attach(queue, callback);
    }

    /** Create an event bound to a queue
     */
    template <typename T, typename M>
    Event(EventQueue *queue, T *obj, M method) {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
        attach(queue, obj, method);
    }

    /** Safe lifetime management
     */
    ~Event() {
        cancel();
    }

    /** Attach an event to a queue
     */
    void attach(EventQueue *queue, FuncPtr<void(A0, A1)> callback) {
        _queue = queue;
        _callback.attach(callback);
    }

    /** Attach an event to a queue
     */
    template <typename T, typename M>
    void attach(EventQueue *queue, T *obj, M method) {
        _queue = queue;
        _callback.attach(FuncPtr<void(A0, A1)>(obj, method));
    }

    /** Set delay for when the event is dispatched after it is posted
     *  @param ms   Delay in milliseconds
     */
    void delay(int ms) {
        _event.delay = ms;
    }

    /** Set event to repeat periodically after it is posted
     *  @param ms   period in milliseconds
     */
    void period(int ms) {
        _event.period = ms;
    }

    /** Set tolerance hint on when the event must be called, defaults to 0
     *  @param ms   tolerance in milliseconds
     */
    void tolerance(int ms) {
        (void)ms; // currently ignored
    }

    /** Post the event onto the bound queue
     */
    void call(A0 a0, A1 a1) {
        _bind.attach(_callback, a0, a1);
        _event.callback = Binder<void(A0, A1), A0, A1>::thunk;
        _event.data = &_bind;
        _queue->event_register(&_event, _event.delay);
    }

    /** Post the event onto the bound queue
     */
    void operator()(A0 a0, A1 a1) {
        return call(a0, a1);
    }

    /** Test if event has been bound
     */
    operator bool() const {
        return _callback && _queue;
    }

    /** Static thunk for passing as C-style function
     *  @param data Event to dispatch passed as void pointer
     */
    static void thunk(void *data, A0 a0, A1 a1) {
        return static_cast<Event<void(A0, A1)>*>(data)
                ->call(a0, a1);
    }

    /** Cancel a pending event
     */
    void cancel() {
        _queue->event_unregister(&_event);
    }

private:
    EventQueue *_queue;
    EventQueue::event _event;
    FuncPtr<void(A0, A1)> _callback;
    Binder<void(A0, A1), A0, A1> _bind;
};

/** Pendable event class
 */
template <typename A0>
class Event<void(A0)> {
public:
    /** Create an unbound event
     */
    Event() {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
    }

    /** Create an event bound to a queue
     */
    Event(EventQueue *queue, FuncPtr<void(A0)> callback) {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
        attach(queue, callback);
    }

    /** Create an event bound to a queue
     */
    template <typename T, typename M>
    Event(EventQueue *queue, T *obj, M method) {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
        attach(queue, obj, method);
    }

    /** Safe lifetime management
     */
    ~Event() {
        cancel();
    }

    /** Attach an event to a queue
     */
    void attach(EventQueue *queue, FuncPtr<void(A0)> callback) {
        _queue = queue;
        _callback.attach(callback);
    }

    /** Attach an event to a queue
     */
    template <typename T, typename M>
    void attach(EventQueue *queue, T *obj, M method) {
        _queue = queue;
        _callback.attach(FuncPtr<void(A0)>(obj, method));
    }

    /** Set delay for when the event is dispatched after it is posted
     *  @param ms   Delay in milliseconds
     */
    void delay(int ms) {
        _event.delay = ms;
    }

    /** Set event to repeat periodically after it is posted
     *  @param ms   period in milliseconds
     */
    void period(int ms) {
        _event.period = ms;
    }

    /** Set tolerance hint on when the event must be called, defaults to 0
     *  @param ms   tolerance in milliseconds
     */
    void tolerance(int ms) {
        (void)ms; // currently ignored
    }

    /** Post the event onto the bound queue
     */
    void call(A0 a0) {
        _bind.attach(_callback, a0);
        _event.callback = Binder<void(A0), A0>::thunk;
        _event.data = &_bind;
        _queue->event_register(&_event, _event.delay);
    }

    /** Post the event onto the bound queue
     */
    void operator()(A0 a0) {
        return call(a0);
    }

    /** Test if event has been bound
     */
    operator bool() const {
        return _callback && _queue;
    }

    /** Static thunk for passing as C-style function
     *  @param data Event to dispatch passed as void pointer
     */
    static void thunk(void *data, A0 a0) {
        return static_cast<Event<void(A0)>*>(data)
                ->call(a0);
    }

    /** Cancel a pending event
     */
    void cancel() {
        _queue->event_unregister(&_event);
    }

private:
    EventQueue *_queue;
    EventQueue::event _event;
    FuncPtr<void(A0)> _callback;
    Binder<void(A0), A0> _bind;
};

/** Pendable event class
 */
template <>
class Event<void()> {
public:
    /** Create an unbound event
     */
    Event() {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
    }

    /** Create an event bound to a queue
     */
    Event(EventQueue *queue, FuncPtr<void()> callback) {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
        attach(queue, callback);
    }

    /** Create an event bound to a queue
     */
    template <typename T, typename M>
    Event(EventQueue *queue, T *obj, M method) {
        memset(&_event, 0, sizeof _event);
        _event.delay = 0;
        _event.period = -1;
        attach(queue, obj, method);
    }

    /** Safe lifetime management
     */
    ~Event() {
        cancel();
    }

    /** Attach an event to a queue
     */
    void attach(EventQueue *queue, FuncPtr<void()> callback) {
        _queue = queue;
        _callback.attach(callback);
    }

    /** Attach an event to a queue
     */
    template <typename T, typename M>
    void attach(EventQueue *queue, T *obj, M method) {
        _queue = queue;
        _callback.attach(FuncPtr<void()>(obj, method));
    }

    /** Set delay for when the event is dispatched after it is posted
     *  @param ms   Delay in milliseconds
     */
    void delay(int ms) {
        _event.delay = ms;
    }

    /** Set event to repeat periodically after it is posted
     *  @param ms   period in milliseconds
     */
    void period(int ms) {
        _event.period = ms;
    }

    /** Set tolerance hint on when the event must be called, defaults to 0
     *  @param ms   tolerance in milliseconds
     */
    void tolerance(int ms) {
        (void)ms; // currently ignored
    }

    /** Post the event onto the bound queue
     */
    void call() {
        _event.callback = FuncPtr<void()>::thunk;
        _event.data = &_callback;
        _queue->event_register(&_event, _event.delay);
    }

    /** Post the event onto the bound queue
     */
    void operator()() {
        return call();
    }

    /** Test if event has been bound
     */
    operator bool() const {
        return _callback && _queue;
    }

    /** Static thunk for passing as C-style function
     *  @param data Event to dispatch passed as void pointer
     */
    static void thunk(void *data) {
        return static_cast<Event<void()>*>(data)
                ->call();
    }

    /** Cancel a pending event
     */
    void cancel() {
        _queue->event_unregister(&_event);
    }

private:
    EventQueue *_queue;
    EventQueue::event _event;
    FuncPtr<void()> _callback;
};


#endif