#pragma once #include #include #include #include #include namespace extra2d::event { /** * @brief 监听器链表节点 */ struct ListenerEntry { ListenerEntry* next = nullptr; ListenerEntry* prev = nullptr; class ListenerBase* listener = nullptr; }; /** * @brief 监听器基类 */ class ListenerBase { protected: ListenerEntry* entry_ = nullptr; friend class ListenerContainer; }; /** * @brief 监听器容器,管理同一事件的所有监听器 */ class ListenerContainer { public: ListenerContainer() = default; ~ListenerContainer(); template bool broadcast(Args&&... args); protected: ListenerEntry* listenerList_ = nullptr; ListenerEntry* listenersToAdd_ = nullptr; std::vector listenersToRemove_; int broadcasting_ = 0; void addListener(ListenerBase* listener); void removeListener(ListenerBase* listener); void processPendingListeners(); bool hasPendingListeners() const; template friend class Listener; }; /** * @brief 事件处理器数据库,每个事件类型一个容器 */ template class ListenerDB { public: static ListenerContainer* container() { static ListenerContainer* ctn = new ListenerContainer(); return ctn; } }; /** * @brief 事件特征定义 */ template struct EventTrait { using Bus = BusT; using ArgTuple = std::tuple; static constexpr size_t ARG_COUNT = sizeof...(Args); }; /** * @brief 元组提取器 */ template struct TupleExtractor { using FuncType = void(); using StdFuncType = std::function; }; template struct TupleExtractor> { using FuncType = void(Args...); using StdFuncType = std::function; }; /** * @brief 监听器模板类 * * 构造时自动注册,析构时自动注销 */ template class Listener : public ListenerBase { public: using ArgTuple = typename EHandler::ArgTuple; using StdFuncType = typename TupleExtractor::StdFuncType; Listener(); ~Listener(); template void bind(Fn&& func) { callback_ = std::forward(func); } void enable() { enabled_ = true; } void disable() { enabled_ = false; } bool isEnabled() const { return enabled_; } void reset() { callback_ = nullptr; } template void invoke(Args&&... args) { if (callback_ && enabled_) { callback_(std::forward(args)...); } } const char* busName() const { return EHandler::BUS_NAME; } const char* eventName() const { return EHandler::NAME; } private: bool enabled_ = true; StdFuncType callback_; }; template Listener::Listener() { entry_ = new ListenerEntry(); entry_->listener = this; ListenerDB::container()->addListener(this); } template Listener::~Listener() { ListenerDB::container()->removeListener(this); } #define EVENT_LIST_LOOP_BEGIN(curr, list) \ for (ListenerEntry* curr = list; curr != nullptr; curr = curr->next) { #define EVENT_LIST_LOOP_END(curr, list) } template bool ListenerContainer::broadcast(Args&&... args) { broadcasting_++; EVENT_LIST_LOOP_BEGIN(curr, listenerList_) if (curr->listener) { static_cast*>(curr->listener)->invoke(std::forward(args)...); } EVENT_LIST_LOOP_END(curr, listenerList_) broadcasting_--; if (!broadcasting_ && hasPendingListeners()) { processPendingListeners(); } return true; } /** * @brief 广播事件 */ template void broadcast(Args&&... args) { static_assert(sizeof...(Args) == EHandler::ARG_COUNT, "Parameter count incorrect"); auto* container = ListenerDB::container(); container->template broadcast(std::forward(args)...); } } // namespace extra2d::event