Selaa lähdekoodia

registry: prepare to rework groups

Michele Caini 3 vuotta sitten
vanhempi
commit
56c3917841
3 muutettua tiedostoa jossa 107 lisäystä ja 52 poistoa
  1. 98 43
      src/entt/entity/registry.hpp
  2. 4 4
      test/entt/entity/group.cpp
  3. 5 5
      test/entt/entity/registry.cpp

+ 98 - 43
src/entt/entity/registry.hpp

@@ -1247,25 +1247,23 @@ public:
      * to iterate them as fast as possible.
      *
      * @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.
+     * @tparam Other Other types of storage _owned_ by the group.
+     * @tparam Get Type of storage _observed_ by the group, if any.
+     * @tparam Exclude Type of storage used to filter the group, if any.
      * @return A newly created group.
      */
-    template<typename... Owned, typename... Get, typename... Exclude>
-    [[nodiscard]] basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>
+    template<typename Owned, typename... Other, typename... Get, typename... Exclude>
+    [[nodiscard]] basic_group<owned_t<storage_for_type<Owned>, storage_for_type<Other>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<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");
-
-        using handler_type = group_handler<exclude_t<std::remove_const_t<Exclude>...>, get_t<std::remove_const_t<Get>...>, std::remove_const_t<Owned>...>;
+        using handler_type = group_handler<exclude_t<std::remove_const_t<Exclude>...>, get_t<std::remove_const_t<Get>...>, std::remove_const_t<Owned>, std::remove_const_t<Other>...>;
 
-        const auto cpools = std::forward_as_tuple(assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...);
-        constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
+        const auto cpools = std::forward_as_tuple(assure<std::remove_const_t<Owned>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Get>>()...);
+        constexpr auto size = 1u + sizeof...(Other) + sizeof...(Get) + sizeof...(Exclude);
         handler_type *handler = nullptr;
 
         auto it = std::find_if(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
             return gdata.size == size
-                   && (gdata.owned(type_hash<std::remove_const_t<Owned>>::value()) && ...)
+                   && (gdata.owned(type_hash<std::remove_const_t<Owned>>::value()) && ... && gdata.owned(type_hash<std::remove_const_t<Other>>::value()))
                    && (gdata.get(type_hash<std::remove_const_t<Get>>::value()) && ...)
                    && (gdata.exclude(type_hash<std::remove_const_t<Exclude>>::value()) && ...);
         });
@@ -1276,7 +1274,7 @@ public:
             group_data candidate = {
                 size,
                 std::apply([this](auto &&...args) { return std::allocate_shared<handler_type>(get_allocator(), std::forward<decltype(args)>(args)...); }, entt::uses_allocator_construction_args<typename handler_type::value_type>(get_allocator())),
-                []([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == type_hash<std::remove_const_t<Owned>>::value()) || ...); },
+                []([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == type_hash<std::remove_const_t<Owned>>::value()) || ... || (ctype == type_hash<std::remove_const_t<Other>>::value())); },
                 []([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == type_hash<std::remove_const_t<Get>>::value()) || ...); },
                 []([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == type_hash<std::remove_const_t<Exclude>>::value()) || ...); },
             };
@@ -1286,51 +1284,108 @@ public:
             const void *maybe_valid_if = nullptr;
             const void *discard_if = nullptr;
 
-            if constexpr(sizeof...(Owned) == 0) {
-                groups.push_back(std::move(candidate));
-            } else {
-                [[maybe_unused]] auto has_conflict = [size](const auto &gdata) {
-                    const auto overlapping = (0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value()));
-                    const auto sz = overlapping + (0u + ... + gdata.get(type_hash<std::remove_const_t<Get>>::value())) + (0u + ... + gdata.exclude(type_hash<std::remove_const_t<Exclude>>::value()));
-                    return !overlapping || ((sz == size) || (sz == gdata.size));
-                };
+            [[maybe_unused]] auto has_conflict = [size](const auto &gdata) {
+                const auto overlapping = (gdata.owned(type_hash<std::remove_const_t<Owned>>::value()) + ... + gdata.owned(type_hash<std::remove_const_t<Other>>::value()));
+                const auto sz = overlapping + (0u + ... + gdata.get(type_hash<std::remove_const_t<Get>>::value())) + (0u + ... + gdata.exclude(type_hash<std::remove_const_t<Exclude>>::value()));
+                return !overlapping || ((sz == size) || (sz == gdata.size));
+            };
 
-                ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), std::move(has_conflict)), "Conflicting groups");
+            ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), std::move(has_conflict)), "Conflicting groups");
 
-                const auto next = std::find_if_not(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
-                    return !(0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value())) || (size > gdata.size);
-                });
+            const auto next = std::find_if_not(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
+                return !(gdata.owned(type_hash<std::remove_const_t<Owned>>::value()) + ... + gdata.owned(type_hash<std::remove_const_t<Other>>::value())) || (size > gdata.size);
+            });
 
-                const auto prev = std::find_if(std::make_reverse_iterator(next), groups.crend(), [](const auto &gdata) {
-                    return (0u + ... + gdata.owned(type_hash<std::remove_const_t<Owned>>::value()));
-                });
+            const auto prev = std::find_if(std::make_reverse_iterator(next), groups.crend(), [](const auto &gdata) {
+                return (gdata.owned(type_hash<std::remove_const_t<Owned>>::value()) + ... + gdata.owned(type_hash<std::remove_const_t<Other>>::value()));
+            });
 
-                maybe_valid_if = (next == groups.cend() ? maybe_valid_if : next->group.get());
-                discard_if = (prev == groups.crend() ? discard_if : prev->group.get());
-                groups.insert(next, std::move(candidate));
-            }
+            maybe_valid_if = (next == groups.cend() ? maybe_valid_if : next->group.get());
+            discard_if = (prev == groups.crend() ? discard_if : prev->group.get());
+            groups.insert(next, std::move(candidate));
 
-            (on_construct<std::remove_const_t<Owned>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Owned>>>(*handler), ...);
+            on_construct<std::remove_const_t<Owned>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Owned>>>(*handler);
+            (on_construct<std::remove_const_t<Other>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Other>>>(*handler), ...);
             (on_construct<std::remove_const_t<Get>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Get>>>(*handler), ...);
             (on_destroy<std::remove_const_t<Exclude>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Exclude>>>(*handler), ...);
 
-            (on_destroy<std::remove_const_t<Owned>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
+            on_destroy<std::remove_const_t<Owned>>().before(discard_if).template connect<&handler_type::discard_if>(*handler);
+            (on_destroy<std::remove_const_t<Other>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
             (on_destroy<std::remove_const_t<Get>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
             (on_construct<std::remove_const_t<Exclude>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
 
-            if constexpr(sizeof...(Owned) == 0) {
-                for(const auto entity: view<Owned..., Get...>(exclude<Exclude...>)) {
-                    handler->current.push(entity);
-                }
-            } else {
-                // we cannot iterate backwards because we want to leave behind valid entities in case of owned types
-                for(auto *first = std::get<0>(cpools).data(), *last = first + std::get<0>(cpools).size(); first != last; ++first) {
-                    handler->template maybe_valid_if<type_list_element_t<0, type_list<std::remove_const_t<Owned>...>>>(*this, *first);
-                }
+            // we cannot iterate backwards because we want to leave behind valid entities in case of owned types
+            for(auto *first = std::get<0>(cpools).data(), *last = first + std::get<0>(cpools).size(); first != last; ++first) {
+                handler->template maybe_valid_if<Owned>(*this, *first);
+            }
+        }
+
+        return {
+            handler->current,
+            std::get<storage_for_type<std::remove_const_t<Owned>> &>(cpools),
+            std::get<storage_for_type<std::remove_const_t<Other>> &>(cpools)...,
+            std::get<storage_for_type<std::remove_const_t<Get>> &>(cpools)...,
+            assure<std::remove_const_t<Exclude>>()...};
+    }
+
+    /**
+     * @brief Returns a group for the given components.
+     * @tparam Get Type of storage _observed_ by the group.
+     * @tparam Other Other types of storage _observed_ by the group.
+     * @tparam Exclude Type of storage used to filter the group.
+     * @return A newly created group.
+     */
+    template<typename Get, typename... Other, typename... Exclude>
+    [[nodiscard]] basic_group<owned_t<>, get_t<storage_for_type<Get>, storage_for_type<Other>...>, exclude_t<storage_for_type<Exclude>...>>
+    group(get_t<Get, Other...>, exclude_t<Exclude...> = {}) {
+        using handler_type = group_handler<exclude_t<std::remove_const_t<Exclude>...>, get_t<std::remove_const_t<Get>, std::remove_const_t<Other>...>>;
+
+        const auto cpools = std::forward_as_tuple(assure<std::remove_const_t<Get>>(), assure<std::remove_const_t<Other>>()...);
+        constexpr auto size = 1u + sizeof...(Other) + sizeof...(Exclude);
+        handler_type *handler = nullptr;
+
+        auto it = std::find_if(groups.cbegin(), groups.cend(), [size](const auto &gdata) {
+            return gdata.size == size
+                   && (gdata.get(type_hash<std::remove_const_t<Get>>::value()) && ... && gdata.get(type_hash<std::remove_const_t<Other>>::value()))
+                   && (gdata.exclude(type_hash<std::remove_const_t<Exclude>>::value()) && ...);
+        });
+
+        if(it != groups.cend()) {
+            handler = static_cast<handler_type *>(it->group.get());
+        } else {
+            group_data candidate = {
+                size,
+                std::apply([this](auto &&...args) { return std::allocate_shared<handler_type>(get_allocator(), std::forward<decltype(args)>(args)...); }, entt::uses_allocator_construction_args<typename handler_type::value_type>(get_allocator())),
+                []([[maybe_unused]] const id_type ctype) noexcept { return false; },
+                []([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == type_hash<std::remove_const_t<Get>>::value()) || ... || (ctype == type_hash<std::remove_const_t<Other>>::value())); },
+                []([[maybe_unused]] const id_type ctype) noexcept { return ((ctype == type_hash<std::remove_const_t<Exclude>>::value()) || ...); },
+            };
+
+            handler = static_cast<handler_type *>(candidate.group.get());
+
+            const void *maybe_valid_if = nullptr;
+            const void *discard_if = nullptr;
+
+            groups.push_back(std::move(candidate));
+
+            on_construct<std::remove_const_t<Get>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Get>>>(*handler);
+            (on_construct<std::remove_const_t<Other>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Other>>>(*handler), ...);
+            (on_destroy<std::remove_const_t<Exclude>>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<std::remove_const_t<Exclude>>>(*handler), ...);
+
+            on_destroy<std::remove_const_t<Get>>().before(discard_if).template connect<&handler_type::discard_if>(*handler);
+            (on_destroy<std::remove_const_t<Other>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
+            (on_construct<std::remove_const_t<Exclude>>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
+
+            for(const auto entity: view<Get, Other...>(exclude<Exclude...>)) {
+                handler->current.push(entity);
             }
         }
 
-        return {handler->current, std::get<storage_for_type<std::remove_const_t<Owned>> &>(cpools)..., std::get<storage_for_type<std::remove_const_t<Get>> &>(cpools)..., assure<std::remove_const_t<Exclude>>()...};
+        return {
+            handler->current,
+            std::get<storage_for_type<std::remove_const_t<Get>> &>(cpools),
+            std::get<storage_for_type<std::remove_const_t<Other>> &>(cpools)...,
+            assure<std::remove_const_t<Exclude>>()...};
     }
 
     /*! @copydoc group */

+ 4 - 4
test/entt/entity/group.cpp

@@ -1060,7 +1060,7 @@ TEST(OwningGroup, SortUnordered) {
 
 TEST(OwningGroup, SortWithExclusionList) {
     entt::registry registry;
-    auto group = registry.group<boxed_int>({}, entt::exclude<char>);
+    auto group = registry.group<boxed_int>(entt::get<>, entt::exclude<char>);
 
     entt::entity entities[5]{};
     registry.create(std::begin(entities), std::end(entities));
@@ -1226,7 +1226,7 @@ TEST(OwningGroup, ExcludedComponents) {
     registry.emplace<int>(e1, 1);
     registry.emplace<char>(e1);
 
-    const auto group = registry.group<int>({}, entt::exclude<char, double>);
+    const auto group = registry.group<int>(entt::get<>, entt::exclude<char, double>);
 
     const auto e2 = registry.create();
     registry.emplace<int>(e2, 2);
@@ -1297,8 +1297,8 @@ TEST(OwningGroup, EmptyAndNonEmptyTypes) {
 
 TEST(OwningGroup, TrackEntitiesOnComponentDestruction) {
     entt::registry registry;
-    const auto group = registry.group<int>({}, entt::exclude<char>);
-    const auto cgroup = std::as_const(registry).group_if_exists<const int>({}, entt::exclude<char>);
+    const auto group = registry.group<int>(entt::get<>, entt::exclude<char>);
+    const auto cgroup = std::as_const(registry).group_if_exists<const int>(entt::get<>, entt::exclude<char>);
 
     const auto entity = registry.create();
     registry.emplace<int>(entity);

+ 5 - 5
test/entt/entity/registry.cpp

@@ -1026,7 +1026,7 @@ TEST(Registry, NonOwningGroupInitOnFirstUse) {
     registry.emplace<char>(entities[2u], 'c');
 
     std::size_t cnt{};
-    auto group = registry.group<>(entt::get<int, char>);
+    auto group = registry.group(entt::get<int, char>);
     group.each([&cnt](auto...) { ++cnt; });
 
     ASSERT_FALSE((registry.owned<int, char>()));
@@ -1036,7 +1036,7 @@ TEST(Registry, NonOwningGroupInitOnFirstUse) {
 TEST(Registry, NonOwningGroupInitOnEmplace) {
     entt::registry registry;
     entt::entity entities[3u];
-    auto group = registry.group<>(entt::get<int, char>);
+    auto group = registry.group(entt::get<int, char>);
 
     registry.create(std::begin(entities), std::end(entities));
     registry.insert<int>(std::begin(entities), std::end(entities), 0);
@@ -1159,7 +1159,7 @@ TEST(Registry, CleanViewAfterRemoveAndClear) {
 
 TEST(Registry, CleanNonOwningGroupViewAfterRemoveAndClear) {
     entt::registry registry;
-    auto group = registry.group<>(entt::get<int, char>);
+    auto group = registry.group(entt::get<int, char>);
 
     const auto entity = registry.create();
     registry.emplace<int>(entity, 0);
@@ -1916,7 +1916,7 @@ TEST(Registry, NonOwningGroupInterleaved) {
     registry.emplace<int>(entity);
     registry.emplace<char>(entity);
 
-    const auto group = registry.group<>(entt::get<int, char>);
+    const auto group = registry.group(entt::get<int, char>);
 
     entity = registry.create();
     registry.emplace<int>(entity);
@@ -1970,7 +1970,7 @@ TEST(Registry, PartialOwningGroupInterleaved) {
 
 TEST(Registry, NonOwningGroupSortInterleaved) {
     entt::registry registry;
-    const auto group = registry.group<>(entt::get<int, char>);
+    const auto group = registry.group(entt::get<int, char>);
 
     const auto e0 = registry.create();
     registry.emplace<int>(e0, 0);