-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEventBus.hpp
114 lines (97 loc) · 3.28 KB
/
EventBus.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#pragma once
#include "Common.hpp"
#include "EventBase.hpp"
#include "IoGroup.hpp"
#include "Sync.hpp"
// TODO: exceptions?
class EventBus {
public:
EventBus() = delete;
EventBus(const EventBus &) = delete;
EventBus(EventBus &&) = delete;
inline EventBus(IoGroup &vIoGroup) : x_vIoGroup(vIoGroup) {}
inline ~EventBus() {
RAII_LOCK(x_mtxPending);
while (x_uPending)
x_cvPending.Wait(x_mtxPending);
}
EventBus &operator =(const EventBus &) = delete;
EventBus &operator =(EventBus &&) = delete;
private:
struct X_HandlerContext {
std::unordered_set<void *> set;
RWLock rwl;
};
private:
template<class tHandler>
constexpr void X_Register(tHandler &) noexcept {}
template<class tHandler, class tEvent, class ...tvEvents>
inline void X_Register(tHandler &vHandler) noexcept {
{
auto &vCtx = x_aCtx[tEvent::kEventId];
RAII_LOCK(vCtx.rwl.WriteLock());
vCtx.set.emplace(reinterpret_cast<void *>(static_cast<tEvent::Handler *>(&vHandler)));
}
X_Register<tHandler, tvEvents...>(vHandler);
}
template<class tHandler>
constexpr void X_Unregister(tHandler &) noexcept {}
template<class tHandler, class tEvent, class ...tvEvents>
inline void X_Unregister(tHandler &vHandler) noexcept {
auto &vCtx = x_aCtx[tEvent::kEventId];
if (vCtx.rwl.WriteLock().TryAcquire()) {
vCtx.set.erase(reinterpret_cast<void *>(static_cast<tEvent::Handler *>(&vHandler)));
vCtx.rwl.WriteLock().Release();
}
else {
auto &&fnJob = [this, &vCtx, &vHandler] {
{
RAII_LOCK(vCtx.rwl.WriteLock());
vCtx.set.erase(reinterpret_cast<void *>(&vHandler));
}
RAII_LOCK(x_mtxPending);
--x_uPending;
x_cvPending.WakeOne();
};
RAII_LOCK(x_mtxPending);
++x_uPending;
x_vIoGroup.PostJob(std::move(fnJob));
}
X_Unregister<tHandler, tvEvents...>(vHandler);
}
public:
template<class ...tvEvents>
inline EventBus &Register(HandlerBase<tvEvents...> &vHandler) noexcept {
X_Register<HandlerBase<tvEvents...>, tvEvents...>(vHandler);
return *this;
}
template<class ...tvEvents>
inline EventBus &Unregister(HandlerBase<tvEvents...> &vHandler) noexcept {
X_Unregister<HandlerBase<tvEvents...>, tvEvents...>(vHandler);
return *this;
}
template<
class tEvent,
REQUIRES(std::is_base_of_v<EventBase<tEvent::kEventId, tEvent>, tEvent>)
>
inline EventBus &PostEvent(tEvent &e) noexcept {
auto &vCtx = x_aCtx[tEvent::kEventId];
RAII_LOCK(vCtx.rwl.ReadLock());
for (auto pHandler : vCtx.set)
reinterpret_cast<typename tEvent::Handler *>(pHandler)->OnEvent(e);
return *this;
}
template<
class tEvent,
REQUIRES(std::is_base_of_v<EventBase<tEvent::kEventId, tEvent>, tEvent>)
>
inline EventBus &PostEvent(tEvent &&e) noexcept {
return PostEvent(e);
}
private:
IoGroup &x_vIoGroup;
X_HandlerContext x_aCtx[256];
Mutex x_mtxPending;
ConditionVariable x_cvPending;
U32 x_uPending = 0;
};