SubscriptionRegistry.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * SubscriptionRegistry.h, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #pragma once
  11. VCMI_LIB_NAMESPACE_BEGIN
  12. class Environment;
  13. namespace events
  14. {
  15. class EventBus;
  16. class DLL_LINKAGE EventSubscription : public boost::noncopyable
  17. {
  18. public:
  19. virtual ~EventSubscription() = default;
  20. };
  21. template <typename E>
  22. class SubscriptionRegistry : public boost::noncopyable
  23. {
  24. public:
  25. using PreHandler = std::function<void(E &)>;
  26. using ExecHandler = std::function<void(E &)>;
  27. using PostHandler = std::function<void(const E &)>;
  28. using BusTag = const void *;
  29. std::unique_ptr<EventSubscription> subscribeBefore(BusTag tag, PreHandler && handler)
  30. {
  31. std::unique_lock<std::shared_mutex> lock(mutex);
  32. auto storage = std::make_shared<PreHandlerStorage>(std::move(handler));
  33. preHandlers[tag].push_back(storage);
  34. return std::make_unique<PreSubscription>(tag, storage);
  35. }
  36. std::unique_ptr<EventSubscription> subscribeAfter(BusTag tag, PostHandler && handler)
  37. {
  38. std::unique_lock<std::shared_mutex> lock(mutex);
  39. auto storage = std::make_shared<PostHandlerStorage>(std::move(handler));
  40. postHandlers[tag].push_back(storage);
  41. return std::make_unique<PostSubscription>(tag, storage);
  42. }
  43. void executeEvent(const EventBus * bus, E & event, const ExecHandler & execHandler)
  44. {
  45. std::shared_lock<std::shared_mutex> lock(mutex);
  46. {
  47. auto it = preHandlers.find(bus);
  48. if(it != std::end(preHandlers))
  49. {
  50. for(auto & h : it->second)
  51. (*h)(event);
  52. }
  53. }
  54. if(event.isEnabled())
  55. {
  56. if(execHandler)
  57. execHandler(event);
  58. auto it = postHandlers.find(bus);
  59. if(it != std::end(postHandlers))
  60. {
  61. for(auto & h : it->second)
  62. (*h)(event);
  63. }
  64. }
  65. }
  66. private:
  67. template <typename T>
  68. class HandlerStorage
  69. {
  70. public:
  71. explicit HandlerStorage(T && handler_)
  72. : handler(handler_)
  73. {
  74. }
  75. STRONG_INLINE
  76. void operator()(E & event)
  77. {
  78. handler(event);
  79. }
  80. private:
  81. T handler;
  82. };
  83. using PreHandlerStorage = HandlerStorage<PreHandler>;
  84. using PostHandlerStorage = HandlerStorage<PostHandler>;
  85. class PreSubscription : public EventSubscription
  86. {
  87. public:
  88. PreSubscription(BusTag tag_, std::shared_ptr<PreHandlerStorage> handler_)
  89. : handler(handler_),
  90. tag(tag_)
  91. {
  92. }
  93. virtual ~PreSubscription()
  94. {
  95. auto registry = E::getRegistry();
  96. registry->unsubscribe(tag, handler, registry->preHandlers);
  97. }
  98. private:
  99. BusTag tag;
  100. std::shared_ptr<PreHandlerStorage> handler;
  101. };
  102. class PostSubscription : public EventSubscription
  103. {
  104. public:
  105. PostSubscription(BusTag tag_, std::shared_ptr<PostHandlerStorage> handler_)
  106. : handler(handler_),
  107. tag(tag_)
  108. {
  109. }
  110. virtual ~PostSubscription()
  111. {
  112. auto registry = E::getRegistry();
  113. registry->unsubscribe(tag, handler, registry->postHandlers);
  114. }
  115. private:
  116. BusTag tag;
  117. std::shared_ptr<PostHandlerStorage> handler;
  118. };
  119. std::shared_mutex mutex;
  120. std::map<BusTag, std::vector<std::shared_ptr<PreHandlerStorage>>> preHandlers;
  121. std::map<BusTag, std::vector<std::shared_ptr<PostHandlerStorage>>> postHandlers;
  122. template <typename T>
  123. void unsubscribe(BusTag tag, T what, std::map<BusTag, std::vector<T>> & from)
  124. {
  125. std::unique_lock<std::shared_mutex> lock(mutex);
  126. auto it = from.find(tag);
  127. if(it != std::end(from))
  128. {
  129. it->second -= what;
  130. if(it->second.empty())
  131. {
  132. from.erase(tag);
  133. }
  134. }
  135. }
  136. };
  137. }
  138. VCMI_LIB_NAMESPACE_END