8
8
#include < atomic>
9
9
#include < algorithm>
10
10
#include < tuple>
11
+ #include < optional>
11
12
12
13
namespace geode ::event::v3 {
13
14
template <typename T>
@@ -20,88 +21,110 @@ namespace geode::event::v3 {
20
21
{ a == b } -> std::convertible_to<bool >;
21
22
};
22
23
23
- template <class PoolType >
24
- class Pool : protected PoolType {
25
- public:
26
- using EventType = typename PoolType::EventType;
27
- using CallbackType = typename PoolType::CallbackType;
28
-
24
+ class Pool {
29
25
private:
30
26
std::mutex mutex;
31
27
std::atomic_size_t recurse;
32
- std::vector<std::pair<EventType *, CallbackType >> toAdd;
33
- std::vector<std::pair<EventType *, EventType *>> toMove;
34
- std::vector<EventType *> toRemove;
28
+ std::vector<std::pair<void *, void * >> toAdd;
29
+ std::vector<std::pair<void *, void *>> toMove;
30
+ std::vector<void *> toRemove;
35
31
36
32
void catchup () {
37
33
std::lock_guard lock (mutex);
38
34
for (auto & ev : toRemove) {
39
- this ->PoolType :: removeListener (ev);
35
+ this ->removeListener (ev);
40
36
}
41
37
for (auto & [ev, cb] : toAdd) {
42
- this ->PoolType :: addListener (ev, std::move (cb));
38
+ this ->addListener (ev, std::move (cb));
43
39
}
44
40
for (auto & [from, to] : toMove) {
45
- this ->PoolType :: moveListener (from, to);
41
+ this ->moveListener (from, to);
46
42
}
47
43
toRemove.clear ();
48
44
toAdd.clear ();
49
45
toMove.clear ();
50
46
}
51
47
48
+ protected:
49
+ virtual ~Pool () = default ;
50
+ virtual void callListener (void * event, void * params) = 0;
51
+ virtual void addListener (void * event, void * callable) = 0;
52
+ virtual void removeListener (void * event) = 0;
53
+ virtual void moveListener (void * from, void * to) = 0;
54
+
52
55
public:
53
56
template <class ... Args>
54
- void callListeners (EventType * event, Args&&... args ) {
57
+ void callListeners (void * event, void * params ) {
55
58
recurse++;
56
- auto listeners = this ->getListeners (event);
57
- for (const auto & listener : listeners) {
58
- listener (std::forward<Args>(args)...);
59
- }
59
+ this ->callListener (event, params);
60
60
recurse--;
61
61
62
62
if (recurse == 0 ) {
63
63
this ->catchup ();
64
64
}
65
65
}
66
66
67
- void addListener (EventType * event, CallbackType callback ) {
67
+ void addListenerSafe ( void * event, void * callable ) {
68
68
std::lock_guard lock (mutex);
69
- if (recurse == 0 ) {
70
- this ->PoolType ::addListener (event, std::move (callback));
71
- } else {
72
- toAdd.emplace_back (event, std::move (callback));
69
+ if (recurse >= 0 ) {
70
+ toAdd.emplace_back (event, callable);
71
+ }
72
+ else {
73
+ this ->addListener (event, callable);
73
74
}
74
75
}
75
76
76
- void removeListener (EventType * event) {
77
+ void removeListenerSafe ( void * event) {
77
78
std::lock_guard lock (mutex);
78
- if (recurse == 0 ) {
79
- this ->PoolType ::removeListener (event);
80
- } else {
79
+ if (recurse >= 0 ) {
81
80
toRemove.emplace_back (event);
82
81
}
82
+ else {
83
+ this ->removeListener (event);
84
+ }
83
85
}
84
86
85
- void moveListener (EventType * from, EventType * to) {
87
+ void moveListenerSafe ( void * from, void * to) {
86
88
std::lock_guard lock (mutex);
87
- if (recurse == 0 ) {
88
- this ->PoolType ::moveListener (from, to);
89
- } else {
89
+ if (recurse >= 0 ) {
90
90
toMove.emplace_back (from, to);
91
91
}
92
+ else {
93
+ this ->moveListener (from, to);
94
+ }
95
+ }
96
+ };
97
+
98
+ template <class ... Args>
99
+ class ForwardHelper {
100
+ protected:
101
+ using CallbackType = std::function<void (Args...)>;
102
+ using ForwardTupleType = std::tuple<Args&&...>;
103
+
104
+ void call (void * c, void * t) {
105
+ auto callback = static_cast <CallbackType*>(c);
106
+ auto tuple = static_cast <ForwardTupleType*>(t);
107
+ std::apply (*callback, *tuple);
108
+ }
109
+
110
+ public:
111
+ auto forward (Args&&... args) {
112
+ return ForwardTupleType (std::forward<Args>(args)...);
113
+ }
114
+
115
+ auto callback (std::invocable auto callable) {
116
+ return CallbackType (callable);
92
117
}
93
118
};
94
119
95
- template <class E , class C >
96
- class HashablePool {
120
+ template <class E , class ... Args >
121
+ class HashablePool : public Pool , public ForwardHelper <Args...> {
97
122
protected:
98
123
using EventType = E;
99
- using CallbackType = std::function<C>;
100
124
101
125
private:
102
126
std::unordered_multimap<std::size_t , CallbackType> listeners;
103
127
104
- protected:
105
128
auto getListeners (EventType* event) const {
106
129
auto const hash = std::hash<EventType>{}(*event);
107
130
auto [begin, end] = listeners.equal_range (hash);
@@ -111,29 +134,42 @@ namespace geode::event::v3 {
111
134
return std::ranges::subrange (begin, end) | std::views::transform (getSecond);
112
135
}
113
136
114
- void addListener (EventType* event, CallbackType callback) {
137
+ protected:
138
+ void callListener (void * e, void * p) override {
139
+ auto event = static_cast <EventType*>(e);
140
+
141
+ auto listeners = this ->getListeners (event);
142
+ for (auto const & listener : listeners) {
143
+ this ->call (&listener, p);
144
+ }
145
+ }
146
+
147
+ void addListener (void * e, void * c) override {
148
+ auto event = static_cast <EventType*>(e);
149
+ auto callback = static_cast <CallbackType*>(c);
150
+
115
151
auto const hash = std::hash<EventType>{}(*event);
116
- listeners.emplace (hash, std::move (callback));
152
+ listeners.emplace (hash, std::move (* callback));
117
153
}
118
154
119
- void removeListener (EventType* event) {
155
+ void removeListener (void * e) override {
156
+ auto event = static_cast <EventType*>(e);
157
+
120
158
auto const hash = std::hash<EventType>{}(*event);
121
159
listeners.erase (hash);
122
160
}
123
161
124
- void moveListener (EventType * from, EventType * to) {}
162
+ void moveListener (void * from, void * to) override {}
125
163
};
126
164
127
- template <class E , class C >
128
- class EqualityComparablePool {
165
+ template <class E , class ... Args >
166
+ class EqualityComparablePool : public Pool , public ForwardHelper <Args...> {
129
167
protected:
130
168
using EventType = E;
131
- using CallbackType = std::function<C>;
132
169
133
170
private:
134
171
std::vector<std::pair<EventType*, CallbackType>> listeners;
135
172
136
- protected:
137
173
auto getListeners (EventType* event) const {
138
174
auto isEvent = [event](auto const & pair) {
139
175
return pair.first ->operator ==(*event);
@@ -144,17 +180,35 @@ namespace geode::event::v3 {
144
180
return std::ranges::filter_view (listeners, isEvent) | std::views::transform (getSecond);
145
181
}
146
182
147
- void addListener (EventType* event, CallbackType callback) {
148
- listeners.emplace_back (event, std::move (callback));
183
+ protected:
184
+ void callListener (void * e, void * p) override {
185
+ auto event = static_cast <EventType*>(e);
186
+
187
+ auto listeners = this ->getListeners (event);
188
+ for (auto const & listener : listeners) {
189
+ this ->call (&listener, p);
190
+ }
191
+ }
192
+
193
+ void addListener (void * e, void * c) override {
194
+ auto event = static_cast <EventType*>(e);
195
+ auto callback = static_cast <CallbackType*>(c);
196
+
197
+ listeners.emplace_back (event, std::move (*callback));
149
198
}
150
199
151
- void removeListener (EventType* event) {
200
+ void removeListener (void * e) override {
201
+ auto event = static_cast <EventType*>(e);
202
+
152
203
std::erase_if (listeners, [&event](auto const & pair) {
153
204
return pair.first == event;
154
205
});
155
206
}
156
207
157
- void moveListener (EventType* from, EventType* to) {
208
+ void moveListener (void * f, void * t) override {
209
+ auto from = static_cast <EventType*>(f);
210
+ auto to = static_cast <EventType*>(t);
211
+
158
212
std::ranges::for_each (listeners, [&](auto & pair) {
159
213
if (pair.first == from) {
160
214
pair.first = to;
@@ -163,39 +217,14 @@ namespace geode::event::v3 {
163
217
}
164
218
};
165
219
166
- template <class PoolType >
167
220
class Event {
168
221
public:
169
- using CallbackType = typename PoolType::CallbackType;
170
- using EventType = typename PoolType::EventType;
171
-
172
- protected:
173
- static inline PoolType pool;
174
-
175
- EventType* self () {
176
- return static_cast <EventType*>(this );
177
- }
222
+ virtual Pool* getPool () = 0;
178
223
179
224
private:
180
225
bool moved;
181
226
182
227
public:
183
- template <class ... Args>
184
- void post (Args&&... args) {
185
- pool.callListeners (self (), std::forward<Args>(args)...);
186
- }
187
-
188
- EventType listen (CallbackType callback) && {
189
- moved = false ;
190
- pool.addListener (self (), std::move (callback));
191
- return std::move (*self ());
192
- }
193
-
194
- EventType& listen (CallbackType callback) & {
195
- moved = false ;
196
- pool.addListener (self (), std::move (callback));
197
- return *self ();
198
- }
199
228
200
229
Event () : moved(true ) {}
201
230
Event (Event const &) = delete ;
@@ -219,22 +248,43 @@ namespace geode::event::v3 {
219
248
using namespace geode ::event::v3;
220
249
}
221
250
222
- class TestEvent : public Event <Pool<EqualityComparablePool<TestEvent, void (std::string_view)>>> {
251
+ class TestEvent : public Event {
252
+ private:
253
+ static inline EqualityComparablePool<TestEvent, std::string_view> s_pool;
254
+
223
255
public:
224
256
std::optional<size_t > key;
225
257
226
258
TestEvent () : key() {}
227
259
TestEvent (size_t key) : key(key) {}
228
260
261
+ template <class ... Args>
262
+ void post (Args&&... args) {
263
+ pool.callListeners (self (), std::forward<Args>(args)...);
264
+ }
265
+
266
+ TestEvent listen (std::invocable auto callback) && {
267
+ moved = false ;
268
+ pool.addListener (self (), std::move (callback));
269
+ return std::move (*this );
270
+ }
271
+
272
+ TestEvent& listen (CallbackType callback) & {
273
+ moved = false ;
274
+ pool.addListener (self (), std::move (callback));
275
+ return *this ;
276
+ }
277
+
229
278
bool operator ==(TestEvent const & other) {
230
279
if (!key) {
231
280
return true ;
232
281
}
233
- if (!other.key ) {
234
- return false ;
235
- }
236
282
return *key == *other.key ;
237
283
}
284
+
285
+ Pool* getPool () override {
286
+ return &s_pool;
287
+ }
238
288
};
239
289
}
240
290
0 commit comments