Initial commit.
This commit is contained in:
commit
cb0391ce80
56 changed files with 3485 additions and 0 deletions
91
Shared/Events.h
Normal file
91
Shared/Events.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <typeindex>
|
||||
#include <any>
|
||||
#include <algorithm>
|
||||
|
||||
class EventTarget {
|
||||
public:
|
||||
template<typename T>
|
||||
using Callback = std::function<void(const T &)>;
|
||||
|
||||
// Subscribe to an event type.
|
||||
template<typename T>
|
||||
uint64_t listen(Callback<T> callback) {
|
||||
auto type = std::type_index(typeid(T));
|
||||
auto & vec = callbacks[type];
|
||||
|
||||
uint64_t id = nextEventId++;
|
||||
|
||||
vec.emplace_back([cb = std::move(callback)](const std::any & e) {
|
||||
cb(std::any_cast<const T &>(e));
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
// Unsubscribe a specific listener.
|
||||
template<typename T>
|
||||
void unlisten(uint64_t id) {
|
||||
_unlisten(std::type_index(typeid(T)), id);
|
||||
}
|
||||
|
||||
// Synchronously dispatch an event.
|
||||
template<typename T>
|
||||
void dispatch(const T & event) {
|
||||
auto it = callbacks.find(std::type_index(typeid(T)));
|
||||
if (it == callbacks.end()) return;
|
||||
|
||||
// Copy the list in case a callback unsubscribes during dispatch.
|
||||
auto copy = it->second;
|
||||
for (const auto & cb : copy) {
|
||||
cb(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Should be called on a main loop to dispatch queued events.
|
||||
void processQueue() {
|
||||
for (auto & [anyEvent, copy] : queued) {
|
||||
auto it = callbacks.find(anyEvent.type());
|
||||
if (it != callbacks.end()) {
|
||||
for (const auto & cb : copy) {
|
||||
cb(anyEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
queued.clear();
|
||||
}
|
||||
|
||||
// Queue an event to be dispatched on the next call to `processQueue`.
|
||||
template<typename T>
|
||||
void queue(const T & event) {
|
||||
auto type = std::type_index(typeid(T));
|
||||
auto it = callbacks.find(type);
|
||||
if (it == callbacks.end()) return;
|
||||
queued.emplace_back(std::any(event), it->second);
|
||||
}
|
||||
|
||||
private:
|
||||
using AnyCallback = std::function<void(const std::any &)>;
|
||||
using CallbackWithId = std::pair<AnyCallback, uint64_t>;
|
||||
|
||||
std::unordered_map<std::type_index, std::vector<AnyCallback>> callbacks {};
|
||||
std::vector<std::pair<std::any, std::vector<AnyCallback>>> queued {};
|
||||
|
||||
uint64_t nextEventId = 0;
|
||||
|
||||
void _unlisten(std::type_index type, uint64_t id) {
|
||||
// auto it = callbacks.find(type);
|
||||
// if (it == callbacks.end()) return;
|
||||
//
|
||||
// auto & vec = it->second;
|
||||
// auto erase_it = std::find_if(vec.begin(), vec.end(),
|
||||
// [id](const auto& p) { return p.second == id; });
|
||||
//
|
||||
// if (erase_it != vec.end()) {
|
||||
// *erase_it = std::move(vec.back());
|
||||
// vec.pop_back();
|
||||
// }
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue