#ifndef ENTT_ENTITY_HELPER_HPP #define ENTT_ENTITY_HELPER_HPP #include #include #include #include "../core/fwd.hpp" #include "../core/type_traits.hpp" #include "component.hpp" #include "fwd.hpp" #include "group.hpp" #include "storage.hpp" #include "view.hpp" namespace entt { /** * @brief Converts a registry to a view. * @tparam Registry Basic registry type. */ template class as_view { template [[nodiscard]] auto dispatch(get_t, exclude_t) const { return reg.template view...>(exclude_t...>{}); } public: /*! @brief Type of registry to convert. */ using registry_type = Registry; /*! @brief Underlying entity identifier. */ using entity_type = typename registry_type::entity_type; /** * @brief Constructs a converter for a given registry. * @param source A valid reference to a registry. */ as_view(registry_type &source) noexcept : reg{source} {} /** * @brief Conversion function from a registry to a view. * @tparam Get Type of storage used to construct the view. * @tparam Exclude Types of storage used to filter the view. * @return A newly created view. */ template operator basic_view() const { return dispatch(Get{}, Exclude{}); } private: registry_type ® }; /** * @brief Converts a registry to a group. * @tparam Registry Basic registry type. */ template class as_group { template [[nodiscard]] auto dispatch(owned_t, get_t, exclude_t) const { if constexpr(std::is_const_v) { return reg.template group_if_exists(get_t{}, exclude_t{}); } else { return reg.template group...>(get_t...>{}, exclude_t...>{}); } } public: /*! @brief Type of registry to convert. */ using registry_type = Registry; /*! @brief Underlying entity identifier. */ using entity_type = typename registry_type::entity_type; /** * @brief Constructs a converter for a given registry. * @param source A valid reference to a registry. */ as_group(registry_type &source) noexcept : reg{source} {} /** * @brief Conversion function from a registry to a group. * @tparam Owned Types of _owned_ by the group. * @tparam Get Types of storage _observed_ by the group. * @tparam Exclude Types of storage used to filter the group. * @return A newly created group. */ template operator basic_group() const { return dispatch(Owned{}, Get{}, Exclude{}); } private: registry_type ® }; /** * @brief Helper to create a listener that directly invokes a member function. * @tparam Member Member function to invoke on an element of the given type. * @tparam Registry Basic registry type. * @param reg A registry that contains the given entity and its elements. * @param entt Entity from which to get the element. */ template>> void invoke(Registry ®, const typename Registry::entity_type entt) { static_assert(std::is_member_function_pointer_v, "Invalid pointer to non-static member function"); (reg.template get>(entt).*Member)(reg, entt); } /** * @brief Returns the entity associated with a given element. * * @warning * Currently, this function only works correctly with the default storage as it * makes assumptions about how the elements are laid out. * * @tparam Args Storage type template parameters. * @param storage A storage that contains the given element. * @param instance A valid element instance. * @return The entity associated with the given element. */ template typename basic_storage::entity_type to_entity(const basic_storage &storage, const typename basic_storage::value_type &instance) { using traits_type = component_traits::value_type>; static_assert(traits_type::page_size != 0u, "Unexpected page size"); const typename basic_storage::base_type &base = storage; const auto *addr = std::addressof(instance); for(auto it = base.rbegin(), last = base.rend(); it < last; it += traits_type::page_size) { if(const auto dist = (addr - std::addressof(storage.get(*it))); dist >= 0 && dist < static_cast(traits_type::page_size)) { return *(it + dist); } } return null; } /*! @brief Primary template isn't defined on purpose. */ template struct sigh_helper; /** * @brief Signal connection helper for registries. * @tparam Registry Basic registry type. */ template struct sigh_helper { /*! @brief Registry type. */ using registry_type = Registry; /** * @brief Constructs a helper for a given registry. * @param ref A valid reference to a registry. */ sigh_helper(registry_type &ref) : bucket{&ref} {} /** * @brief Binds a properly initialized helper to a given signal type. * @tparam Type Type of signal to bind the helper to. * @param id Optional name for the underlying storage to use. * @return A helper for a given registry and signal type. */ template auto with(const id_type id = type_hash::value()) noexcept { return sigh_helper{*bucket, id}; } /** * @brief Returns a reference to the underlying registry. * @return A reference to the underlying registry. */ [[nodiscard]] registry_type ®istry() noexcept { return *bucket; } private: registry_type *bucket; }; /** * @brief Signal connection helper for registries. * @tparam Registry Basic registry type. * @tparam Type Type of signal to connect listeners to. */ template struct sigh_helper final: sigh_helper { /*! @brief Registry type. */ using registry_type = Registry; /** * @brief Constructs a helper for a given registry. * @param ref A valid reference to a registry. * @param id Optional name for the underlying storage to use. */ sigh_helper(registry_type &ref, const id_type id = type_hash::value()) : sigh_helper{ref}, name{id} {} /** * @brief Forwards the call to `on_construct` on the underlying storage. * @tparam Candidate Function or member to connect. * @tparam Args Type of class or type of payload, if any. * @param args A valid object that fits the purpose, if any. * @return This helper. */ template auto on_construct(Args &&...args) { this->registry().template on_construct(name).template connect(std::forward(args)...); return *this; } /** * @brief Forwards the call to `on_update` on the underlying storage. * @tparam Candidate Function or member to connect. * @tparam Args Type of class or type of payload, if any. * @param args A valid object that fits the purpose, if any. * @return This helper. */ template auto on_update(Args &&...args) { this->registry().template on_update(name).template connect(std::forward(args)...); return *this; } /** * @brief Forwards the call to `on_destroy` on the underlying storage. * @tparam Candidate Function or member to connect. * @tparam Args Type of class or type of payload, if any. * @param args A valid object that fits the purpose, if any. * @return This helper. */ template auto on_destroy(Args &&...args) { this->registry().template on_destroy(name).template connect(std::forward(args)...); return *this; } private: id_type name; }; /** * @brief Deduction guide. * @tparam Registry Basic registry type. */ template sigh_helper(Registry &) -> sigh_helper; } // namespace entt #endif