Pārlūkot izejas kodu

view: make view pack also work with empty views

Michele Caini 2 gadi atpakaļ
vecāks
revīzija
d90363e4a4
2 mainītis faili ar 42 papildinājumiem un 10 dzēšanām
  1. 16 6
      src/entt/entity/view.hpp
  2. 26 4
      test/entt/entity/view.cpp

+ 16 - 6
src/entt/entity/view.hpp

@@ -31,6 +31,14 @@ template<typename Type, std::size_t N>
     return std::apply([entt](const auto *...curr) { return (!curr->contains(entt) && ...); }, filter);
 }
 
+template<typename... Get, typename... Exclude, std::size_t... Index>
+[[nodiscard]] auto view_pack(const std::tuple<Get *...> value, const std::tuple<Exclude *...> excl, std::index_sequence<Index...>) {
+    const auto pools = std::tuple_cat(value, excl);
+    basic_view<get_t<Get...>, exclude_t<Exclude...>> elem{};
+    (((std::get<Index>(pools) != nullptr) ? elem.storage<Index>(*std::get<Index>(pools)) : void()), ...);
+    return elem;
+}
+
 template<typename Type, std::size_t Get, std::size_t Exclude>
 class view_iterator final {
     using iterator_type = typename Type::const_iterator;
@@ -539,9 +547,10 @@ public:
      */
     template<typename... OGet, typename... OExclude>
     [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
-        return std::apply(
-            [](auto *...curr) { return basic_view<get_t<Get..., OGet...>, exclude_t<Exclude..., OExclude...>>{*curr...}; },
-            std::tuple_cat(pools, other.pools, internal::filter_as_tuple<Exclude...>(filter), internal::filter_as_tuple<OExclude...>(other.filter)));
+        return internal::view_pack(
+            std::tuple_cat(pools, other.pools),
+            std::tuple_cat(internal::filter_as_tuple<Exclude...>(filter), internal::filter_as_tuple<OExclude...>(other.filter)),
+            std::index_sequence_for<Get..., OGet..., Exclude..., OExclude...>{});
     }
 
 private:
@@ -879,9 +888,10 @@ public:
      */
     template<typename... OGet, typename... OExclude>
     [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
-        return std::apply(
-            [](auto *...curr) { return basic_view<get_t<Get, OGet...>, exclude_t<OExclude...>>{*curr...}; },
-            std::tuple_cat(pools, other.pools, internal::filter_as_tuple<OExclude...>(other.filter)));
+        return internal::view_pack(
+            std::tuple_cat(pools, other.pools),
+            internal::filter_as_tuple<OExclude...>(other.filter),
+            std::index_sequence_for<Get, OGet..., OExclude...>{});
     }
 
 private:

+ 26 - 4
test/entt/entity/view.cpp

@@ -1421,10 +1421,10 @@ TEST(View, Pipe) {
     registry.emplace<char>(other);
     registry.emplace<stable_type>(other);
 
-    const auto view1 = registry.view<int>(entt::exclude<const double>);
-    const auto view2 = registry.view<const char>(entt::exclude<float>);
-    const auto view3 = registry.view<empty_type>();
-    const auto view4 = registry.view<stable_type>();
+    auto view1 = registry.view<int>(entt::exclude<const double>);
+    auto view2 = registry.view<const char>(entt::exclude<float>);
+    auto view3 = registry.view<empty_type>();
+    auto view4 = registry.view<stable_type>();
 
     static_assert(std::is_same_v<entt::basic_view<entt::get_t<entt::storage_type_t<int>, const entt::storage_type_t<char>>, entt::exclude_t<const entt::storage_type_t<double>, entt::storage_type_t<float>>>, decltype(view1 | view2)>);
     static_assert(std::is_same_v<entt::basic_view<entt::get_t<const entt::storage_type_t<char>, entt::storage_type_t<int>>, entt::exclude_t<entt::storage_type_t<float>, const entt::storage_type_t<double>>>, decltype(view2 | view1)>);
@@ -1441,4 +1441,26 @@ TEST(View, Pipe) {
 
     ASSERT_FALSE((view1 | view4 | view2).contains(entity));
     ASSERT_TRUE((view1 | view4 | view2).contains(other));
+
+    view1 = {};
+    view3 = {};
+
+    ASSERT_FALSE(view1);
+    ASSERT_TRUE(view2);
+    ASSERT_FALSE(view3);
+    ASSERT_TRUE(view4);
+
+    auto pack14 = view1 | view4;
+    auto pack32 = view3 | view2;
+
+    ASSERT_FALSE(pack14);
+    ASSERT_FALSE(pack32);
+
+    ASSERT_EQ(pack14.storage<int>(), nullptr);
+    ASSERT_EQ(pack14.storage<const double>(), nullptr);
+    ASSERT_NE(pack14.storage<stable_type>(), nullptr);
+
+    ASSERT_EQ(pack32.storage<empty_type>(), nullptr);
+    ASSERT_NE(pack32.storage<const char>(), nullptr);
+    ASSERT_NE(pack32.storage<float>(), nullptr);
 }