Преглед изворни кода

runtime view: swap-only policy support - close #1252

skypjack пре 10 месеци
родитељ
комит
3b977186ed
2 измењених фајлова са 69 додато и 6 уклоњено
  1. 15 6
      src/entt/entity/runtime_view.hpp
  2. 54 0
      test/entt/entity/runtime_view.cpp

+ 15 - 6
src/entt/entity/runtime_view.hpp

@@ -126,6 +126,12 @@ class basic_runtime_view {
     static_assert(std::is_same_v<typename alloc_traits::value_type, Type *>, "Invalid value type");
     using container_type = std::vector<Type *, Allocator>;
 
+    [[nodiscard]] auto offset() const noexcept {
+        ENTT_ASSERT(!pools.empty(), "Invalid view");
+        const auto &leading = *pools.front();
+        return (leading.policy() == deletion_policy::swap_only) ? leading.free_list() : leading.size();
+    }
+
 public:
     /*! @brief Allocator type. */
     using allocator_type = Allocator;
@@ -133,6 +139,8 @@ public:
     using entity_type = typename Type::entity_type;
     /*! @brief Unsigned integer type. */
     using size_type = std::size_t;
+    /*! @brief Signed integer type. */
+    using difference_type = std::ptrdiff_t;
     /*! @brief Common type among all storage types. */
     using common_type = Type;
     /*! @brief Bidirectional iterator type. */
@@ -219,10 +227,10 @@ public:
      * @return This runtime view.
      */
     basic_runtime_view &iterate(common_type &base) {
-        if(pools.empty() || !(base.size() < pools[0u]->size())) {
+        if(pools.empty() || !(base.size() < pools.front()->size())) {
             pools.push_back(&base);
         } else {
-            pools.push_back(std::exchange(pools[0u], &base));
+            pools.push_back(std::exchange(pools.front(), &base));
         }
 
         return *this;
@@ -243,7 +251,7 @@ public:
      * @return Estimated number of entities iterated by the view.
      */
     [[nodiscard]] size_type size_hint() const {
-        return pools.empty() ? size_type{} : pools.front()->size();
+        return pools.empty() ? size_type{} : offset();
     }
 
     /**
@@ -255,7 +263,7 @@ public:
      * @return An iterator to the first entity that has the given elements.
      */
     [[nodiscard]] iterator begin() const {
-        return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->begin()};
+        return pools.empty() ? iterator{} : iterator{pools, filter, pools.front()->end() - static_cast<difference_type>(offset())};
     }
 
     /**
@@ -265,7 +273,7 @@ public:
      * given elements.
      */
     [[nodiscard]] iterator end() const {
-        return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->end()};
+        return pools.empty() ? iterator{} : iterator{pools, filter, pools.front()->end()};
     }
 
     /**
@@ -284,7 +292,8 @@ public:
     [[nodiscard]] bool contains(const entity_type entt) const {
         return !pools.empty()
                && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
-               && std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
+               && std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); })
+               && pools.front()->index(entt) < offset();
     }
 
     /**

+ 54 - 0
test/entt/entity/runtime_view.cpp

@@ -73,6 +73,27 @@ TYPED_TEST(RuntimeView, Functionalities) {
     ASSERT_EQ(view.begin(), view.end());
 }
 
+TYPED_TEST(RuntimeView, InvalidView) {
+    using runtime_view_type = typename TestFixture::type;
+
+    runtime_view_type view{};
+
+    ASSERT_FALSE(view);
+
+    ASSERT_EQ(view.size_hint(), 0u);
+    ASSERT_FALSE(view.contains(entt::null));
+
+    ASSERT_EQ(view.begin(), typename decltype(view)::iterator{});
+    ASSERT_EQ(view.begin(), view.end());
+
+    view.each([](const entt::entity) { FAIL(); });
+
+    entt::storage<int> storage;
+    view.iterate(storage);
+
+    ASSERT_TRUE(view);
+}
+
 TYPED_TEST(RuntimeView, Constructors) {
     using runtime_view_type = typename TestFixture::type;
 
@@ -516,3 +537,36 @@ TYPED_TEST(RuntimeView, StorageEntityWithExclude) {
         ASSERT_EQ(entt, entity[1u]);
     });
 }
+
+TYPED_TEST(RuntimeView, StorageEntityExcludeOnly) {
+    using runtime_view_type = typename TestFixture::type;
+
+    std::tuple<entt::storage<entt::entity>, entt::storage<int>> storage{};
+    const std::array entity{std::get<0>(storage).generate(), std::get<0>(storage).generate(), std::get<0>(storage).generate()};
+    runtime_view_type view{};
+
+    std::get<1>(storage).emplace(entity[2u]);
+
+    std::get<0>(storage).erase(entity[0u]);
+    std::get<0>(storage).bump(entity[0u]);
+
+    view.iterate(std::get<0>(storage)).exclude(std::get<1>(storage));
+
+    ASSERT_FALSE(view.contains(entity[0u]));
+    ASSERT_TRUE(view.contains(entity[1u]));
+    ASSERT_FALSE(view.contains(entity[2u]));
+
+    ASSERT_EQ(view.size_hint(), 2u);
+    ASSERT_NE(view.begin(), view.end());
+
+    ASSERT_EQ(std::distance(view.begin(), view.end()), 1);
+    ASSERT_EQ(*view.begin(), entity[1u]);
+
+    for(auto entt: view) {
+        ASSERT_EQ(entt, entity[1u]);
+    }
+
+    view.each([&entity](auto entt) {
+        ASSERT_EQ(entt, entity[1u]);
+    });
+}