#pragma once #include #include #include #include #include #include #include namespace cru { class Event2Base { public: virtual ~Event2Base() = default; virtual void RevokeHandler(int token_value) = 0; }; template class EventContext { public: EventContext() : argument_(), result_() {} explicit EventContext(TArgument argument) : argument_(std::move(argument)), result_() {} EventContext(TArgument argument, TResult result) : argument_(std::move(argument)), result_(std::move(result)) {} TArgument& GetArgument() { return argument_; } const TArgument& GetArgument() const { return argument_; } TResult& GetResult() { return result_; } const TResult& GetResult() const { return result_; } void SetResult(const TResult& result) { result_ = result; } void SetResult(TResult&& result) { result_ = std::move(result); } TResult TakeResult() { return std::move(result_); } bool GetStopHandling() const { return stop_handling_; } void SetStopHandling(bool stop = true) { stop_handling_ = stop; } private: TArgument argument_; TResult result_; bool stop_handling_ = false; }; template class Event2; template constexpr bool is_event2_v = false; template constexpr bool is_event2_v> = true; class EventHandlerToken { public: EventHandlerToken(ObjectResolver event_resolver, int token_value) : event_resolver_(std::move(event_resolver)), token_value_(token_value) {} ObjectResolver GetEventResolver() const { return event_resolver_; } int GetTokenValue() const { return token_value_; } inline void RevokeHandler() const; private: ObjectResolver event_resolver_; int token_value_; }; namespace details { struct Event2BehaviorFlagTag {}; } // namespace details using Event2BehaviorFlag = Bitmask; struct Event2BehaviorFlags { /** * @brief Make a copy of handler list before invoking handlers. So the event * object or its owner can be destroyed during running handlers. */ static constexpr Event2BehaviorFlag CopyHandlers = Event2BehaviorFlag::FromOffset(1); }; template class Event2 : public Event2Base, public SelfResolvable> { public: using HandlerToken = EventHandlerToken; using Context = EventContext; using Handler = std::function; using SpyOnlyHandler = std::function; template static std::enable_if_t, Handler> WrapAsHandler( TFunc&& handler) { return Handler([h = std::forward(handler)](Context*) { h(); }); } template static std::enable_if_t, Handler> WrapAsHandler(TFunc&& handler) { return Handler(std::forward(handler)); } private: struct HandlerData { int token_value; Handler handler; }; public: explicit Event2(Event2BehaviorFlag flags = {}) : flags_(flags) {} Event2(const Event2&) = delete; Event2(Event2&&) = delete; Event2& operator=(const Event2&) = delete; Event2& operator=(Event2&&) = delete; ~Event2() override = default; public: template HandlerToken AddHandler(TFunc&& handler) { auto token = this->current_token_value_++; auto real_handler = WrapAsHandler(std::forward(handler)); HandlerData handler_data{token, std::move(real_handler)}; this->handlers_.push_back(std::move(handler_data)); return HandlerToken(this->CreateResolver(), token); } void RevokeHandler(int token_value) override { auto iter = this->handlers_.cbegin(); auto end = this->handlers_.cend(); for (; iter != end; ++iter) { if (iter->token_value == token_value) { this->handlers_.erase(iter); break; } } } void RevokeHandler(const HandlerToken& token) { return RevokeHandler(token.GetTokenValue()); } TResult Raise() { Context context; RunInContext(&context); return context.TakeResult(); } TResult Raise(TArgument argument) { Context context(std::move(argument)); RunInContext(&context); return context.TakeResult(); } TResult Raise(TArgument argument, TResult result) { Context context(std::move(argument), std::move(result)); RunInContext(&context); return context.TakeResult(); } private: void RunInContext(Context* context) { if (this->flags_ & Event2BehaviorFlags::CopyHandlers) { std::vector handlers_copy; for (const auto& handler : this->handlers_) { handlers_copy.push_back(handler.handler); } for (const auto& handler : handlers_copy) { if (context->GetStopHandling()) { break; } handler(context); } } else { for (const auto& handler : this->handlers_) { if (context->GetStopHandling()) { break; } handler.handler(context); } } } private: int current_token_value_ = 1; std::vector handlers_; Event2BehaviorFlag flags_; }; inline void EventHandlerToken::RevokeHandler() const { auto event = this->event_resolver_.Resolve(); if (event) { event->RevokeHandler(this->token_value_); } } } // namespace cru