helper.hpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #ifndef ENTT_ENTITY_HELPER_HPP
  2. #define ENTT_ENTITY_HELPER_HPP
  3. #include <memory>
  4. #include <type_traits>
  5. #include <utility>
  6. #include "../core/fwd.hpp"
  7. #include "../core/type_traits.hpp"
  8. #include "../signal/delegate.hpp"
  9. #include "fwd.hpp"
  10. #include "group.hpp"
  11. #include "storage.hpp"
  12. #include "view.hpp"
  13. namespace entt {
  14. /**
  15. * @brief Converts a registry to a view.
  16. * @tparam Registry Basic registry type.
  17. */
  18. template<typename Registry>
  19. class as_view {
  20. template<typename... Get, typename... Exclude>
  21. auto dispatch(get_t<Get...>, exclude_t<Exclude...>) const {
  22. return reg.template view<constness_as_t<typename Get::value_type, Get>...>(exclude_t<constness_as_t<typename Exclude::value_type, Exclude>...>{});
  23. }
  24. public:
  25. /*! @brief Type of registry to convert. */
  26. using registry_type = Registry;
  27. /*! @brief Underlying entity identifier. */
  28. using entity_type = typename registry_type::entity_type;
  29. /**
  30. * @brief Constructs a converter for a given registry.
  31. * @param source A valid reference to a registry.
  32. */
  33. as_view(registry_type &source) noexcept
  34. : reg{source} {}
  35. /**
  36. * @brief Conversion function from a registry to a view.
  37. * @tparam Get Type of storage used to construct the view.
  38. * @tparam Exclude Types of storage used to filter the view.
  39. * @return A newly created view.
  40. */
  41. template<typename Get, typename Exclude>
  42. operator basic_view<Get, Exclude>() const {
  43. return dispatch(Get{}, Exclude{});
  44. }
  45. private:
  46. registry_type &reg;
  47. };
  48. /**
  49. * @brief Converts a registry to a group.
  50. * @tparam Registry Basic registry type.
  51. */
  52. template<typename Registry>
  53. class as_group {
  54. template<typename... Owned, typename... Get, typename... Exclude>
  55. auto dispatch(owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>) const {
  56. if constexpr(std::is_const_v<registry_type>) {
  57. return reg.template group_if_exists<typename Owned::value_type...>(get_t<typename Get::value_type...>{}, exclude_t<typename Exclude::value_type...>{});
  58. } else {
  59. return reg.template group<constness_as_t<typename Owned::value_type, Owned>...>(get_t<constness_as_t<typename Get::value_type, Get>...>{}, exclude_t<constness_as_t<typename Exclude::value_type, Exclude>...>{});
  60. }
  61. }
  62. public:
  63. /*! @brief Type of registry to convert. */
  64. using registry_type = Registry;
  65. /*! @brief Underlying entity identifier. */
  66. using entity_type = typename registry_type::entity_type;
  67. /**
  68. * @brief Constructs a converter for a given registry.
  69. * @param source A valid reference to a registry.
  70. */
  71. as_group(registry_type &source) noexcept
  72. : reg{source} {}
  73. /**
  74. * @brief Conversion function from a registry to a group.
  75. * @tparam Owned Types of _owned_ by the group.
  76. * @tparam Get Types of storage _observed_ by the group.
  77. * @tparam Exclude Types of storage used to filter the group.
  78. * @return A newly created group.
  79. */
  80. template<typename Owned, typename Get, typename Exclude>
  81. operator basic_group<Owned, Get, Exclude>() const {
  82. return dispatch(Owned{}, Get{}, Exclude{});
  83. }
  84. private:
  85. registry_type &reg;
  86. };
  87. /**
  88. * @brief Helper to create a listener that directly invokes a member function.
  89. * @tparam Member Member function to invoke on a component of the given type.
  90. * @tparam Registry Basic registry type.
  91. * @param reg A registry that contains the given entity and its components.
  92. * @param entt Entity from which to get the component.
  93. */
  94. template<auto Member, typename Registry = std::decay_t<nth_argument_t<0u, decltype(Member)>>>
  95. void invoke(Registry &reg, const typename Registry::entity_type entt) {
  96. static_assert(std::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function");
  97. delegate<void(Registry &, const typename Registry::entity_type)> func;
  98. func.template connect<Member>(reg.template get<member_class_t<decltype(Member)>>(entt));
  99. func(reg, entt);
  100. }
  101. /**
  102. * @brief Returns the entity associated with a given component.
  103. *
  104. * @warning
  105. * Currently, this function only works correctly with the default storage as it
  106. * makes assumptions about how the components are laid out.
  107. *
  108. * @tparam Args Storage type template parameters.
  109. * @param storage A storage that contains the given component.
  110. * @param instance A valid component instance.
  111. * @return The entity associated with the given component.
  112. */
  113. template<typename... Args>
  114. auto to_entity(const basic_storage<Args...> &storage, const typename basic_storage<Args...>::value_type &instance) -> typename basic_storage<Args...>::entity_type {
  115. constexpr auto page_size = basic_storage<Args...>::traits_type::page_size;
  116. const typename basic_storage<Args...>::base_type &base = storage;
  117. const auto *addr = std::addressof(instance);
  118. for(auto it = base.rbegin(), last = base.rend(); it < last; it += page_size) {
  119. if(const auto dist = (addr - std::addressof(storage.get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(page_size)) {
  120. return *(it + dist);
  121. }
  122. }
  123. return null;
  124. }
  125. /**
  126. * @copybrief to_entity
  127. * @tparam Args Registry type template parameters.
  128. * @tparam Component Type of component.
  129. * @param reg A registry that contains the given entity and its components.
  130. * @param instance A valid component instance.
  131. * @return The entity associated with the given component.
  132. */
  133. template<typename... Args, typename Component>
  134. [[deprecated("use storage based to_entity instead")]] typename basic_registry<Args...>::entity_type to_entity(const basic_registry<Args...> &reg, const Component &instance) {
  135. if(const auto *storage = reg.template storage<Component>(); storage) {
  136. return to_entity(*storage, instance);
  137. }
  138. return null;
  139. }
  140. /*! @brief Primary template isn't defined on purpose. */
  141. template<typename...>
  142. struct sigh_helper;
  143. /**
  144. * @brief Signal connection helper for registries.
  145. * @tparam Registry Basic registry type.
  146. */
  147. template<typename Registry>
  148. struct sigh_helper<Registry> {
  149. /*! @brief Registry type. */
  150. using registry_type = Registry;
  151. /**
  152. * @brief Constructs a helper for a given registry.
  153. * @param ref A valid reference to a registry.
  154. */
  155. sigh_helper(registry_type &ref)
  156. : bucket{&ref} {}
  157. /**
  158. * @brief Binds a properly initialized helper to a given signal type.
  159. * @tparam Type Type of signal to bind the helper to.
  160. * @param id Optional name for the underlying storage to use.
  161. * @return A helper for a given registry and signal type.
  162. */
  163. template<typename Type>
  164. auto with(const id_type id = type_hash<Type>::value()) noexcept {
  165. return sigh_helper<registry_type, Type>{*bucket, id};
  166. }
  167. /**
  168. * @brief Returns a reference to the underlying registry.
  169. * @return A reference to the underlying registry.
  170. */
  171. [[nodiscard]] registry_type &registry() noexcept {
  172. return *bucket;
  173. }
  174. private:
  175. registry_type *bucket;
  176. };
  177. /**
  178. * @brief Signal connection helper for registries.
  179. * @tparam Registry Basic registry type.
  180. * @tparam Type Type of signal to connect listeners to.
  181. */
  182. template<typename Registry, typename Type>
  183. struct sigh_helper<Registry, Type> final: sigh_helper<Registry> {
  184. /*! @brief Registry type. */
  185. using registry_type = Registry;
  186. /**
  187. * @brief Constructs a helper for a given registry.
  188. * @param ref A valid reference to a registry.
  189. * @param id Optional name for the underlying storage to use.
  190. */
  191. sigh_helper(registry_type &ref, const id_type id = type_hash<Type>::value())
  192. : sigh_helper<Registry>{ref},
  193. name{id} {}
  194. /**
  195. * @brief Forwards the call to `on_construct` on the underlying storage.
  196. * @tparam Candidate Function or member to connect.
  197. * @tparam Args Type of class or type of payload, if any.
  198. * @param args A valid object that fits the purpose, if any.
  199. * @return This helper.
  200. */
  201. template<auto Candidate, typename... Args>
  202. auto on_construct(Args &&...args) {
  203. this->registry().template on_construct<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
  204. return *this;
  205. }
  206. /**
  207. * @brief Forwards the call to `on_update` on the underlying storage.
  208. * @tparam Candidate Function or member to connect.
  209. * @tparam Args Type of class or type of payload, if any.
  210. * @param args A valid object that fits the purpose, if any.
  211. * @return This helper.
  212. */
  213. template<auto Candidate, typename... Args>
  214. auto on_update(Args &&...args) {
  215. this->registry().template on_update<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
  216. return *this;
  217. }
  218. /**
  219. * @brief Forwards the call to `on_destroy` on the underlying storage.
  220. * @tparam Candidate Function or member to connect.
  221. * @tparam Args Type of class or type of payload, if any.
  222. * @param args A valid object that fits the purpose, if any.
  223. * @return This helper.
  224. */
  225. template<auto Candidate, typename... Args>
  226. auto on_destroy(Args &&...args) {
  227. this->registry().template on_destroy<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
  228. return *this;
  229. }
  230. private:
  231. id_type name;
  232. };
  233. /**
  234. * @brief Deduction guide.
  235. * @tparam Registry Basic registry type.
  236. */
  237. template<typename Registry>
  238. sigh_helper(Registry &) -> sigh_helper<Registry>;
  239. } // namespace entt
  240. #endif