Explorar o código

group: storage based model

Michele Caini %!s(int64=3) %!d(string=hai) anos
pai
achega
01d125f53d
Modificáronse 4 ficheiros con 70 adicións e 59 borrados
  1. 3 3
      src/entt/entity/fwd.hpp
  2. 37 35
      src/entt/entity/group.hpp
  3. 17 11
      src/entt/entity/helper.hpp
  4. 13 10
      src/entt/entity/registry.hpp

+ 3 - 3
src/entt/entity/fwd.hpp

@@ -34,7 +34,7 @@ class basic_view;
 template<typename>
 struct basic_runtime_view;
 
-template<typename, typename, typename, typename>
+template<typename, typename, typename>
 class basic_group;
 
 template<typename>
@@ -160,8 +160,8 @@ using runtime_view = basic_runtime_view<sparse_set>;
  * @brief Alias declaration for the most common use case.
  * @tparam Args Other template parameters.
  */
-template<typename... Args>
-using group = basic_group<entity, Args...>;
+template<typename Owned, typename Get, typename Exclude>
+using group = basic_group<type_list_transform_t<Owned, storage_for>, type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
 
 } // namespace entt
 

+ 37 - 35
src/entt/entity/group.hpp

@@ -99,7 +99,7 @@ template<typename... Lhs, typename... Rhs>
  * Primary template isn't defined on purpose. All the specializations give a
  * compile-time error, but for a few reasonable cases.
  */
-template<typename, typename, typename, typename>
+template<typename, typename, typename>
 class basic_group;
 
 /**
@@ -121,27 +121,27 @@ class basic_group;
  * In all other cases, modifying the pools iterated by the group in any way
  * invalidates all the iterators and using them results in undefined behavior.
  *
- * @tparam Entity A valid entity type (see entt_traits for more details).
- * @tparam Get Type of components observed by the group.
- * @tparam Exclude Types of components used to filter the group.
+ * @tparam Get Type of storage _observed_ by the group.
+ * @tparam Exclude Types of storage used to filter the group.
  */
-template<typename Entity, typename... Get, typename... Exclude>
-class basic_group<Entity, owned_t<>, get_t<Get...>, exclude_t<Exclude...>> {
-    /*! @brief A registry is allowed to create groups. */
-    friend class basic_registry<Entity>;
+template<typename... Get, typename... Exclude>
+class basic_group<owned_t<>, get_t<Get...>, exclude_t<Exclude...>> {
+    using underlying_type = std::common_type_t<typename Get::entity_type..., typename Exclude::entity_type...>;
+    using basic_common_type = std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>;
 
     template<typename Comp>
-    static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Comp>, type_list<std::remove_const_t<Get>...>>;
+    static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Comp>, type_list<typename Get::value_type...>>;
 
-    using basic_common_type = std::common_type_t<typename storage_for_t<Get, Entity>::base_type...>;
+    /*! @brief A registry is allowed to create groups. */
+    friend class basic_registry<underlying_type>;
 
-    basic_group(basic_common_type &ref, storage_for_t<Get, Entity> &...gpool) noexcept
+    basic_group(basic_common_type &ref, Get &...gpool) noexcept
         : handler{&ref},
           pools{&gpool...} {}
 
 public:
     /*! @brief Underlying entity identifier. */
-    using entity_type = Entity;
+    using entity_type = underlying_type;
     /*! @brief Unsigned integer type. */
     using size_type = std::size_t;
     /*! @brief Common type among all storage types. */
@@ -151,7 +151,7 @@ public:
     /*! @brief Reversed iterator type. */
     using reverse_iterator = typename base_type::reverse_iterator;
     /*! @brief Iterable group type. */
-    using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<>, get_t<storage_for_t<Get, entity_type>...>>>;
+    using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<>, get_t<Get...>>>;
 
     /*! @brief Default constructor to use to create empty, invalid groups. */
     basic_group() noexcept
@@ -186,8 +186,8 @@ public:
     }
 
     /**
-     * @brief Returns the number of entities that have the given components.
-     * @return Number of entities that have the given components.
+     * @brief Returns the number of entities that are part of the group.
+     * @return Number of entities that are part of the group.
      */
     [[nodiscard]] size_type size() const noexcept {
         return *this ? handler->size() : size_type{};
@@ -486,7 +486,7 @@ public:
 
 private:
     base_type *const handler;
-    const std::tuple<storage_for_t<Get, entity_type> *...> pools;
+    const std::tuple<Get *...> pools;
 };
 
 /**
@@ -517,36 +517,38 @@ private:
  * In all other cases, modifying the pools iterated by the group in any way
  * invalidates all the iterators and using them results in undefined behavior.
  *
- * @tparam Entity A valid entity type (see entt_traits for more details).
- * @tparam Owned Types of components owned by the group.
- * @tparam Get Types of components observed by the group.
- * @tparam Exclude Types of components used to filter the group.
+ * @tparam Owned Types of storage _owned_ by the group.
+ * @tparam Get Types of storage _observed_ by the group.
+ * @tparam Exclude Types of storage used to filter the group.
  */
-template<typename Entity, typename... Owned, typename... Get, typename... Exclude>
-class basic_group<Entity, owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> {
+template<typename... Owned, typename... Get, typename... Exclude>
+class basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> {
+    using underlying_type = std::common_type_t<typename Owned::entity_type..., typename Get::entity_type..., typename Exclude::entity_type...>;
+    using basic_common_type = std::common_type_t<typename Owned::base_type..., typename Get::base_type..., typename Exclude::base_type...>;
+
     /*! @brief A registry is allowed to create groups. */
-    friend class basic_registry<Entity>;
+    friend class basic_registry<underlying_type>;
 
     template<typename Comp>
-    static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Comp>, type_list<std::remove_const_t<Owned>..., std::remove_const_t<Get>...>>;
+    static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Comp>, type_list<typename Owned::value_type..., typename Get::value_type...>>;
 
-    basic_group(const std::size_t &extent, storage_for_t<Owned, Entity> &...opool, storage_for_t<Get, Entity> &...gpool) noexcept
+    basic_group(const std::size_t &extent, Owned &...opool, Get &...gpool) noexcept
         : pools{&opool..., &gpool...},
           length{&extent} {}
 
 public:
     /*! @brief Underlying entity identifier. */
-    using entity_type = Entity;
+    using entity_type = underlying_type;
     /*! @brief Unsigned integer type. */
     using size_type = std::size_t;
     /*! @brief Common type among all storage types. */
-    using base_type = std::common_type_t<typename storage_for_t<Owned, entity_type>::base_type..., typename storage_for_t<Get, entity_type>::base_type...>;
+    using base_type = basic_common_type;
     /*! @brief Random access iterator type. */
     using iterator = typename base_type::iterator;
     /*! @brief Reversed iterator type. */
     using reverse_iterator = typename base_type::reverse_iterator;
     /*! @brief Iterable group type. */
-    using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<storage_for_t<Owned, entity_type>...>, get_t<storage_for_t<Get, entity_type>...>>>;
+    using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<Owned...>, get_t<Get...>>>;
 
     /*! @brief Default constructor to use to create empty, invalid groups. */
     basic_group() noexcept
@@ -573,8 +575,8 @@ public:
     }
 
     /**
-     * @brief Returns the number of entities that have the given components.
-     * @return Number of entities that have the given components.
+     * @brief Returns the number of entities that that are part of the group.
+     * @return Number of entities that that are part of the group.
      */
     [[nodiscard]] size_type size() const noexcept {
         return *this ? *length : size_type{};
@@ -830,17 +832,17 @@ public:
             std::get<0>(pools)->sort_n(*length, std::move(comp), std::move(algo), std::forward<Args>(args)...);
         }
 
-        [this](auto &head, auto &...other) {
+        std::apply([this](auto *head, auto *...other) {
             for(auto next = *length; next; --next) {
                 const auto pos = next - 1;
-                [[maybe_unused]] const auto entt = head.data()[pos];
-                (other.swap_elements(other.data()[pos], entt), ...);
+                [[maybe_unused]] const auto entt = head->data()[pos];
+                (other->swap_elements(other->data()[pos], entt), ...);
             }
-        }(*std::get<index_of<Owned>>(pools)...);
+        }, pools);
     }
 
 private:
-    const std::tuple<storage_for_t<Owned, entity_type> *..., storage_for_t<Get, entity_type> *...> pools;
+    const std::tuple<Owned *..., Get *...> pools;
     const size_type *const length;
 };
 

+ 17 - 11
src/entt/entity/helper.hpp

@@ -49,7 +49,17 @@ private:
  * @tparam Registry Basic registry type.
  */
 template<typename Registry>
-struct as_group {
+class as_group {
+    template<typename... Owned, typename... Get, typename... Exclude>
+    auto dispatch(owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>) const {
+        if constexpr(std::is_const_v<registry_type>) {
+            return reg.template group_if_exists<typename Owned::value_type...>(get_t<typename Get::value_type...>{}, exclude_t<typename Exclude::value_type...>{});
+        } else {
+            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>...>{});
+        }
+    }
+
+public:
     /*! @brief Type of registry to convert. */
     using registry_type = Registry;
     /*! @brief Underlying entity identifier. */
@@ -64,18 +74,14 @@ struct as_group {
 
     /**
      * @brief Conversion function from a registry to a group.
-     * @tparam Get Types of components observed by the group.
-     * @tparam Exclude Types of components used to filter the group.
-     * @tparam Owned Types of components owned by the 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<typename Get, typename Exclude, typename... Owned>
-    operator basic_group<entity_type, owned_t<Owned...>, Get, Exclude>() const {
-        if constexpr(std::is_const_v<registry_type>) {
-            return reg.template group_if_exists<Owned...>(Get{}, Exclude{});
-        } else {
-            return reg.template group<Owned...>(Get{}, Exclude{});
-        }
+    template<typename Owned, typename Get, typename Exclude>
+    operator basic_group<Owned, Get, Exclude>() const {
+        return dispatch(Owned{}, Get{}, Exclude{});
     }
 
 private:

+ 13 - 10
src/entt/entity/registry.hpp

@@ -221,6 +221,9 @@ class basic_registry {
     using entity_traits = entt_traits<Entity>;
     using basic_common_type = basic_sparse_set<Entity>;
 
+    template<typename Owned, typename Get, typename Exclude>
+    using group_type = basic_group<type_list_transform_t<Owned, storage_for>, type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
+
     template<typename...>
     struct group_handler;
 
@@ -1244,13 +1247,13 @@ public:
      * The group takes the ownership of the pools and arrange components so as
      * to iterate them as fast as possible.
      *
-     * @tparam Owned Types of components owned by the group.
-     * @tparam Get Types of components observed by the group.
-     * @tparam Exclude Types of components used to filter the group.
+     * @tparam Owned Type of storage _owned_ by the group.
+     * @tparam Get Type of storage _observed_ by the group.
+     * @tparam Exclude Type of storage used to filter the group.
      * @return A newly created group.
      */
     template<typename... Owned, typename... Get, typename... Exclude>
-    [[nodiscard]] basic_group<entity_type, owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> group(get_t<Get...> = {}, exclude_t<Exclude...> = {}) {
+    [[nodiscard]] group_type<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> group(get_t<Get...> = {}, exclude_t<Exclude...> = {}) {
         static_assert(sizeof...(Owned) + sizeof...(Get) > 0, "Exclusion-only groups are not supported");
         static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1, "Single component groups are not allowed");
 
@@ -1332,7 +1335,7 @@ public:
 
     /*! @copydoc group */
     template<typename... Owned, typename... Get, typename... Exclude>
-    [[nodiscard]] basic_group<entity_type, owned_t<const Owned...>, get_t<const Get...>, exclude_t<const Exclude...>> group_if_exists(get_t<Get...> = {}, exclude_t<Exclude...> = {}) const {
+    [[nodiscard]] group_type<owned_t<const Owned...>, get_t<const Get...>, exclude_t<const Exclude...>> group_if_exists(get_t<Get...> = {}, exclude_t<Exclude...> = {}) const {
         auto it = std::find_if(groups.cbegin(), groups.cend(), [](const auto &gdata) {
             return gdata.size == (sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude))
                    && (gdata.owned(type_hash<std::remove_const_t<Owned>>::value()) && ...)
@@ -1361,15 +1364,15 @@ public:
 
     /**
      * @brief Checks whether a group can be sorted.
-     * @tparam Owned Types of components owned by the group.
-     * @tparam Get Types of components observed by the group.
-     * @tparam Exclude Types of components used to filter the group.
+     * @tparam Owned Type of storage _owned_ by the group.
+     * @tparam Get Type of storage _observed_ by the group.
+     * @tparam Exclude Type of storage used to filter the group.
      * @return True if the group can be sorted, false otherwise.
      */
     template<typename... Owned, typename... Get, typename... Exclude>
-    [[nodiscard]] bool sortable(const basic_group<entity_type, owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> &) noexcept {
+    [[nodiscard]] bool sortable(const basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> &) noexcept {
         constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
-        auto pred = [size](const auto &gdata) { return (0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value())) && (size < gdata.size); };
+        auto pred = [size](const auto &gdata) { return (0u + ... + gdata.owned(type_hash<typename Owned::value_type>::value())) && (size < gdata.size); };
         return std::find_if(groups.cbegin(), groups.cend(), std::move(pred)) == groups.cend();
     }