9 #include "imstkSpinLock.h" 19 #define SIGNAL(className,signalName) static std::string signalName() { return #className "::"#signalName; } 35 Event(
const std::string type) : m_type(type),m_sender(
nullptr) { }
36 virtual~
Event() =
default;
50 Command() : m_call(
nullptr),m_event(
nullptr) { }
51 Command(std::function<
void(
Event*)> call,std::shared_ptr<Event> event) : m_call(call),m_event(event) { }
60 if (m_event !=
nullptr)
62 if (m_call !=
nullptr)
64 m_call(m_event.get());
70 std::function<void(Event*)> m_call =
nullptr;
71 std::shared_ptr<Event> m_event =
nullptr;
74 template<
class T,
class RecieverType>
75 static void connect(std::shared_ptr<EventObject>,std::string(*)(),
76 std::shared_ptr<RecieverType>,
void(RecieverType::*)(T*));
78 static void connect(std::shared_ptr<EventObject>, std::string (*)(),
79 std::function<
void(T*)>);
81 template<
class T,
class RecieverType>
82 static void queueConnect(std::shared_ptr<EventObject>, std::string (*)(),
83 std::shared_ptr<RecieverType>,
void (RecieverType::*)(T*));
85 static void queueConnect(std::shared_ptr<EventObject>, std::string (*)(),
86 std::shared_ptr<EventObject>, std::function<
void(T*)>);
88 static void disconnect(std::shared_ptr<EventObject>,
89 std::shared_ptr<EventObject>, std::string (*)());
108 using Observer = std::tuple<bool, std::weak_ptr<EventObject>, std::function<void (Event*)>>;
123 std::shared_ptr<T> ePtr = std::make_shared<T>(e);
125 if (ePtr->m_sender ==
nullptr)
127 ePtr->m_sender =
this;
132 for (
auto i = directObservers.begin(); i != directObservers.end(); i++)
134 if (i->first == e.m_type)
136 std::vector<Observer>& observers = i->second;
137 for (std::vector<Observer>::iterator j = observers.begin(); j != observers.end();)
139 bool isLambda = std::get<0>(*j);
140 std::function<void(Event*)> receivingFunc = std::get<2>(*j);
144 if ((!isLambda && std::get<1>(*j).expired()) || receivingFunc ==
nullptr)
146 j = i->second.erase(j);
151 receivingFunc(ePtr.get());
159 for (
auto i = queuedObservers.begin(); i != queuedObservers.end(); i++)
161 if (i->first == e.m_type)
163 std::vector<Observer>& observers = i->second;
164 for (std::vector<Observer>::iterator j = observers.begin(); j != observers.end();)
166 bool isLambda = std::get<0>(*j);
167 std::function<void(Event*)> receivingFunc = std::get<2>(*j);
171 if ((!isLambda && std::get<1>(*j).expired()) || receivingFunc ==
nullptr)
173 j = i->second.erase(j);
178 std::shared_ptr<EventObject> receivingObj = std::get<1>(*j).lock();
179 receivingObj->eventQueueLock.lock();
180 receivingObj->eventQueue.push_back(
Command(receivingFunc, ePtr));
181 receivingObj->eventQueueLock.unlock();
195 std::shared_ptr<T> ePtr = std::make_shared<T>(e);
197 if (ePtr->m_sender ==
nullptr)
199 ePtr->m_sender =
this;
202 eventQueueLock.lock();
203 eventQueue.push_back(
Command(
nullptr, ePtr));
204 eventQueueLock.unlock();
213 eventQueueLock.lock();
214 if (eventQueue.empty())
216 eventQueueLock.unlock();
220 Command command = eventQueue.front();
221 eventQueue.pop_front();
223 eventQueueLock.unlock();
235 std::list<Command> cmds;
236 eventQueueLock.lock();
238 while (!eventQueue.empty())
240 cmds.push_back(eventQueue.front());
241 eventQueue.pop_front();
244 eventQueueLock.unlock();
258 eventQueueLock.lock();
259 for (std::deque<Command>::iterator i = eventQueue.begin(); i != eventQueue.end(); i++)
263 while (!eventQueue.empty())
265 Command command = eventQueue.back();
266 eventQueue.pop_back();
268 eventQueueLock.unlock();
276 eventQueueLock.lock();
277 for (std::deque<Command>::reverse_iterator i = eventQueue.rbegin(); i != eventQueue.rend(); i++)
281 while (!eventQueue.empty())
283 Command command = eventQueue.back();
284 eventQueue.pop_back();
286 eventQueueLock.unlock();
295 eventQueueLock.lock();
297 while (!eventQueue.empty())
299 Command command = eventQueue.back();
300 eventQueue.pop_back();
303 eventQueueLock.unlock();
307 template<
class T,
class RecieverType>
308 friend void connect(std::shared_ptr<EventObject>, std::string (*)(),
309 std::shared_ptr<RecieverType>,
void (RecieverType::*)(T*));
311 friend void connect(std::shared_ptr<EventObject>,
312 std::string (*)(), std::function<
void(T*)>);
314 template<
typename T,
class RecieverType>
315 friend void queueConnect(std::shared_ptr<EventObject>, std::string (*)(),
316 std::shared_ptr<RecieverType>,
void (RecieverType::*)(T*));
318 friend void queueConnect(std::shared_ptr<EventObject>, std::string (*)(),
319 std::shared_ptr<EventObject>, std::function<
void(T*)>);
321 friend void disconnect(std::shared_ptr<EventObject>,
322 std::shared_ptr<EventObject>, std::string (*)());
326 void addDirectObserver(std::string eventType, Observer observer)
328 std::vector<std::pair<std::string, std::vector<Observer>>>::iterator i =
329 std::find_if(directObservers.begin(), directObservers.end(),
330 [eventType](
const std::pair<std::string, std::vector<Observer>>& j)
331 {
return j.first == eventType; });
332 if (i == directObservers.end())
334 std::pair<std::string, std::vector<Observer>> test = std::pair<std::string, std::vector<Observer>>(eventType, std::vector<Observer>());
335 test.second.push_back(observer);
336 directObservers.push_back(test);
340 i->second.push_back(observer);
344 void addQueuedObserver(std::string eventType, Observer observer)
346 std::vector<std::pair<std::string, std::vector<Observer>>>::iterator i =
347 std::find_if(queuedObservers.begin(), queuedObservers.end(),
348 [eventType](
const std::pair<std::string, std::vector<Observer>>& j)
349 {
return j.first == eventType; });
350 if (i == queuedObservers.end())
352 std::pair<std::string, std::vector<Observer>> test = std::pair<std::string, std::vector<Observer>>(eventType, std::vector<Observer>());
353 test.second.push_back(observer);
354 queuedObservers.push_back(test);
358 i->second.push_back(observer);
364 std::deque<Command> eventQueue;
367 std::vector<std::pair<std::string, std::vector<Observer>>> queuedObservers;
368 std::vector<std::pair<std::string, std::vector<Observer>>> directObservers;
372 #pragma warning(push) 373 #pragma warning(disable: 4505) 375 template<
class T,
class ReceiverType>
386 connect(std::shared_ptr<EventObject> sender, std::string (* senderFunc)(),
387 std::shared_ptr<ReceiverType> receiver,
void (ReceiverType::* receiverFunc)(T*))
389 static_assert(std::is_base_of<EventObject, ReceiverType>::value,
"receiver not derived from EventObject");
391 std::function<void(T*)> receiverStdFunc = std::bind(receiverFunc, receiver.get(), std::placeholders::_1);
392 sender->addDirectObserver(senderFunc(), EventObject::Observer(
false, receiver, [ = ](
Event* e) { receiverStdFunc(static_cast<T*>(e)); }));
407 connect(std::shared_ptr<EventObject> sender, std::string (* senderFunc)(),
408 std::function<
void(T*)> receiverFunc)
410 sender->addDirectObserver(senderFunc(), EventObject::Observer(
true,
411 std::weak_ptr<EventObject>(), [ = ](
Event* e) { receiverFunc(static_cast<T*>(e)); }));
424 template<
class T,
class ReceiverType>
426 queueConnect(std::shared_ptr<EventObject> sender, std::string (* senderFunc)(),
427 std::shared_ptr<ReceiverType> receiver,
void (ReceiverType::* recieverFunc)(T*))
430 static_assert(std::is_base_of<EventObject, ReceiverType>::value,
"receiver not derived from EventObject");
432 std::function<void(T*)> recieverStdFunc = std::bind(recieverFunc, receiver.get(), std::placeholders::_1);
433 sender->addQueuedObserver(senderFunc(), EventObject::Observer(
false, receiver, [ = ](
Event* e) { recieverStdFunc(static_cast<T*>(e)); }));
451 queueConnect(std::shared_ptr<EventObject> sender, std::string (* senderFunc)(),
452 std::shared_ptr<EventObject> receiver, std::function<
void(T*)> recieverFunc)
454 sender->addQueuedObserver(senderFunc(), EventObject::Observer(
true, receiver, [ = ](
Event* e) { recieverFunc(static_cast<T*>(e)); }));
469 disconnect(std::shared_ptr<EventObject> sender,
470 std::shared_ptr<EventObject> reciever, std::string (* senderFunc)())
472 const std::string eventType = senderFunc();
474 auto i1 = std::find_if(sender->directObservers.begin(), sender->directObservers.end(),
475 [eventType](
const std::pair<std::string, std::vector<EventObject::Observer>>& j) {
return j.first == eventType; });
476 if (i1 != sender->directObservers.end())
478 auto j = std::find_if(i1->second.begin(), i1->second.end(), [reciever](
const EventObject::Observer& k) {
return std::get<1>(k).lock() == reciever; });
482 auto i2 = std::find_if(sender->queuedObservers.begin(), sender->queuedObservers.end(),
483 [eventType](
const std::pair<std::string, std::vector<EventObject::Observer>>& j) {
return j.first == eventType; });
484 if (i2 != sender->queuedObservers.end())
486 auto j = std::find_if(i2->second.begin(), i2->second.end(), [reciever](
const EventObject::Observer& k) {
return std::get<1>(k).lock() == reciever; });
void rforeachEvent(std::function< void(Command cmd)> func)
thread safe reverse loop over all event commands, one can implement a custom handler ...
void doAllEvents()
Do all the events in the event queue.
void doEvent()
Do an event, if none exists return.
void foreachEvent(std::function< void(Command cmd)> func)
Thread safe loop over all event commands, one can implement a custom handler.
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
void clearEvents()
Removes all events from queue cleans up copies of the event.
void invoke()
Call the underlying function if present then delete the event data.
EventObject is the base class for all objects in iMSTK that can receive and emit events. It supports direct and queued observer functions. Direct observers receive events immediately on the same thread This can either be posted on an object or be a function pointer Queued observers receive events within their queue which they can process whenever they like. These can be connected with the connect/queuedConnect/disconnect functions Lambda recievers cannot be disconnected unless all receivers to a signal are removed.
void queueEvent(const T &e)
Queues event directly to this.
void postEvent(const T &e)
Emits the event Direct observers will be immediately called, in sync Queued observers will receive th...
Stores everything needed to invoke an event A call may not be present, in which case invoke doesn't d...