💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
3.5 KiB

  1. /*
  2. * Copyright (C) 2023 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_EVENT_QUEUE_HPP
  20. #define ANTKEEPER_EVENT_QUEUE_HPP
  21. #include "event/subscriber.hpp"
  22. #include "event/subscription.hpp"
  23. #include <any>
  24. #include <functional>
  25. #include <list>
  26. #include <map>
  27. #include <memory>
  28. #include <typeindex>
  29. #include <utility>
  30. namespace event {
  31. /**
  32. * Collects messages from publishers to be distributed to subscribers when desired.
  33. */
  34. class queue
  35. {
  36. public:
  37. /**
  38. * Subscribes a function object to messages published by this queue.
  39. *
  40. * @tparam T Message type.
  41. *
  42. * @param subscriber Function object to subscribe.
  43. *
  44. * @return Shared subscription object which will unsubscribe the subscriber on destruction.
  45. */
  46. template <class T>
  47. [[nodiscard]] std::shared_ptr<subscription> subscribe(subscriber<T>&& subscriber)
  48. {
  49. // Allocate shared pointer to std::any object containing subscriber
  50. std::shared_ptr<std::any> shared_subscriber = std::make_shared<std::any>(std::make_any<event::subscriber<T>>(std::move(subscriber)));
  51. // Append subscriber to subscriber list and store iterator
  52. auto iterator = subscribers.emplace(std::type_index(typeid(T)), shared_subscriber);
  53. // Construct and return a shared subscription object which removes the subscriber from the subscriber list when unsubscribed or destructed
  54. return std::make_shared<subscription>
  55. (
  56. std::static_pointer_cast<void>(shared_subscriber),
  57. [this, iterator = std::move(iterator)]()
  58. {
  59. this->subscribers.erase(iterator);
  60. }
  61. );
  62. }
  63. /**
  64. * Adds a message to the queue, to be distributed later.
  65. *
  66. * @tparam T Message type.
  67. *
  68. * @param message Message to enqueue.
  69. */
  70. template <class T>
  71. void enqueue(const T& message)
  72. {
  73. messages.emplace_back
  74. (
  75. [this, message]()
  76. {
  77. this->distribute<T>(message);
  78. }
  79. );
  80. }
  81. /**
  82. * Distributes queued messages in FIFO order to subscribers.
  83. */
  84. void flush()
  85. {
  86. while (!messages.empty())
  87. {
  88. messages.front()();
  89. messages.pop_front();
  90. }
  91. }
  92. /**
  93. * Removes all messages from the queue.
  94. */
  95. void clear()
  96. {
  97. messages.clear();
  98. }
  99. /**
  100. * Returns `true` if there are no messages in the queue, `false` otherwise.
  101. */
  102. [[nodiscard]] inline bool empty() const noexcept
  103. {
  104. return messages.empty();
  105. }
  106. private:
  107. /**
  108. * Distributes a message.
  109. *
  110. * @tparam T Message type.
  111. *
  112. * @param message Message to distribute.
  113. */
  114. template <class T>
  115. void distribute(const T& message) const
  116. {
  117. // For each subscriber of the given message type
  118. const auto range = subscribers.equal_range(std::type_index(typeid(T)));
  119. for (auto i = range.first; i != range.second; ++i)
  120. {
  121. // Send message to subscriber
  122. std::any_cast<subscriber<T>>(*(i->second))(message);
  123. }
  124. }
  125. std::multimap<std::type_index, std::shared_ptr<std::any>> subscribers;
  126. std::list<std::function<void()>> messages;
  127. };
  128. } // namespace event
  129. #endif // ANTKEEPER_EVENT_QUEUE_HPP