aboutsummaryrefslogtreecommitdiff
path: root/include/cru/common/event.hpp
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2019-06-26 22:45:27 +0800
committercrupest <crupest@outlook.com>2019-06-26 22:45:27 +0800
commitf404a3b2eb7bb9865d0c6f938538899996a53d8c (patch)
tree63fd179086c5e482a878a5207f6d4b105d4098cd /include/cru/common/event.hpp
parent35abeab46fb0ccb115d10e73315e3251cc9dc880 (diff)
downloadcru-f404a3b2eb7bb9865d0c6f938538899996a53d8c.tar.gz
cru-f404a3b2eb7bb9865d0c6f938538899996a53d8c.tar.bz2
cru-f404a3b2eb7bb9865d0c6f938538899996a53d8c.zip
...
Diffstat (limited to 'include/cru/common/event.hpp')
-rw-r--r--include/cru/common/event.hpp47
1 files changed, 33 insertions, 14 deletions
diff --git a/include/cru/common/event.hpp b/include/cru/common/event.hpp
index cc21cb91..d08bcbea 100644
--- a/include/cru/common/event.hpp
+++ b/include/cru/common/event.hpp
@@ -3,9 +3,9 @@
#include "self_resolvable.hpp"
+#include <algorithm>
#include <functional>
#include <list>
-#include <map>
#include <memory>
#include <utility>
@@ -43,7 +43,7 @@ class EventBase : private SelfResovable<EventBase> {
// A non-copyable and movable event revoker.
// Call function call operator to revoke the handler.
class EventRevoker {
- friend class ::cru::details::EventBase;
+ friend details::EventBase;
private:
EventRevoker(ObjectResovler<details::EventBase>&& resolver,
@@ -116,6 +116,14 @@ struct IEvent {
// It stores a list of event handlers.
template <typename TEventArgs>
class Event : public details::EventBase, public IEvent<TEventArgs> {
+ private:
+ struct HandlerData {
+ HandlerData(EventHandlerToken token, EventHandler handler)
+ : token(token), handler(handler) {}
+ EventHandlerToken token;
+ EventHandler handler;
+ };
+
public:
Event() = default;
Event(const Event&) = delete;
@@ -126,34 +134,45 @@ class Event : public details::EventBase, public IEvent<TEventArgs> {
EventRevoker AddHandler(const EventHandler& handler) override {
const auto token = current_token_++;
- handlers_.emplace(token, handler);
+ handlers_->emplace_back(token, handler);
return CreateRevoker(token);
}
EventRevoker AddHandler(EventHandler&& handler) override {
const auto token = current_token_++;
- handlers_.emplace(token, std::move(handler));
+ handlers_->emplace_back(token, std::move(handler));
return CreateRevoker(token);
}
void Raise(EventArgs 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(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;
+ handler(args);
+ }
}
protected:
void RemoveHandler(EventHandlerToken token) override {
- auto find_result = handlers_.find(token);
- if (find_result != handlers_.cend()) handlers_.erase(find_result);
+ 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);
}
private:
- std::map<EventHandlerToken, EventHandler> handlers_{};
+ std::shared_ptr<std::list<HandlerData>> handlers_ =
+ std::make_shared<std::list<HandlerData>>();
EventHandlerToken current_token_ = 0;
};