Files
render/template/include/event.hpp
T
2026-08-17 06:31:43 +09:00

111 lines
3.0 KiB
C++

/**
* 这是一个线程不安全(单线程)版的event,不可以用于多线程
*/
#ifndef ZCPPWIN_EVENT_HPP
#define ZCPPWIN_EVENT_HPP
#include <cstdint>
#include <functional>
#include <memory>
#include <unordered_map>
#include <vector>
#include <utility>
namespace Z {
template<typename... Args>
class Event {
public:
using Callback = std::function<void(Args...)>;
private: //region Event::private
struct Handle {
uint64_t id{};
std::weak_ptr<void> guard;
Callback cb;
};
struct State {
uint64_t nextID{1};
};
void Disconn_(uint64_t id) {
m_handles.erase(id);
}
static bool IsAlive(Handle &h) {
// guard为null->活
if (!h.guard.owner_before(std::weak_ptr<void>{}) &&
!std::weak_ptr<void>{}.owner_before(h.guard)) {
return true;
}
// guard非null且已死->死
if (h.guard.expired())return false;
// guard非null且活->活
return true;
}
private:
std::shared_ptr<State> m_state;
std::unordered_map<uint64_t, Handle> m_handles;
public:
class Connection { //region class Connection
public:
Connection() = default;
Connection(const Connection &) = delete;
Connection &operator=(const Connection &) = delete;
Connection(Connection &&other) noexcept { MoveFrom(std::move(other)); }
Connection &operator=(Connection &&other) noexcept {
if (this != &other) {
Disconnect();
MoveFrom(std::move(other));
}
return *this;
}
~Connection() { Disconnect(); }
private:
friend class Event;
Connection(uint64_t id, Event *owner, std::weak_ptr<State> wp) :
m_id(id), m_owner(owner), guard_state(wp) {}
void Disconnect() {
if (m_id == 0 || guard_state.expired()) { return; }
m_owner->Disconn_(m_id);
m_id = 0;
}
void MoveFrom(Connection &&other) noexcept {
m_owner = other.m_owner;
m_id = other.m_id;
other.m_owner = nullptr;
other.m_id = 0;
}
private:
uint64_t m_id;
Event *m_owner;
const std::weak_ptr<State> guard_state;
}; //Class Connection
Event() {
m_state = std::make_shared<State>();
}
Connection Subscribe(Callback cb) {
Handle h{m_state->nextID++, {}, std::move(cb)};
m_handles.emplace(h.id, std::move(h));
return {h.id, this, std::weak_ptr{m_state}};
}
void EmitEvent(Args... args) {
std::vector<uint64_t> cleanIds{};
for (auto &kv: m_handles) {
if (!IsAlive(kv.second)) {
cleanIds.push_back(kv.first);
} else {
kv.second.cb(args...);
}
}
if (!cleanIds.empty()) {
for (auto &id: cleanIds) {
m_handles.erase(id);
}
}
}
};
}
#endif //ZCPPWIN_EVENT_HPP