From a6691ef539d3738333273c1096a3feec40d9feae Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Wed, 24 Jul 2019 00:16:31 +0800 Subject: ... --- .clang-format | 2 ++ include/cru/common/event.hpp | 57 ++++++++++++++++------------------ include/cru/common/self_resolvable.hpp | 36 ++++++++++----------- include/cru/ui/window.hpp | 2 +- src/CMakeLists.txt | 2 +- 5 files changed, 48 insertions(+), 51 deletions(-) diff --git a/.clang-format b/.clang-format index f6cb8ad9..b455db81 100644 --- a/.clang-format +++ b/.clang-format @@ -1 +1,3 @@ BasedOnStyle: Google + +IncludeBlocks: Preserve \ No newline at end of file diff --git a/include/cru/common/event.hpp b/include/cru/common/event.hpp index 2e4b82b4..50918dd0 100644 --- a/include/cru/common/event.hpp +++ b/include/cru/common/event.hpp @@ -3,9 +3,8 @@ #include "self_resolvable.hpp" -#include +#include #include -#include #include #include @@ -17,7 +16,7 @@ namespace details { // It erases event args types and provides a // unified form to create event revoker and // revoke(remove) handler. -class EventBase : public SelfResovable { +class EventBase : public SelfResolvable { friend EventRevoker; protected: @@ -46,7 +45,7 @@ class EventRevoker { friend details::EventBase; private: - EventRevoker(ObjectResovler&& resolver, + EventRevoker(ObjectResolver&& resolver, details::EventBase::EventHandlerToken token) : resolver_(std::move(resolver)), token_(token) {} @@ -68,7 +67,7 @@ class EventRevoker { } private: - ObjectResovler resolver_; + ObjectResolver resolver_; details::EventBase::EventHandlerToken token_; }; @@ -85,11 +84,6 @@ using DeducedEventArgs = std::conditional_t< std::conditional_t, TRaw, const TRaw&>>; // Provides an interface of event. -// -// Note that this class does not inherit Interface because Interface is -// public destructable, but I want to make this class not public -// destructable to prevent user from destructing it. -// // IEvent only allow to add handler but not to raise the event. You may // want to create an Event object and expose IEvent only so users won't // be able to emit the event. @@ -117,6 +111,7 @@ struct IEvent { template class Event : public details::EventBase, public IEvent { using typename IEvent::EventHandler; + private: struct HandlerData { HandlerData(EventHandlerToken token, EventHandler handler) @@ -135,45 +130,45 @@ class Event : public details::EventBase, public IEvent { EventRevoker AddHandler(const EventHandler& handler) override { const auto token = current_token_++; - handlers_->emplace_back(token, handler); + this->handler_data_list_.emplace_after(this->last_handler_iterator_ ,token, handler); + ++(this->last_handler_iterator_); return CreateRevoker(token); } EventRevoker AddHandler(EventHandler&& handler) override { const auto token = current_token_++; - handlers_->emplace_back(token, std::move(handler)); + this->handler_data_list_.emplace_after(this->last_handler_iterator_ ,token, std::move(handler)); + ++(this->last_handler_iterator_); return CreateRevoker(token); } + // This method will make a copy of all handlers. Because user might delete a + // handler in a handler, which may lead to seg fault as the handler is deleted + // while being executed. + // Thanks to this behavior, all handlers will be taken a snapshot when Raise + // is called, so even if you delete a handler during this period, all handlers + // in the snapshot will be executed. void Raise(EventArgs args) { - // Make a copy of the shared_ptr to retain the handlers in case the event is - // deleted during executing. if the handler is a lambda with member data, - // then the member data will be destroyed and result in seg fault. - const auto handlers = handlers_; - // do not use range for because it is not safe when current node is deleted. - auto i = handlers->cbegin(); - while (i != handlers->cend()) { - // first move the i forward. - const auto current = i++; - // The same as above but in case that the RemoveHandler is called and - // the handler is not valid then. - const auto handler = current->handler; + std::forward_list handlers; + auto iter = handlers.cbefore_begin(); + for (const auto& data : this->handler_data_list_) { + handlers.insert_after(iter, data.handler); + iter++; + } + for (const auto& handler : handlers) { handler(args); } } protected: void RemoveHandler(EventHandlerToken token) override { - auto find_result = std::find_if(handlers_->cbegin(), handlers_->cend(), - [token](const HandlerData& handler_data) { - return handler_data.token == token; - }); - if (find_result != handlers_->cend()) handlers_->erase(find_result); + this->handler_data_list_.remove_if( + [token](const HandlerData& data) { return data.token == token; }); } private: - std::shared_ptr> handlers_ = - std::make_shared>(); + std::forward_list handler_data_list_{}; + typename std::forward_list::const_iterator last_handler_iterator_ = this->handler_data_list_.cbefore_begin(); // remember the last handler to make push back O(1) EventHandlerToken current_token_ = 0; }; diff --git a/include/cru/common/self_resolvable.hpp b/include/cru/common/self_resolvable.hpp index 3e9d74ed..708fea50 100644 --- a/include/cru/common/self_resolvable.hpp +++ b/include/cru/common/self_resolvable.hpp @@ -7,21 +7,21 @@ namespace cru { template -class SelfResovable; +class SelfResolvable; template -class ObjectResovler { - friend SelfResovable; +class ObjectResolver { + friend SelfResolvable; private: - ObjectResovler(const std::shared_ptr& resolver) : resolver_(resolver) {} + ObjectResolver(const std::shared_ptr& resolver) : resolver_(resolver) {} public: - ObjectResovler(const ObjectResovler&) = default; - ObjectResovler& operator=(const ObjectResovler&) = default; - ObjectResovler(ObjectResovler&&) = default; - ObjectResovler& operator=(ObjectResovler&&) = default; - ~ObjectResovler() = default; + ObjectResolver(const ObjectResolver&) = default; + ObjectResolver& operator=(const ObjectResolver&) = default; + ObjectResolver(ObjectResolver&&) = default; + ObjectResolver& operator=(ObjectResolver&&) = default; + ~ObjectResolver() = default; T* Resolve() const { // resolver_ is null only when this has been moved. @@ -35,16 +35,16 @@ class ObjectResovler { }; template -class SelfResovable { +class SelfResolvable { public: - SelfResovable() : resolver_(new T*(static_cast(this))) {} - SelfResovable(const SelfResovable&) = delete; - SelfResovable& operator=(const SelfResovable&) = delete; - SelfResovable(SelfResovable&&) = delete; - SelfResovable& operator=(SelfResovable&&) = delete; - virtual ~SelfResovable() { (*resolver_) = nullptr; } - - ObjectResovler CreateResolver() { return ObjectResovler(resolver_); } + SelfResolvable() : resolver_(new T*(static_cast(this))) {} + SelfResolvable(const SelfResolvable&) = delete; + SelfResolvable& operator=(const SelfResolvable&) = delete; + SelfResolvable(SelfResolvable&&) = delete; + SelfResolvable& operator=(SelfResolvable&&) = delete; + virtual ~SelfResolvable() { (*resolver_) = nullptr; } + + ObjectResolver CreateResolver() { return ObjectResolver(resolver_); } private: std::shared_ptr resolver_; diff --git a/include/cru/ui/window.hpp b/include/cru/ui/window.hpp index 311f1487..197198d2 100644 --- a/include/cru/ui/window.hpp +++ b/include/cru/ui/window.hpp @@ -17,7 +17,7 @@ namespace render { class WindowRenderObject; } -class Window final : public ContentControl, public SelfResovable { +class Window final : public ContentControl, public SelfResolvable { public: static constexpr auto control_type = L"Window"; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 50092e1c..0507ee2b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,7 +46,7 @@ target_sources(cru_platform_native INTERFACE target_link_libraries(cru_platform_native INTERFACE cru_platform_graph) if(WIN32) -add_subdirectory(win) + add_subdirectory(win) endif() add_subdirectory(ui) -- cgit v1.2.3