aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2019-05-23 23:07:27 +0800
committercrupest <crupest@outlook.com>2019-05-23 23:07:27 +0800
commit9c2ece689c580f6857f50a81c09d423e6fed4a83 (patch)
treefb3e01fb00fbdbe76d052ee4e46392032848c884 /include
parent691918e9e25b4f7e4731ff8d0e563c6316160254 (diff)
downloadcru-9c2ece689c580f6857f50a81c09d423e6fed4a83.tar.gz
cru-9c2ece689c580f6857f50a81c09d423e6fed4a83.tar.bz2
cru-9c2ece689c580f6857f50a81c09d423e6fed4a83.zip
...
Diffstat (limited to 'include')
-rw-r--r--include/cru/common/event.hpp76
-rw-r--r--include/cru/ui/window.hpp3
2 files changed, 53 insertions, 26 deletions
diff --git a/include/cru/common/event.hpp b/include/cru/common/event.hpp
index 741dcd99..ff99e745 100644
--- a/include/cru/common/event.hpp
+++ b/include/cru/common/event.hpp
@@ -11,37 +11,45 @@ namespace cru {
class EventRevoker;
namespace details {
+// Base class of all Event<T...>.
+// It erases event args types and provides a
+// unified form to create event revoker and
+// revoke(remove) handler.
class EventBase {
friend EventRevoker;
protected:
using EventHandlerToken = long;
- EventBase() : resolve_ptr_(new std::reference_wrapper(*this)) {}
-
+ EventBase() : resolver_(new EventBase*(this)) {}
EventBase(const EventBase& other) = delete;
EventBase(EventBase&& other) = delete;
EventBase& operator=(const EventBase& other) = delete;
EventBase& operator=(EventBase&& other) = delete;
virtual ~EventBase() = default;
+ // Remove the handler with the given token. If the token
+ // corresponds to no handler (which might have be revoked
+ // before), then nothing will be done.
virtual void RemoveHandler(EventHandlerToken token) = 0;
+ // Create a revoker with the given token.
inline EventRevoker CreateRevoker(EventHandlerToken token);
private:
- std::shared_ptr<std::reference_wrapper<EventBase>> resolve_ptr_;
+ std::shared_ptr<EventBase*> resolver_;
};
} // namespace details
+// A copyable and movable event revoker.
+// Call function call operator to revoke the handler.
class EventRevoker {
friend class ::cru::details::EventBase;
private:
- EventRevoker(const std::shared_ptr<
- std::reference_wrapper<details::EventBase>>& resolve_ptr,
+ EventRevoker(const std::shared_ptr<details::EventBase*>& resolver,
details::EventBase::EventHandlerToken token)
- : weak_ptr_(resolve_ptr), token_(token) {}
+ : weak_resolver_(resolver), token_(token) {}
public:
EventRevoker(const EventRevoker& other) = default;
@@ -50,20 +58,25 @@ class EventRevoker {
EventRevoker& operator=(EventRevoker&& other) = default;
~EventRevoker() = default;
+ // Revoke the registered handler. If the event has already
+ // been destroyed, then nothing will be done. If one of the
+ // copies calls this, then other copies's calls will have no
+ // effect. (They have the same token.)
void operator()() const {
- const auto true_resolver = weak_ptr_.lock();
+ const auto true_resolver = weak_resolver_.lock();
+ // if true_resolver is nullptr, then the event has been destroyed.
if (true_resolver) {
- (*true_resolver).get().RemoveHandler(token_);
+ (*true_resolver)->RemoveHandler(token_);
}
}
private:
- std::weak_ptr<std::reference_wrapper<details::EventBase>> weak_ptr_;
+ std::weak_ptr<details::EventBase*> weak_resolver_;
details::EventBase::EventHandlerToken token_;
};
inline EventRevoker details::EventBase::CreateRevoker(EventHandlerToken token) {
- return EventRevoker(resolve_ptr_, token);
+ return EventRevoker(resolver_, token);
}
// A non-copyable non-movable Event class.
@@ -92,19 +105,24 @@ class Event : public details::EventBase {
return CreateRevoker(token);
}
- template <typename Arg>
- EventRevoker AddHandler(Arg&& handler) {
- static_assert(std::is_invocable_v<Arg, TArgs...>, "Handler not invocable.");
+ template <typename FArg>
+ EventRevoker AddHandler(FArg&& handler) {
+ static_assert(std::is_invocable_v<FArg, TArgs...>,
+ "Handler not invocable.");
const auto token = current_token_++;
- handlers_.emplace(token, EventHandler(std::forward<Arg>(handler)));
+ handlers_.emplace(token, EventHandler(std::forward<FArg>(handler)));
return CreateRevoker(token);
}
- template <typename... Args>
- void Raise(Args&&... args) {
+ template <typename... FArg>
+ void Raise(FArg&&... args) {
+ // copy the handlers to a list, because the handler might be removed
+ // during executing, and the handler with its data will be destroyed.
+ // if the handler is a lambda with member data, then the member data
+ // will be destroyed and result in seg fault.
std::list<EventHandler> handlers;
for (const auto& [key, handler] : handlers_) handlers.push_back(handler);
- for (const auto& handler : handlers) handler(std::forward<Args>(args)...);
+ for (const auto& handler : handlers) handler(std::forward<FArg>(args)...);
}
protected:
@@ -118,20 +136,28 @@ class Event : public details::EventBase {
EventHandlerToken current_token_ = 0;
};
+namespace details {
+struct EventRevokerGuardDestroyer {
+ void operator()(EventRevoker* p) const {
+ (*p)();
+ delete p;
+ }
+};
+} // namespace details
+
class EventRevokerGuard {
public:
- EventRevokerGuard() = default;
+ explicit EventRevokerGuard(EventRevoker revoker)
+ : revoker_(new EventRevoker(std::move(revoker))) {}
EventRevokerGuard(const EventRevokerGuard& other) = delete;
- EventRevokerGuard(EventRevokerGuard&& other) = delete;
+ EventRevokerGuard(EventRevokerGuard&& other) = default;
EventRevokerGuard& operator=(const EventRevokerGuard& other) = delete;
- EventRevokerGuard& operator=(EventRevokerGuard&& other) = delete;
- ~EventRevokerGuard() {
- for (const auto revoker : revokers_) revoker();
- }
+ EventRevokerGuard& operator=(EventRevokerGuard&& other) = default;
+ ~EventRevokerGuard() = default;
- void Add(EventRevoker revoker) { revokers_.push_back(std::move(revoker)); }
+ EventRevoker Get() const { return *revoker_; }
private:
- std::list<EventRevoker> revokers_;
+ std::unique_ptr<EventRevoker, details::EventRevokerGuardDestroyer> revoker_;
};
} // namespace cru
diff --git a/include/cru/ui/window.hpp b/include/cru/ui/window.hpp
index 0a81e2e1..140ac531 100644
--- a/include/cru/ui/window.hpp
+++ b/include/cru/ui/window.hpp
@@ -4,6 +4,7 @@
#include "event/ui_event.hpp"
#include <memory>
+#include <vector>
namespace cru::platform::native {
struct NativeWindow;
@@ -82,7 +83,7 @@ class Window final : public ContentControl {
private:
platform::native::NativeWindow* native_window_;
- EventRevokerGuard event_revoker_guard_;
+ std::vector<EventRevokerGuard> event_revoker_guards_;
std::shared_ptr<render::WindowRenderObject> render_object_;