#pragma once #include "base.hpp" #include #include #include #include namespace cru { using EventHandlerRevoker = std::function; // A non-copyable non-movable Event class. // It stores a list of event handlers. template class Event { private: using EventResolver = std::function; class EventHandlerRevokerImpl { public: EventHandlerRevokerImpl(const std::shared_ptr& resolver, long token) : resolver_(resolver), token_(token) {} EventHandlerRevokerImpl(const EventHandlerRevokerImpl& other) = default; EventHandlerRevokerImpl(EventHandlerRevokerImpl&& other) = default; EventHandlerRevokerImpl& operator=(EventHandlerRevokerImpl&& other) = default; EventHandlerRevokerImpl& operator=(EventHandlerRevokerImpl&& other) = default; ~EventHandlerRevokerImpl() = default; void operator()() { const auto true_resolver = resolver_.lock(); if (true_resolver) { true_resolver()->RemoveHandler(token_); } } private: std::weak_ptr resolver_; long token_; }; public: using EventHandler = std::function; Event() : event_resolver_(new std::function([this] { return this; })) {} Event(const Event&) = delete; Event& operator=(const Event&) = delete; Event(Event&&) = delete; Event& operator=(Event&&) = delete; ~Event() = default; EventHandlerRevoker AddHandler(const EventHandler& handler) { const auto token = current_token_++; handlers_.emplace(token, handler); return EventHandlerRevoker(EventHandlerRevokerImpl(event_resolver_, token)); } template EventHandlerRevoker AddHandler(Args&& args...) { const auto token = current_token_++; handlers_.emplace(token, EventHandler(std::forward(args)...)); return EventHandlerRevoker(EventHandlerRevokerImpl(event_resolver_, token)); } template void Raise(Args&&... args) { for (const auto& handler : handlers_) (handler.second)(std::forward(args)...); } private: void RemoveHandler(const long token) { auto find_result = handlers_.find(token); if (find_result != handlers_.cend()) handlers_.erase(find_result); } private: std::map handlers_{}; long current_token_ = 0; std::shared_ptr event_resolver_; }; } // namespace cru