/** * 这是一个线程不安全(单线程)版的event,不可以用于多线程 */ #ifndef ZCPPWIN_EVENT_HPP #define ZCPPWIN_EVENT_HPP #include #include #include #include #include #include namespace Z { template class Event { public: using Callback = std::function; private: //region Event::private struct Handle { uint64_t id{}; std::weak_ptr 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{}) && !std::weak_ptr{}.owner_before(h.guard)) { return true; } // guard非null且已死->死 if (h.guard.expired())return false; // guard非null且活->活 return true; } private: std::shared_ptr m_state; std::unordered_map 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 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 guard_state; }; //Class Connection Event() { m_state = std::make_shared(); } 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 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