Note! This project has moved to github.com/armmbed/mbed-events
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-22
- Revision:
- 13:b84e049b2d9c
- Parent:
- 12:1feb78280125
- Child:
- 14:5abf2ccf2dbf
File content as of revision 13:b84e049b2d9c:
/* 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, typename A4> class Event<void(A0, A1, A2, A3, A4)> { public: /** Create an event bound to a queue */ Event(EventQueue *queue=0, FuncPtr<void(A0, A1, A2, A3, A4)> callback=0) { 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) { _queue = queue; } /** Attach a callback to an event */ void attach(FuncPtr<void(A0, A1, A2, A3, A4)> callback) { _callback.attach(callback); } /** Attach a callback to an event */ template <typename T, typename M> void attach(T *obj, M method) { attach(FuncPtr<void(A0, A1, A2, A3, A4)>(obj, method)); } /** Attach a callback to an event */ void attach(EventQueue *queue, FuncPtr<void(A0, A1, A2, A3, A4)> callback) { attach(queue); attach(callback); } /** Attach an event to a queue */ template <typename T, typename M> void attach(EventQueue *queue, T *obj, M method) { attach(queue); attach(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 * @return True if the event was posted successfully */ bool trigger(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { if (_event.registered) { return false; } _bind.attach(_callback, a0, a1, a2, a3, a4); _event.callback = Binder<void(A0, A1, A2, A3, A4), A0, A1, A2, A3, A4>::thunk; _event.data = &_bind; _queue->event_register(&_event, _event.delay); return true; } /** Post the event onto the bound queue */ void call(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { trigger(a0, a1, a2, a3, a4); } /** Post the event onto the bound queue */ void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { return call(a0, a1, a2, a3, a4); } /** 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, A4 a4) { return static_cast<Event<void(A0, A1, A2, A3, A4)>*>(data) ->call(a0, a1, a2, a3, a4); } /** Cancel a pending event */ void cancel() { _queue->event_unregister(&_event); } private: EventQueue *_queue; EventQueue::event _event; FuncPtr<void(A0, A1, A2, A3, A4)> _callback; Binder<void(A0, A1, A2, A3, A4), A0, A1, A2, A3, A4> _bind; }; /** Pendable event class */ template <typename A0, typename A1, typename A2, typename A3> class Event<void(A0, A1, A2, A3)> { public: /** Create an event bound to a queue */ Event(EventQueue *queue=0, FuncPtr<void(A0, A1, A2, A3)> callback=0) { 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) { _queue = queue; } /** Attach a callback to an event */ void attach(FuncPtr<void(A0, A1, A2, A3)> callback) { _callback.attach(callback); } /** Attach a callback to an event */ template <typename T, typename M> void attach(T *obj, M method) { attach(FuncPtr<void(A0, A1, A2, A3)>(obj, method)); } /** Attach a callback to an event */ void attach(EventQueue *queue, FuncPtr<void(A0, A1, A2, A3)> callback) { attach(queue); attach(callback); } /** Attach an event to a queue */ template <typename T, typename M> void attach(EventQueue *queue, T *obj, M method) { attach(queue); attach(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 */ bool trigger(A0 a0, A1 a1, A2 a2, A3 a3) { if (_event.registered) { return false; } _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); return true; } /** Post the event onto the bound queue */ void call(A0 a0, A1 a1, A2 a2, A3 a3) { trigger(a0, a1, a2, a3); } /** 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 event bound to a queue */ Event(EventQueue *queue=0, FuncPtr<void(A0, A1, A2)> callback=0) { 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) { _queue = queue; } /** Attach a callback to an event */ void attach(FuncPtr<void(A0, A1, A2)> callback) { _callback.attach(callback); } /** Attach a callback to an event */ template <typename T, typename M> void attach(T *obj, M method) { attach(FuncPtr<void(A0, A1, A2)>(obj, method)); } /** Attach a callback to an event */ void attach(EventQueue *queue, FuncPtr<void(A0, A1, A2)> callback) { attach(queue); attach(callback); } /** Attach an event to a queue */ template <typename T, typename M> void attach(EventQueue *queue, T *obj, M method) { attach(queue); attach(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 */ bool trigger(A0 a0, A1 a1, A2 a2) { if (_event.registered) { return false; } _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); return true; } /** Post the event onto the bound queue */ void call(A0 a0, A1 a1, A2 a2) { trigger(a0, a1, a2); } /** 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 event bound to a queue */ Event(EventQueue *queue=0, FuncPtr<void(A0, A1)> callback=0) { 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) { _queue = queue; } /** Attach a callback to an event */ void attach(FuncPtr<void(A0, A1)> callback) { _callback.attach(callback); } /** Attach a callback to an event */ template <typename T, typename M> void attach(T *obj, M method) { attach(FuncPtr<void(A0, A1)>(obj, method)); } /** Attach a callback to an event */ void attach(EventQueue *queue, FuncPtr<void(A0, A1)> callback) { attach(queue); attach(callback); } /** Attach an event to a queue */ template <typename T, typename M> void attach(EventQueue *queue, T *obj, M method) { attach(queue); attach(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 */ bool trigger(A0 a0, A1 a1) { if (_event.registered) { return false; } _bind.attach(_callback, a0, a1); _event.callback = Binder<void(A0, A1), A0, A1>::thunk; _event.data = &_bind; _queue->event_register(&_event, _event.delay); return true; } /** Post the event onto the bound queue */ void call(A0 a0, A1 a1) { trigger(a0, a1); } /** 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 event bound to a queue */ Event(EventQueue *queue=0, FuncPtr<void(A0)> callback=0) { 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) { _queue = queue; } /** Attach a callback to an event */ void attach(FuncPtr<void(A0)> callback) { _callback.attach(callback); } /** Attach a callback to an event */ template <typename T, typename M> void attach(T *obj, M method) { attach(FuncPtr<void(A0)>(obj, method)); } /** Attach a callback to an event */ void attach(EventQueue *queue, FuncPtr<void(A0)> callback) { attach(queue); attach(callback); } /** Attach an event to a queue */ template <typename T, typename M> void attach(EventQueue *queue, T *obj, M method) { attach(queue); attach(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 */ bool trigger(A0 a0) { if (_event.registered) { return false; } _bind.attach(_callback, a0); _event.callback = Binder<void(A0), A0>::thunk; _event.data = &_bind; _queue->event_register(&_event, _event.delay); return true; } /** Post the event onto the bound queue */ void call(A0 a0) { trigger(a0); } /** 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=0, FuncPtr<void()> callback=0) { 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) { _queue = queue; } /** Attach a callback to an event */ void attach(FuncPtr<void()> callback) { _callback.attach(callback); } /** Attach a callback to an event */ template <typename T, typename M> void attach(T *obj, M method) { attach(FuncPtr<void()>(obj, method)); } /** Attach a callback to an event */ void attach(EventQueue *queue, FuncPtr<void()> callback) { attach(queue); attach(callback); } /** Attach an event to a queue */ template <typename T, typename M> void attach(EventQueue *queue, T *obj, M method) { attach(queue); attach(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 */ bool trigger() { if (_event.registered) { return false; } _event.callback = FuncPtr<void()>::thunk; _event.data = &_callback; _queue->event_register(&_event, _event.delay); return true; } /** Post the event onto the bound queue */ void call() { trigger(); } /** 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