Gorgon Game Engine
Event.h
Go to the documentation of this file.
1 #pragma once
3 
4 #include <type_traits>
5 #include <vector>
6 #include <functional>
7 #include <mutex>
8 
9 #include <atomic>
10 
11 #include "Types.h"
12 #include "Containers/Collection.h"
13 #include "Utils/Assert.h"
14 #include "TMP.h"
15 
16 
17 namespace Gorgon {
18 
20  namespace internal {
21  namespace event {
22  template<class Source_, typename... Params_>
23  struct HandlerBase {
24  virtual void Fire(std::mutex &locker, Source_ *, Params_...) = 0;
25 
26  virtual ~HandlerBase() {}
27  };
28 
29  template<class Source_, typename... Params_>
30  struct EmptyHandlerFn : public HandlerBase<Source_, Params_...> {
31  EmptyHandlerFn(std::function<void()> fn) : fn(fn) { }
32 
33  virtual void Fire(std::mutex &locker, Source_ *, Params_...) {
34  auto f=fn;
35  locker.unlock();
36  f();
37  }
38 
39  std::function<void()> fn;
40  };
41 
42  template<class Source_, typename... Params_>
43  struct ArgsHandlerFn : public HandlerBase<Source_, Params_...> {
44  ArgsHandlerFn(std::function<void(Params_...)> fn) : fn(fn) { }
45 
46  virtual void Fire(std::mutex &locker, Source_ *, Params_... args) {
47  auto f=fn;
48  locker.unlock();
49  f(std::forward<Params_>(args)...);
50  }
51 
52  std::function<void(Params_...)> fn;
53  };
54 
55  template<class Source_, typename... Params_>
56  struct FullHandlerFn : public HandlerBase<Source_, Params_...> {
57  static_assert(!std::is_same<Source_, void>::value, "No source class exists for this event (void cannot be passed around)");
58 
59  FullHandlerFn(std::function<void(Source_&, Params_...)> fn) : fn(fn) { }
60 
61  virtual void Fire(std::mutex &locker, Source_ *source, Params_... args) {
62  auto f=fn;
63  locker.unlock();
64  f(*source, std::forward<Params_>(args)...);
65  }
66 
67  std::function<void(Source_&, Params_...)> fn;
68  };
69 
70  template<class Source_, class... Params_>
71  static HandlerBase<Source_, Params_...>& createhandlerfn(void(*fn)()) {
72  return *new EmptyHandlerFn<Source_, Params_...>(fn);
73  }
74 
75  template<class Source_, class... Params_>
76  static HandlerBase<Source_, Params_...>& createhandlerfn(void(*fn)(Params_...)) {
77  return *new ArgsHandlerFn<Source_, Params_...>(fn);
78  }
79 
80  template<class Source_, class... Params_>
81  static HandlerBase<Source_, Params_...>& createhandlerfn(void(*fn)(Source_ &, Params_...)) {
82  return *new FullHandlerFn<Source_, Params_...>(fn);
83  }
84 
85  template<class F_, class Source_, int N, class... Params_>
86  static typename std::enable_if<TMP::FunctionTraits<F_>::Arity==0, HandlerBase<Source_, Params_...>&>::type
87  createhandler_internal(F_ fn) {
88  return *new EmptyHandlerFn<Source_, Params_...>(fn);
89  }
90 
91  template<class F_, class Source_, int N, typename... Params_>
92  static typename std::enable_if<TMP::FunctionTraits<F_>::Arity!=0 && TMP::FunctionTraits<F_>::Arity==N, HandlerBase<Source_, Params_...>&>::type
93  createhandler_internal(F_ fn) {
94  return *new ArgsHandlerFn<Source_, Params_...>(fn);
95  }
96 
97  template<class F_, class Source_, int N, class... Params_>
98  static typename std::enable_if<TMP::FunctionTraits<F_>::Arity==N+1, HandlerBase<Source_, Params_...>&>::type
99  createhandler_internal(F_ fn) {
100  return *new FullHandlerFn<Source_, Params_...>(fn);
101  }
102 
103  template<class F_, class Source_, class... Params_>
104  typename std::enable_if<TMP::HasParanthesisOperator<F_>::value, HandlerBase<Source_, Params_...>&>::type
105  create_handler(F_ fn) {
106  return createhandler_internal<F_, Source_, sizeof...(Params_), Params_...>(fn);
107  }
108 
109  template<class F_, class Source_, class... Params_, typename N=void>
110  typename std::enable_if<!TMP::HasParanthesisOperator<F_>::value, HandlerBase<Source_, Params_...>&>::type
111  create_handler(F_ fn) {
112  return createhandlerfn<Source_, Params_...>(fn);
113  }
114  }
115  }
116 
118 
119 
121  typedef intptr_t EventToken;
122 
133  template<class Source_=void, typename... Params_>
134  class Event {
135  public:
136 
138  typedef intptr_t Token;
139 
141  Event() : source(nullptr) {
142  fire.clear();
143  static_assert( std::is_same<Source_, void>::value , "Empty constructor cannot be used." );
144  }
145 
147  template <class S_ = Source_>
148  explicit Event(typename std::enable_if<!std::is_same<S_, void>::value, S_>::type &source) : source(&source) {
149  fire.clear();
150  static_assert(!std::is_same<Source_, void>::value, "Filling constructor is not required, use the default.");
151  }
152 
154  template <class S_ = Source_>
155  explicit Event(typename std::enable_if<!std::is_same<S_, void>::value, S_>::type *source) : source(source) {
156  ASSERT(source, "Source cannot be nullptr");
157  fire.clear();
158  static_assert(!std::is_same<Source_, void>::value, "Filling constructor is not required, use the default.");
159  }
160 
162  Event(Event &&event) : source(nullptr) {
163  fire.clear();
164  Swap(event);
165 #ifndef NDEBUG
166  event.movedout = true;
167 #endif
168  }
169 
170 
172  ~Event() {
173  ASSERT(!fire.test_and_set(), "An event cannot be destroyed while its being fired.");
174  std::lock_guard<std::mutex> g(access);
175 
176  handlers.Destroy();
177  }
178 
180  Event(const Event &) = delete;
181 
183  Event &operator =(const Event &) = delete;
184 
186  Event &operator =(Event &&other) {
187  if(&other==this) return *this;
188 
189  std::lock_guard<std::mutex> g(access);
190 
191  ASSERT(!fire.test_and_set(), "An event cannot be moved into while its being fired.");
192 
193  handlers.Destroy();
194 
195  source=nullptr;
196  fire.clear();
197  Swap(other);
198 
199  return *this;
200  }
201 
203  void Swap(Event &other) {
204  if(&other==this) return;
205 
206  using std::swap;
207 
208  ASSERT(!fire.test_and_set() && !other.fire.test_and_set(), "An event cannot be swapped while its being fired.");
209 
210  swap(source, other.source);
211  swap(handlers, other.handlers);
212 
213  fire.clear();
214  other.fire.clear();
215  }
216 
222  template<class F_>
223  Token Register(F_ fn) {
224 
225  ASSERT(!movedout, "This event is moved out of");
226 
227  auto &handler=internal::event::create_handler<F_, Source_, Params_...>(fn);
228 
229  std::lock_guard<std::mutex> g(access);
230  handlers.Add(handler);
231 
232  return reinterpret_cast<Token>(&handler);
233  }
234 
244  template<class C_, typename... A_>
245  Token Register(C_ &c, void(C_::*fn)(A_...)) {
246 
247  ASSERT(!movedout, "This event is moved out of");
248 
249  std::function<void(A_...)> f=TMP::MakeFunctionFromMember(fn, &c);
250 
251  return Register(f);
252  }
253 
259  void Unregister(Token token) {
260 
261  ASSERT(!movedout, "This event is moved out of");
262 
263  std::lock_guard<std::mutex> g(access);
264 
265  auto item=reinterpret_cast<internal::event::HandlerBase<Source_, Params_...>*>(token);
266 
267  auto l=handlers.FindLocation(item);
268  if(l==-1) return;
269 
270  if(iterator.IsValid() && iterator.CurrentPtr()==item) {
271  handlers.Delete(l);
272 
273  //Collection iterator can point element -1
274  iterator.Previous();
275  }
276  else {
277  handlers.Delete(l);
278  }
279  }
280 
283  void operator()(Params_... args) {
284  //stops the request if it is received from a different thread.
285  std::lock_guard<std::recursive_mutex> g(firemtx);
286 
287  ASSERT(!movedout, "This event is moved out of");
288 
289  try {
290  for(iterator=handlers.begin(); iterator.IsValid(); iterator.Next()) {
291  access.lock();
292  // fire method will unlock access after it creates a local copy of the function
293  // this allows the fired object to be safely deleted.
294  iterator->Fire(access, source, std::forward<Params_>(args)...);
295  }
296  }
297  catch(...) {
298  //unlock everything if something goes bad
299 
300  //just in case
301  access.unlock();
302 
303  fire.clear();
304 
305  throw;
306  }
307 
308  fire.clear();
309  }
310 
312  void Clear() {
313  std::lock_guard<std::recursive_mutex> g1(firemtx);
314  std::lock_guard<std::mutex> g2(access);
315 
316 #ifndef NDEBUG
317  ASSERT(!fire.test_and_set(), "Recursion detected during event execution.");
318 #else
319  //prevent recursion
320  if(fire.test_and_set()) return;
321 #endif
322 
323  fire.clear();
324 
325  handlers.DeleteAll();
326  }
327 
329  static const Token EmptyToken;
330 
331  private:
332 
333 #ifndef NDEBUG
334  bool movedout = false;
335 #endif
336 
337 
338  std::mutex access;
339  std::atomic_flag fire;
340  Source_ *source;
341  Containers::Collection<internal::event::HandlerBase<Source_, Params_...>> handlers;
342  typename Containers::Collection<internal::event::HandlerBase<Source_, Params_...>>::Iterator iterator;
343  std::recursive_mutex firemtx;
344  };
345 
346  template<class C_, class ...P_>
347  const typename Event<C_, P_...>::Token Event<C_, P_...>::EmptyToken = 0;
348 
350  template<class Source_, class... Args_>
352  l.Swap(r);
353  }
354 }
Gorgon::Event::EmptyToken
static const Token EmptyToken
value for an empty token
Definition: Event.h:329
Gorgon::EventToken
intptr_t EventToken
Generic type to store event tokens.
Definition: Event.h:121
Gorgon::swap
void swap(Event< Source_, Args_... > &l, Event< Source_, Args_... > &r)
Swaps two events.
Definition: Event.h:351
Gorgon::Event
This class provides event mechanism.
Definition: Event.h:134
Collection.h
contains collection, a vector of references.
Gorgon::Event::~Event
~Event()
Destructor.
Definition: Event.h:172
Gorgon::Event::Event
Event(typename std::enable_if<!std::is_same< S_, void >::value, S_ >::type *source)
Constructor for class specific source.
Definition: Event.h:155
Gorgon::Event::Clear
void Clear()
Removes all registered handlers from this event.
Definition: Event.h:312
Gorgon::Event::operator=
Event & operator=(const Event &)=delete
Copy assignment is disabled.
TMP.h
This file contains template metaprogramming methods and classes used throughout Gorgon Library.
Gorgon::Input::Keyboard::Keycodes::N
constexpr Key N
Definition: Keyboard.h:93
Gorgon::Event::Register
Token Register(F_ fn)
Registers a new function to be called when this event is triggered.
Definition: Event.h:223
Gorgon::Event::Event
Event(Event &&event)
Move constructor.
Definition: Event.h:162
Gorgon::Event::operator()
void operator()(Params_... args)
Fire this event.
Definition: Event.h:283
Gorgon
Root namespace for Gorgon Game Engine.
Definition: Any.h:19
ASSERT
#define ASSERT(expression, message,...)
Replaces regular assert to allow messages and backtrace.
Definition: Assert.h:161
Gorgon::Containers::Collection
Collection is a container for reference typed objects.
Definition: Collection.h:21
Gorgon::Event::Swap
void Swap(Event &other)
Swaps two Events, used for move semantics.
Definition: Event.h:203
Gorgon::Event::Event
Event()
Constructor for empty source.
Definition: Event.h:141
Gorgon::Event::Event
Event(typename std::enable_if<!std::is_same< S_, void >::value, S_ >::type &source)
Constructor for class specific source.
Definition: Event.h:148
Gorgon::Event::Register
Token Register(C_ &c, void(C_::*fn)(A_...))
Registers a new function to be called when this event is triggered.
Definition: Event.h:245
Types.h
contains type definitions for Gorgon system
Gorgon::Event::Unregister
void Unregister(Token token)
Unregisters the given marked with the given token.
Definition: Event.h:259
Gorgon::TMP::MakeFunctionFromMember
std::function< Ret_(Args...) > MakeFunctionFromMember(Ret_(T_::*pm)(Args...), T_ *that)
Definition: TMP.h:482
Gorgon::Event::Token
intptr_t Token
Data type for tokens.
Definition: Event.h:138
Gorgon::Event::Event
Event(const Event &)=delete
Copy constructor is disabled.
Assert.h