emitter.hpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #ifndef ENTT_SIGNAL_EMITTER_HPP
  2. #define ENTT_SIGNAL_EMITTER_HPP
  3. #include <functional>
  4. #include <type_traits>
  5. #include <utility>
  6. #include "../container/dense_map.hpp"
  7. #include "../core/compressed_pair.hpp"
  8. #include "../core/fwd.hpp"
  9. #include "../core/type_info.hpp"
  10. #include "../core/utility.hpp"
  11. #include "fwd.hpp"
  12. namespace entt {
  13. /**
  14. * @brief General purpose event emitter.
  15. *
  16. * To create an emitter type, derived classes must inherit from the base as:
  17. *
  18. * @code{.cpp}
  19. * struct my_emitter: emitter<my_emitter> {
  20. * // ...
  21. * }
  22. * @endcode
  23. *
  24. * Handlers for the different events are created internally on the fly. It's not
  25. * required to specify in advance the full list of accepted events.<br/>
  26. * Moreover, whenever an event is published, an emitter also passes a reference
  27. * to itself to its listeners.
  28. *
  29. * @tparam Derived Emitter type.
  30. * @tparam Allocator Type of allocator used to manage memory and elements.
  31. */
  32. template<typename Derived, typename Allocator>
  33. class emitter {
  34. using key_type = id_type;
  35. using mapped_type = std::function<void(void *)>;
  36. using alloc_traits = std::allocator_traits<Allocator>;
  37. using container_allocator = typename alloc_traits::template rebind_alloc<std::pair<const key_type, mapped_type>>;
  38. using container_type = dense_map<key_type, mapped_type, identity, std::equal_to<key_type>, container_allocator>;
  39. public:
  40. /*! @brief Allocator type. */
  41. using allocator_type = Allocator;
  42. /*! @brief Unsigned integer type. */
  43. using size_type = std::size_t;
  44. /*! @brief Default constructor. */
  45. emitter()
  46. : emitter{allocator_type{}} {}
  47. /**
  48. * @brief Constructs an emitter with a given allocator.
  49. * @param allocator The allocator to use.
  50. */
  51. explicit emitter(const allocator_type &allocator)
  52. : handlers{allocator, allocator} {}
  53. /*! @brief Default destructor. */
  54. virtual ~emitter() noexcept {
  55. static_assert(std::is_base_of_v<emitter<Derived, Allocator>, Derived>, "Invalid emitter type");
  56. }
  57. /**
  58. * @brief Move constructor.
  59. * @param other The instance to move from.
  60. */
  61. emitter(emitter &&other) noexcept
  62. : handlers{std::move(other.handlers)} {}
  63. /**
  64. * @brief Allocator-extended move constructor.
  65. * @param other The instance to move from.
  66. * @param allocator The allocator to use.
  67. */
  68. emitter(emitter &&other, const allocator_type &allocator) noexcept
  69. : handlers{container_type{std::move(other.handlers.first()), allocator}, allocator} {
  70. ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying an emitter is not allowed");
  71. }
  72. /**
  73. * @brief Move assignment operator.
  74. * @param other The instance to move from.
  75. * @return This dispatcher.
  76. */
  77. emitter &operator=(emitter &&other) noexcept {
  78. ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying an emitter is not allowed");
  79. handlers = std::move(other.handlers);
  80. return *this;
  81. }
  82. /**
  83. * @brief Exchanges the contents with those of a given emitter.
  84. * @param other Emitter to exchange the content with.
  85. */
  86. void swap(emitter &other) {
  87. using std::swap;
  88. swap(handlers, other.handlers);
  89. }
  90. /**
  91. * @brief Returns the associated allocator.
  92. * @return The associated allocator.
  93. */
  94. [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
  95. return handlers.second();
  96. }
  97. /**
  98. * @brief Publishes a given event.
  99. * @tparam Type Type of event to trigger.
  100. * @param value An instance of the given type of event.
  101. */
  102. template<typename Type>
  103. void publish(Type &&value) {
  104. if(const auto id = type_id<Type>().hash(); handlers.first().contains(id)) {
  105. handlers.first()[id](&value);
  106. }
  107. }
  108. /**
  109. * @brief Registers a listener with the event emitter.
  110. * @tparam Type Type of event to which to connect the listener.
  111. * @param func The listener to register.
  112. */
  113. template<typename Type>
  114. void on(std::function<void(Type &, Derived &)> func) {
  115. handlers.first().insert_or_assign(type_id<Type>().hash(), [func = std::move(func), this](void *value) {
  116. func(*static_cast<Type *>(value), static_cast<Derived &>(*this));
  117. });
  118. }
  119. /**
  120. * @brief Disconnects a listener from the event emitter.
  121. * @tparam Type Type of event of the listener.
  122. */
  123. template<typename Type>
  124. void erase() {
  125. handlers.first().erase(type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value());
  126. }
  127. /*! @brief Disconnects all the listeners. */
  128. void clear() noexcept {
  129. handlers.first().clear();
  130. }
  131. /**
  132. * @brief Checks if there are listeners registered for the specific event.
  133. * @tparam Type Type of event to test.
  134. * @return True if there are no listeners registered, false otherwise.
  135. */
  136. template<typename Type>
  137. [[nodiscard]] bool contains() const {
  138. return handlers.first().contains(type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value());
  139. }
  140. /**
  141. * @brief Checks if there are listeners registered with the event emitter.
  142. * @return True if there are no listeners registered, false otherwise.
  143. */
  144. [[nodiscard]] bool empty() const noexcept {
  145. return handlers.first().empty();
  146. }
  147. private:
  148. compressed_pair<container_type, allocator_type> handlers;
  149. };
  150. } // namespace entt
  151. #endif