mixin.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. #ifndef ENTT_ENTITY_MIXIN_HPP
  2. #define ENTT_ENTITY_MIXIN_HPP
  3. #include <type_traits>
  4. #include <utility>
  5. #include "../config/config.h"
  6. #include "../core/any.hpp"
  7. #include "../signal/sigh.hpp"
  8. #include "entity.hpp"
  9. #include "fwd.hpp"
  10. namespace entt {
  11. /**
  12. * @brief Mixin type used to add signal support to storage types.
  13. *
  14. * The function type of a listener is equivalent to:
  15. *
  16. * @code{.cpp}
  17. * void(basic_registry<entity_type> &, entity_type);
  18. * @endcode
  19. *
  20. * This applies to all signals made available.
  21. *
  22. * @tparam Type Underlying storage type.
  23. * @tparam Registry Basic registry type.
  24. */
  25. template<typename Type, typename Registry>
  26. class basic_sigh_mixin final: public Type {
  27. using underlying_type = Type;
  28. using owner_type = Registry;
  29. using basic_registry_type = basic_registry<typename underlying_type::entity_type, typename underlying_type::base_type::allocator_type>;
  30. using sigh_type = sigh<void(owner_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
  31. using underlying_iterator = typename underlying_type::base_type::basic_iterator;
  32. static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
  33. owner_type &owner_or_assert() const noexcept {
  34. ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
  35. return static_cast<owner_type &>(*owner);
  36. }
  37. void pop(underlying_iterator first, underlying_iterator last) final {
  38. if(auto &reg = owner_or_assert(); destruction.empty()) {
  39. underlying_type::pop(first, last);
  40. } else {
  41. for(; first != last; ++first) {
  42. const auto entt = *first;
  43. destruction.publish(reg, entt);
  44. const auto it = underlying_type::find(entt);
  45. underlying_type::pop(it, it + 1u);
  46. }
  47. }
  48. }
  49. void pop_all() final {
  50. if(auto &reg = owner_or_assert(); !destruction.empty()) {
  51. for(auto it = underlying_type::base_type::begin(0), last = underlying_type::base_type::end(0); it != last; ++it) {
  52. if constexpr(std::is_same_v<typename underlying_type::value_type, typename underlying_type::entity_type>) {
  53. destruction.publish(reg, *it);
  54. } else {
  55. if constexpr(underlying_type::traits_type::in_place_delete) {
  56. if(const auto entt = *it; entt != tombstone) {
  57. destruction.publish(reg, entt);
  58. }
  59. } else {
  60. destruction.publish(reg, *it);
  61. }
  62. }
  63. }
  64. }
  65. underlying_type::pop_all();
  66. }
  67. underlying_iterator try_emplace(const typename underlying_type::entity_type entt, const bool force_back, const void *value) final {
  68. const auto it = underlying_type::try_emplace(entt, force_back, value);
  69. if(auto &reg = owner_or_assert(); it != underlying_type::base_type::end()) {
  70. construction.publish(reg, *it);
  71. }
  72. return it;
  73. }
  74. public:
  75. /*! @brief Allocator type. */
  76. using allocator_type = typename underlying_type::allocator_type;
  77. /*! @brief Underlying entity identifier. */
  78. using entity_type = typename underlying_type::entity_type;
  79. /*! @brief Expected registry type. */
  80. using registry_type = owner_type;
  81. /*! @brief Default constructor. */
  82. basic_sigh_mixin()
  83. : basic_sigh_mixin{allocator_type{}} {}
  84. /**
  85. * @brief Constructs an empty storage with a given allocator.
  86. * @param allocator The allocator to use.
  87. */
  88. explicit basic_sigh_mixin(const allocator_type &allocator)
  89. : underlying_type{allocator},
  90. owner{},
  91. construction{allocator},
  92. destruction{allocator},
  93. update{allocator} {}
  94. /**
  95. * @brief Move constructor.
  96. * @param other The instance to move from.
  97. */
  98. basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
  99. : underlying_type{std::move(other)},
  100. owner{other.owner},
  101. construction{std::move(other.construction)},
  102. destruction{std::move(other.destruction)},
  103. update{std::move(other.update)} {}
  104. /**
  105. * @brief Allocator-extended move constructor.
  106. * @param other The instance to move from.
  107. * @param allocator The allocator to use.
  108. */
  109. basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator) noexcept
  110. : underlying_type{std::move(other), allocator},
  111. owner{other.owner},
  112. construction{std::move(other.construction), allocator},
  113. destruction{std::move(other.destruction), allocator},
  114. update{std::move(other.update), allocator} {}
  115. /**
  116. * @brief Move assignment operator.
  117. * @param other The instance to move from.
  118. * @return This storage.
  119. */
  120. basic_sigh_mixin &operator=(basic_sigh_mixin &&other) noexcept {
  121. underlying_type::operator=(std::move(other));
  122. owner = other.owner;
  123. construction = std::move(other.construction);
  124. destruction = std::move(other.destruction);
  125. update = std::move(other.update);
  126. return *this;
  127. }
  128. /**
  129. * @brief Exchanges the contents with those of a given storage.
  130. * @param other Storage to exchange the content with.
  131. */
  132. void swap(basic_sigh_mixin &other) {
  133. using std::swap;
  134. underlying_type::swap(other);
  135. swap(owner, other.owner);
  136. swap(construction, other.construction);
  137. swap(destruction, other.destruction);
  138. swap(update, other.update);
  139. }
  140. /**
  141. * @brief Returns a sink object.
  142. *
  143. * The sink returned by this function can be used to receive notifications
  144. * whenever a new instance is created and assigned to an entity.<br/>
  145. * Listeners are invoked after the object has been assigned to the entity.
  146. *
  147. * @sa sink
  148. *
  149. * @return A temporary sink object.
  150. */
  151. [[nodiscard]] auto on_construct() noexcept {
  152. return sink{construction};
  153. }
  154. /**
  155. * @brief Returns a sink object.
  156. *
  157. * The sink returned by this function can be used to receive notifications
  158. * whenever an instance is explicitly updated.<br/>
  159. * Listeners are invoked after the object has been updated.
  160. *
  161. * @sa sink
  162. *
  163. * @return A temporary sink object.
  164. */
  165. [[nodiscard]] auto on_update() noexcept {
  166. return sink{update};
  167. }
  168. /**
  169. * @brief Returns a sink object.
  170. *
  171. * The sink returned by this function can be used to receive notifications
  172. * whenever an instance is removed from an entity and thus destroyed.<br/>
  173. * Listeners are invoked before the object has been removed from the entity.
  174. *
  175. * @sa sink
  176. *
  177. * @return A temporary sink object.
  178. */
  179. [[nodiscard]] auto on_destroy() noexcept {
  180. return sink{destruction};
  181. }
  182. /**
  183. * @brief Emplace elements into a storage.
  184. *
  185. * The behavior of this operation depends on the underlying storage type
  186. * (for example, components vs entities).<br/>
  187. * Refer to the specific documentation for more details.
  188. *
  189. * @return A return value as returned by the underlying storage.
  190. */
  191. auto emplace() {
  192. const auto entt = underlying_type::emplace();
  193. construction.publish(owner_or_assert(), entt);
  194. return entt;
  195. }
  196. /**
  197. * @brief Emplace elements into a storage.
  198. *
  199. * The behavior of this operation depends on the underlying storage type
  200. * (for example, components vs entities).<br/>
  201. * Refer to the specific documentation for more details.
  202. *
  203. * @tparam Args Types of arguments to forward to the underlying storage.
  204. * @param hint A valid identifier.
  205. * @param args Parameters to forward to the underlying storage.
  206. * @return A return value as returned by the underlying storage.
  207. */
  208. template<typename... Args>
  209. decltype(auto) emplace(const entity_type hint, Args &&...args) {
  210. if constexpr(std::is_same_v<typename underlying_type::value_type, typename underlying_type::entity_type>) {
  211. const auto entt = underlying_type::emplace(hint, std::forward<Args>(args)...);
  212. construction.publish(owner_or_assert(), entt);
  213. return entt;
  214. } else {
  215. underlying_type::emplace(hint, std::forward<Args>(args)...);
  216. construction.publish(owner_or_assert(), hint);
  217. return this->get(hint);
  218. }
  219. }
  220. /**
  221. * @brief Patches the given instance for an entity.
  222. * @tparam Func Types of the function objects to invoke.
  223. * @param entt A valid identifier.
  224. * @param func Valid function objects.
  225. * @return A reference to the patched instance.
  226. */
  227. template<typename... Func>
  228. decltype(auto) patch(const entity_type entt, Func &&...func) {
  229. underlying_type::patch(entt, std::forward<Func>(func)...);
  230. update.publish(owner_or_assert(), entt);
  231. return this->get(entt);
  232. }
  233. /**
  234. * @brief Emplace elements into a storage.
  235. *
  236. * The behavior of this operation depends on the underlying storage type
  237. * (for example, components vs entities).<br/>
  238. * Refer to the specific documentation for more details.
  239. *
  240. * @tparam It Iterator type (as required by the underlying storage type).
  241. * @tparam Args Types of arguments to forward to the underlying storage.
  242. * @param first An iterator to the first element of the range.
  243. * @param last An iterator past the last element of the range.
  244. * @param args Parameters to use to forward to the underlying storage.
  245. */
  246. template<typename It, typename... Args>
  247. void insert(It first, It last, Args &&...args) {
  248. underlying_type::insert(first, last, std::forward<Args>(args)...);
  249. if(auto &reg = owner_or_assert(); !construction.empty()) {
  250. for(; first != last; ++first) {
  251. construction.publish(reg, *first);
  252. }
  253. }
  254. }
  255. /**
  256. * @brief Forwards variables to derived classes, if any.
  257. * @param value A variable wrapped in an opaque container.
  258. */
  259. void bind(any value) noexcept final {
  260. auto *reg = any_cast<basic_registry_type>(&value);
  261. owner = reg ? reg : owner;
  262. underlying_type::bind(std::move(value));
  263. }
  264. private:
  265. basic_registry_type *owner;
  266. sigh_type construction;
  267. sigh_type destruction;
  268. sigh_type update;
  269. };
  270. } // namespace entt
  271. #endif