| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- /*
- * SubscriptionRegistry.h, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
- #pragma once
- VCMI_LIB_NAMESPACE_BEGIN
- class Environment;
- namespace events
- {
- class EventBus;
- class DLL_LINKAGE EventSubscription : public boost::noncopyable
- {
- public:
- virtual ~EventSubscription() = default;
- };
- template <typename E>
- class SubscriptionRegistry : public boost::noncopyable
- {
- public:
- using PreHandler = std::function<void(E &)>;
- using ExecHandler = std::function<void(E &)>;
- using PostHandler = std::function<void(const E &)>;
- using BusTag = const void *;
- std::unique_ptr<EventSubscription> subscribeBefore(BusTag tag, PreHandler && handler)
- {
- std::unique_lock<std::shared_mutex> lock(mutex);
- auto storage = std::make_shared<PreHandlerStorage>(std::move(handler));
- preHandlers[tag].push_back(storage);
- return std::make_unique<PreSubscription>(tag, storage);
- }
- std::unique_ptr<EventSubscription> subscribeAfter(BusTag tag, PostHandler && handler)
- {
- std::unique_lock<std::shared_mutex> lock(mutex);
- auto storage = std::make_shared<PostHandlerStorage>(std::move(handler));
- postHandlers[tag].push_back(storage);
- return std::make_unique<PostSubscription>(tag, storage);
- }
- void executeEvent(const EventBus * bus, E & event, const ExecHandler & execHandler)
- {
- std::shared_lock<std::shared_mutex> lock(mutex);
- {
- auto it = preHandlers.find(bus);
- if(it != std::end(preHandlers))
- {
- for(auto & h : it->second)
- (*h)(event);
- }
- }
- if(event.isEnabled())
- {
- if(execHandler)
- execHandler(event);
- auto it = postHandlers.find(bus);
- if(it != std::end(postHandlers))
- {
- for(auto & h : it->second)
- (*h)(event);
- }
- }
- }
- private:
- template <typename T>
- class HandlerStorage
- {
- public:
- explicit HandlerStorage(T && handler_)
- : handler(handler_)
- {
- }
- STRONG_INLINE
- void operator()(E & event)
- {
- handler(event);
- }
- private:
- T handler;
- };
- using PreHandlerStorage = HandlerStorage<PreHandler>;
- using PostHandlerStorage = HandlerStorage<PostHandler>;
- class PreSubscription : public EventSubscription
- {
- public:
- PreSubscription(BusTag tag_, std::shared_ptr<PreHandlerStorage> handler_)
- : handler(handler_),
- tag(tag_)
- {
- }
- virtual ~PreSubscription()
- {
- auto registry = E::getRegistry();
- registry->unsubscribe(tag, handler, registry->preHandlers);
- }
- private:
- BusTag tag;
- std::shared_ptr<PreHandlerStorage> handler;
- };
- class PostSubscription : public EventSubscription
- {
- public:
- PostSubscription(BusTag tag_, std::shared_ptr<PostHandlerStorage> handler_)
- : handler(handler_),
- tag(tag_)
- {
- }
- virtual ~PostSubscription()
- {
- auto registry = E::getRegistry();
- registry->unsubscribe(tag, handler, registry->postHandlers);
- }
- private:
- BusTag tag;
- std::shared_ptr<PostHandlerStorage> handler;
- };
- std::shared_mutex mutex;
- std::map<BusTag, std::vector<std::shared_ptr<PreHandlerStorage>>> preHandlers;
- std::map<BusTag, std::vector<std::shared_ptr<PostHandlerStorage>>> postHandlers;
- template <typename T>
- void unsubscribe(BusTag tag, T what, std::map<BusTag, std::vector<T>> & from)
- {
- std::unique_lock<std::shared_mutex> lock(mutex);
- auto it = from.find(tag);
- if(it != std::end(from))
- {
- it->second -= what;
- if(it->second.empty())
- {
- from.erase(tag);
- }
- }
- }
- };
- }
- VCMI_LIB_NAMESPACE_END
|