Engine
Frameworkcreatedbymeusableforthecreationofsimplegames.CurrentlysupportsOpenGL(Verysimple)andVulkan.
Event.hpp
Go to the documentation of this file.
1 //=============================================================================
2 //
3 // (C) Copyright 2015 Amer Saffo (amer_saffo@yahoo.com)
4 // Distributed under the Code Project Open License 1.02 (CPOL)
5 // http://www.codeproject.com/info/cpol10.aspx
6 //
7 //=============================================================================
8 
9 //=============================================================================
10  // version 1.1
11  //=============================================================================
12 
13 #pragma once
14 
15 //-----------------------------------------------------------------------------
16 // define SHARP_EVENT_NO_BOOST to have no dependencies and manage thread-safety
17 // at the application level. Boost is used ONLY to make this class thread-safe.
18 //-----------------------------------------------------------------------------
19 //#ifndef SHARP_EVENT_NO_BOOST
20 //
21 //#include <ThirdParty/boost_1_65_1/boost/thread/locks.hpp>
22 //#include <ThirdParty/boost_1_65_1/boost/thread/shared_mutex.hpp>
23 //#endif // SHARP_EVENT_NO_BOOST
24 
25 #include "Engine/api.hpp"
26 #include <ThirdParty/EASTL-master/include/EASTL/list.h>
27 #include <ThirdParty/EASTL-master/include/EASTL/utility.h>
28 
29 namespace Sharp // short for SharpTools
30 {
31  //=============================================================================
32  // #region EventHandlerImpl
33  //=============================================================================
34 
41  template<typename T>
43  {
44  public:
45  EventHandlerImplBase() {} // needed to define the constructor since we defined the destructor (compiler would otherwise object)
46 
47  virtual ~EventHandlerImplBase() {} // destructor should be made virtual for base as we are going to delete through a base pointer
48 
49  virtual bool IsBindedToSameFunctionAs(EventHandlerImplBase<T>*) = 0; // verify if both handlers are binded to the same function.
50 
51 
52 
56  {
57  if (!pHandler2 || // a null pointer can never be the same as one that points to an actual handler
58  typeid(*this) != typeid(*pHandler2))
59  {
60  return false;
61  }
62 
63  return true;
64  }
65  };
66 
67  //------------------------------------
68  // one argument event handlers support
69  //------------------------------------
70 
71  template<typename T>
73  {
74  public:
75  virtual void OnEvent(T&) = 0; // will be called eventually when a Event is raised
76 
77  };
78 
79 
80 
83  template<typename T>
85  {
86  public:
88  EventHandlerImplForNonMemberFunction(void(*functionToCall)(T&))
89  : m_pFunctionToCall(functionToCall)
90  {
91  }
92 
94  virtual void OnEvent(T& evt)
95  {
96  m_pFunctionToCall(evt);
97  }
98 
101  {
102  if (!IsSametype(pHandler2))
103  {
104  return false;
105  }
106 
107  // they are the same type so we can safely cast to this class type
108  EventHandlerImplForNonMemberFunction<T>* pHandlerCasted = dynamic_cast<EventHandlerImplForNonMemberFunction<T>*>(pHandler2);
109  if (!pHandlerCasted)
110  {
111  // error, should never happen
112  return false;
113  }
114 
115  return this->m_pFunctionToCall == pHandlerCasted->m_pFunctionToCall;
116  }
117 
118  private:
119  void(*m_pFunctionToCall)(T&); // passed in the constructor. Will get called when an event is raised.
120 
121  };
122 
123 
124 
127  template<typename T, typename U>
129  {
130  public:
132  EventHandlerImplForMemberFunction(void(U::*memberFunctionToCall)(T&), U* thisPtr)
133  : m_pCallerInstance(thisPtr)
134  , m_pMemberFunction(memberFunctionToCall)
135  {
136  }
137 
139  virtual void OnEvent(T& evt)
140  {
141  if (m_pCallerInstance)
142  {
143  (m_pCallerInstance->*m_pMemberFunction)(evt);
144  }
145  }
146 
149  {
150  if (!IsSametype(pHandler2))
151  {
152  return false;
153  }
154 
155  // they are the same type so we can safely cast to this class type
156  EventHandlerImplForMemberFunction<T, U>* pHandlerCasted = dynamic_cast<EventHandlerImplForMemberFunction<T, U>*>(pHandler2);
157  if (!pHandlerCasted)
158  {
159  // error, should never happen
160  return false;
161  }
162 
163  return this->m_pCallerInstance == pHandlerCasted->m_pCallerInstance && this->m_pMemberFunction == pHandlerCasted->m_pMemberFunction;
164  }
165 
166  private:
167  U* m_pCallerInstance; // passed in the constructor. This watcher will only be used to call a member function, so m_pCallerInstance would hold the object through which that member function is called.
168 
169  void(U::*m_pMemberFunction)(T&); // passed in the constructor. This watcher will only be used to call a member function through m_pCallerInstance.
170 
171  };
172 
173 
174 
175  //------------------------------------
176 
177  // no arguments event handlers support
178 
179  //------------------------------------
180 
181 
182 
187  template<>
189  {
190  public:
191  virtual void OnEvent() = 0; // will be called eventually when an Event is raised
192 
193  };
194 
195 
196 
199  template<>
201  {
202  public:
204  EventHandlerImplForNonMemberFunction(void(*functionToCall)())
205  : m_pFunctionToCall(functionToCall)
206  {
207  }
208 
210  virtual void OnEvent()
211  {
212  m_pFunctionToCall();
213  }
214 
217  {
218  if (!IsSametype(pHandler2))
219  {
220  return false;
221  }
222 
223  // they are the same type so we can safely cast to this class type
225  if (!pHandlerCasted)
226  {
227  // error, should never happen
228  return false;
229  }
230 
231  return this->m_pFunctionToCall == pHandlerCasted->m_pFunctionToCall;
232  }
233 
234  private:
235  void(*m_pFunctionToCall)(); // passed in the constructor. Will get called when an event is raised.
236 
237  };
238 
239 
240 
243  template<typename U>
245  {
246  public:
248  EventHandlerImplForMemberFunction(void(U::*memberFunctionToCall)(), U* thisPtr)
249  : m_pCallerInstance(thisPtr)
250  , m_pMemberFunction(memberFunctionToCall)
251  {
252  }
253 
255  virtual void OnEvent()
256  {
257  if (m_pCallerInstance)
258  {
259  (m_pCallerInstance->*m_pMemberFunction)();
260  }
261  }
262 
265  {
266  if (!IsSametype(pHandler2))
267  {
268  return false;
269  }
270 
271  // they are the same type so we can safely cast to this class type
273  if (!pHandlerCasted)
274  {
275  // error, should never happen
276  return false;
277  }
278 
279  return this->m_pCallerInstance == pHandlerCasted->m_pCallerInstance && this->m_pMemberFunction == pHandlerCasted->m_pMemberFunction;
280  }
281 
282  private:
283  U* m_pCallerInstance; // passed in the constructor. This watcher will only be used to call a member function, so m_pCallerInstance would hold the object through which that member function is called.
284 
285  void(U::*m_pMemberFunction)(); // passed in the constructor. This watcher will only be used to call a member function through m_pCallerInstance.
286 
287  };
288 
289 
290 
291  //=============================================================================
292 
293  // #endregion EventHandlerImpl
294 
295  //=============================================================================
296 
297 
298 
299  //=============================================================================
300 
301  // #region EventHandler
302 
303  //=============================================================================
304 
305 
306 
318 
319  {
320 
321  public:
322 
323 
324 
325  //------------------------------------
326 
327  // one argument event handlers support
328 
329  //------------------------------------
330 
331 
332 
349  template<typename T>
350  static EventHandlerImpl<T>* Bind(void(*nonMemberFunctionToCall)(T&))
351  {
352  return new EventHandlerImplForNonMemberFunction<T>(nonMemberFunctionToCall);
353  }
354 
356  template<typename T, typename U>
357  static EventHandlerImpl<T>* Bind(void(U::*memberFunctionToCall)(T&), U* thisPtr)
358  {
359  return new EventHandlerImplForMemberFunction<T, U>(memberFunctionToCall, thisPtr);
360  }
361 
362  //------------------------------------
363  // no arguments event handlers support
364  //------------------------------------
365 
367  static EventHandlerImpl<void>* Bind(void(*nonMemberFunctionToCall)())
368  {
369  return new EventHandlerImplForNonMemberFunction<void>(nonMemberFunctionToCall);
370  }
371 
373  template<typename U>
374  static EventHandlerImpl<void>* Bind(void(U::*memberFunctionToCall)(), U* thisPtr)
375  {
376  return new EventHandlerImplForMemberFunction<void, U>(memberFunctionToCall, thisPtr);
377  }
378 
379  private:
380  EventHandler(); // default constructor made private to prevent creating instances of this class. EventHandler only purpose is to provide Event with the Bind function
381 
382  };
383 
384 
385 
386  //=============================================================================
387 
388  // #endregion EventHandler
389 
390  //=============================================================================
391 
392 
393 
394  //=============================================================================
395 
396  // #region Event
397 
398  //=============================================================================
399 
400 
401 
412  template<typename T>
414  {
415  public:
417 
423  virtual ~EventBase()
424  {
425 //#ifndef SHARP_EVENT_NO_BOOST
426  // we are going to modify the handlers list, so we need a write lock.
427  //WriteLock handlersWriteLock(m_handlersMutex);
428 //#endif // SHARP_EVENT_NO_BOOST
429 
430  for (eastl::list< EventHandlerImpl<T>* >::iterator iter = m_eventHandlers.begin(); iter != m_eventHandlers.end(); ++iter)
431  {
432  EventHandlerImpl<T>* pHandler = *iter;
433  if (pHandler)
434  {
435  delete pHandler;
436  pHandler = 0; // just to be consistent
437  }
438  }
439  m_eventHandlers.clear();
440  }
441 
455  EventBase<T>& operator += (EventHandlerImpl<T>* pHandlerToAdd)
456  {
457  // bellow is commented because we decided to let the user add the same handler multiple time and make it his responsibility to remove all those added
458  //if( FindHandlerWithSameBinding(pHandlerToAdd) != m_eventHandlers.end())
459 
460  if (pHandlerToAdd)
461  {
462 
463 //#ifndef SHARP_EVENT_NO_BOOST
464  // we are going to modify the handlers list, so we need a write lock.
465  //WriteLock handlersWriteLock(m_handlersMutex);
466 //#endif // SHARP_EVENT_NO_BOOST
467 
468  // the handler added bellow along with all handlers in the list will be called later when an event is raised
469  m_eventHandlers.push_back(pHandlerToAdd);
470  }
471 
472  return *this;
473  }
474 
480  EventBase<T>& operator -= (EventHandlerImpl<T>* pHandlerToRemove)
481  {
482  if (!pHandlerToRemove)
483  {
484  return *this; // a null passed, so nothing to do
485  }
486 
487 //#ifndef SHARP_EVENT_NO_BOOST
488  // we start by searching the handlers list and modify it ONLY when the passed handler is found
489  //UpgradeableReadLock handlersReadLock(m_handlersMutex); // acquire a read lock for the search and switch to a write lock later when the handler is found and is to be deleted.
490 //#endif // SHARP_EVENT_NO_BOOST
491 
492  // search for a handler that has the same binding as the passed one
493  // search linearly (no other way)
494  for (eastl::list< EventHandlerImpl<T>* >::iterator iter = m_eventHandlers.begin(); iter != m_eventHandlers.end(); ++iter)
495  {
496  EventHandlerImpl<T>* pHandler = *iter;
497  if (pHandlerToRemove->IsBindedToSameFunctionAs(pHandler))
498  {
499 //#ifndef SHARP_EVENT_NO_BOOST
500  // found the handler, we need to get a write lock as we are going to modify the handlers list.
501  //UpgradedWriteLock hanldersWriteLock(handlersReadLock); // this get a write lock without releasing the read lock already acquired.
502 //#endif // SHARP_EVENT_NO_BOOST
503 
504  // erase the memory that was created by the Bind function
505  // this memory is that of an EventHandler class and has nothing to do with the actual functions/class passed to it on Bind
506  EventHandlerImpl<T>* pFoundHandler = *iter;
507  if (pFoundHandler)
508  {
509  delete pFoundHandler;
510  pFoundHandler = 0;
511  }
512 
513  // remove it form the list (safe to do it here as we'll break the loop)
514  m_eventHandlers.erase(iter);
515  break;
516  }
517  }
518 
519  // also delete the passed handler as we don't need it anymore (by design, Event always owns the memory of the handlers passed to it)
520  if (pHandlerToRemove)
521  {
522  delete pHandlerToRemove;
523  pHandlerToRemove = 0;
524  }
525 
526  return *this;
527  }
528 
529  private:
530  EventBase(const EventBase&); // private to disable copying
531 
532  EventBase& operator=(const EventBase&); // private to disable copying
533 
534 
535  protected:
536 
537  eastl::list< EventHandlerImpl<T>* > m_eventHandlers; // all handlers will be notified when operator() is called.
538 
539 
540 
541 //#ifndef SHARP_EVENT_NO_BOOST
542 
543  //typedef boost::unique_lock< boost::shared_mutex > WriteLock;
544  //typedef boost::shared_lock< boost::shared_mutex > ReadLock;
545  //typedef boost::upgrade_lock< boost::shared_mutex > UpgradeableReadLock;
546  //typedef boost::upgrade_to_unique_lock< boost::shared_mutex > UpgradedWriteLock; // upgrade an upgradeable read lock to a write lock without releasing it.
547  //boost::shared_mutex m_handlersMutex; // used a shared mutex because we don't want threads raising the event to block each other. while adding/removing a handler should block all access.
548 
549 //#endif // SHARP_EVENT_NO_BOOST
550 
551  };
552 
553 
554 
555  //------------------------------------
556 
557  // one argument event handlers support
558 
559  //------------------------------------
560 
561  template<typename T>
562  class ENGINE_API Event : public EventBase<T>
563  {
564  public:
570  void operator()(T& eventData)
571  {
572 //#ifndef SHARP_EVENT_NO_BOOST
573  // this event just go through the list without modifying it, so a read lock is enough.
574  // we could have copied the handler list and released the lock, but we didn't do that for two reasons:
575  // 1. a thread removing a handler deletes that handler memory, and so we need to lock the usage of each handler and not only the retrieval of it from the list.
576  // 2. no performance issue here as reading threads don't block each other, and adding/removing a handler is expected to happen a few times only.
577  //ReadLock handlersReadLock(m_handlersMutex);
578 //#endif // SHARP_EVENT_NO_BOOST
579 
580  // raise the event by telling all the handlers
581  for (eastl::list< EventHandlerImpl<T>* >::iterator iter = m_eventHandlers.begin(); iter != m_eventHandlers.end(); ++iter)
582  {
583  EventHandlerImpl<T>* pHandler = *iter;
584  if (pHandler)
585  {
586  pHandler->OnEvent(eventData); // this is a virtual function that will eventually call the function passed to Eventhandler::Bind() for this handler
587  }
588  }
589  }
590  };
591 
592  //----------------------------
593  // no arguments event handlers support
594  //----------------------------
595  template<>
596  class ENGINE_API Event<void> : public EventBase<void>
597  {
598  public:
604  void operator()()
605  {
606 //#ifndef SHARP_EVENT_NO_BOOST
607  // this event just go through the list without modifying it, so a read lock is enough.
608  // we could have copied the handler list and released the lock, but we didn't do that for two reasons:
609  // 1. a thread removing a handler deletes that handler memory, and so we need to lock the usage of each handler and not only the retrieval of it from the list.
610  // 2. no performance issue here as reading threads don't block each other, and adding/removing a handler is expected to happen a few times only.
611  //ReadLock handlersReadLock(m_handlersMutex);
612 //#endif // SHARP_EVENT_NO_BOOST
613 
614  // raise the event by telling all the handlers
615  for (eastl::list< EventHandlerImpl<void>* >::iterator iter = m_eventHandlers.begin(); iter != m_eventHandlers.end(); ++iter)
616  {
617  EventHandlerImpl<void>* pHandler = *iter;
618  if (pHandler)
619  {
620  pHandler->OnEvent(); // this is a virtual function that will eventually call the function passed to Eventhandler::Bind() for this handler
621  }
622  }
623  }
624  };
625 
626  //=============================================================================
627  // #endregion Event
628  //=============================================================================
629 }
bool IsSametype(EventHandlerImplBase< T > *pHandler2)
Definition: Event.hpp:55
virtual bool IsBindedToSameFunctionAs(EventHandlerImplBase< void > *pHandler2)
Definition: Event.hpp:264
virtual void OnEvent(T &)=0
#define ENGINE_API
Definition: api.hpp:25
EventHandlerImplForMemberFunction(void(U::*memberFunctionToCall)(), U *thisPtr)
Definition: Event.hpp:248
eastl::list< EventHandlerImpl< T > * > m_eventHandlers
Definition: Event.hpp:537
virtual ~EventBase()
Definition: Event.hpp:423
EventHandlerImplForMemberFunction(void(U::*memberFunctionToCall)(T &), U *thisPtr)
Definition: Event.hpp:132
virtual bool IsBindedToSameFunctionAs(EventHandlerImplBase< void > *pHandler2)
Definition: Event.hpp:216
virtual bool IsBindedToSameFunctionAs(EventHandlerImplBase< T > *pHandler2)
Definition: Event.hpp:148
static EventHandlerImpl< T > * Bind(void(*nonMemberFunctionToCall)(T &))
Definition: Event.hpp:350
virtual ~EventHandlerImplBase()
Definition: Event.hpp:47
Definition: Event.hpp:29
static EventHandlerImpl< void > * Bind(void(*nonMemberFunctionToCall)())
Definition: Event.hpp:367
EventHandlerImplForNonMemberFunction(void(*functionToCall)())
Definition: Event.hpp:204
virtual bool IsBindedToSameFunctionAs(EventHandlerImplBase< T > *)=0
static EventHandlerImpl< T > * Bind(void(U::*memberFunctionToCall)(T &), U *thisPtr)
Definition: Event.hpp:357
static EventHandlerImpl< void > * Bind(void(U::*memberFunctionToCall)(), U *thisPtr)
Definition: Event.hpp:374
EventHandlerImplForNonMemberFunction(void(*functionToCall)(T &))
Definition: Event.hpp:88
virtual bool IsBindedToSameFunctionAs(EventHandlerImplBase< T > *pHandler2)
Definition: Event.hpp:100
void operator()(T &eventData)
Definition: Event.hpp:570