Explorar el Código

view: allow swapping storage elements of a view

Michele Caini hace 2 años
padre
commit
80563b9557
Se han modificado 3 ficheros con 122 adiciones y 4 borrados
  1. 1 0
      TODO
  2. 52 4
      src/entt/entity/view.hpp
  3. 69 0
      test/entt/entity/view.cpp

+ 1 - 0
TODO

@@ -7,6 +7,7 @@ DOC:
 * examples (and credits) from @alanjfs :)
 * update entity doc when the storage based model is in place
 * in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
+* storage swap on views and empty views (once the static storage in the registry is removed)
 
 TODO (high prio):
 * check natvis files (periodically :)

+ 52 - 4
src/entt/entity/view.hpp

@@ -199,6 +199,7 @@ class basic_view;
  */
 template<typename... Get, typename... Exclude>
 class basic_view<get_t<Get...>, exclude_t<Exclude...>> {
+    static constexpr auto offset = sizeof...(Get);
     using base_type = std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>;
     using underlying_type = typename base_type::entity_type;
 
@@ -267,7 +268,7 @@ public:
     basic_view(Get &...value, Exclude &...excl) noexcept
         : pools{&value...},
           filter{&excl...},
-          view{std::get<0>(pools)} {
+          view{} {
         refresh();
     }
 
@@ -299,7 +300,8 @@ public:
 
     /*! @brief Updates the internal leading view if required. */
     void refresh() noexcept {
-        std::apply([this](auto *...elem) { ((this->view = elem->size() < this->view->size() ? elem : this->view), ...); }, pools);
+        view = std::get<0>(pools);
+        std::apply([this](auto *, auto *...other) { ((this->view = other->size() < this->view->size() ? other : this->view), ...); }, pools);
     }
 
     /**
@@ -327,8 +329,6 @@ public:
      */
     template<std::size_t Index>
     [[nodiscard]] auto *storage() const noexcept {
-        constexpr auto offset = sizeof...(Get);
-
         if constexpr(Index < offset) {
             return std::get<Index>(pools);
         } else {
@@ -336,6 +336,36 @@ public:
         }
     }
 
+    /**
+     * @brief Assigns a storage to a view.
+     * @tparam Type Type of storage to assign to the view.
+     * @param elem A storage to assign to the view.
+     */
+    template<typename Type>
+    void storage(Type &elem) noexcept {
+        storage<index_of<typename Type::value_type>>(elem);
+    }
+
+    /**
+     * @brief Assigns a storage to a view.
+     * @tparam Index Index of the storage to assign to the view.
+     * @tparam Type Type of storage to assign to the view.
+     * @param elem A storage to assign to the view.
+     */
+    template<std::size_t Index, typename Type>
+    void storage(Type &elem) noexcept {
+        if constexpr(Index < offset) {
+            view = (std::get<Index>(pools) == view ? nullptr : view);
+            std::get<Index>(pools) = &elem;
+        } else {
+            std::get<Index - offset>(filter) = &elem;
+        }
+
+        if(view == nullptr && std::apply([](const auto *...curr) { return ((curr != nullptr) && ...); }, pools)) {
+            refresh();
+        }
+    }
+
     /**
      * @brief Estimates the number of entities iterated by the view.
      * @return Estimated number of entities iterated by the view.
@@ -610,6 +640,24 @@ public:
         return std::get<Index>(pools);
     }
 
+    /**
+     * @brief Assigns a storage to a view.
+     * @param elem A storage to assign to the view.
+     */
+    void storage(Get &elem) noexcept {
+        storage<0>(elem);
+    }
+
+    /**
+     * @brief Assigns a storage to a view.
+     * @tparam Index Index of the storage to assign to the view.
+     * @param elem A storage to assign to the view.
+     */
+    template<std::size_t Index>
+    void storage(Get &elem) noexcept {
+        view = std::get<Index>(pools) = &elem;
+    }
+
     /**
      * @brief Returns the number of entities that have the given component.
      * @return Number of entities that have the given component.

+ 69 - 0
test/entt/entity/view.cpp

@@ -509,6 +509,41 @@ TEST(SingleComponentView, Storage) {
     ASSERT_EQ(cview.storage<const char>(), nullptr);
 }
 
+TEST(SingleComponentView, SwapStorage) {
+    using namespace entt::literals;
+
+    entt::registry registry;
+    entt::basic_view<entt::get_t<entt::storage<int>>, entt::exclude_t<>> view;
+    entt::basic_view<entt::get_t<const entt::storage<int>>, entt::exclude_t<>> cview;
+
+    ASSERT_FALSE(view);
+    ASSERT_FALSE(cview);
+    ASSERT_EQ(view.storage<0u>(), nullptr);
+    ASSERT_EQ(cview.storage<const int>(), nullptr);
+
+    const entt::entity entity{42u};
+    registry.emplace<int>(entity);
+
+    view.storage(registry.storage<int>());
+    cview.storage(registry.storage<int>());
+
+    ASSERT_TRUE(view);
+    ASSERT_TRUE(cview);
+    ASSERT_NE(view.storage<0u>(), nullptr);
+    ASSERT_NE(cview.storage<const int>(), nullptr);
+
+    ASSERT_EQ(view.size(), 1u);
+    ASSERT_EQ(cview.size(), 1u);
+    ASSERT_TRUE(view.contains(entity));
+    ASSERT_TRUE(cview.contains(entity));
+
+    view.storage(registry.storage<int>("other"_hs));
+    cview.storage(registry.storage<int>("other"_hs));
+
+    ASSERT_TRUE(view.empty());
+    ASSERT_TRUE(cview.empty());
+}
+
 TEST(MultiComponentView, Functionalities) {
     entt::registry registry;
     auto view = registry.view<int, char>();
@@ -1338,6 +1373,40 @@ TEST(MultiComponentView, Storage) {
     ASSERT_EQ(view.storage<const float>(), nullptr);
 }
 
+TEST(MultiComponentView, SwapStorage) {
+    using namespace entt::literals;
+
+    entt::registry registry;
+    entt::basic_view<entt::get_t<entt::storage<int>>, entt::exclude_t<const entt::storage<char>>> view;
+
+    ASSERT_FALSE(view);
+    ASSERT_EQ(view.storage<0u>(), nullptr);
+    ASSERT_EQ(view.storage<const char>(), nullptr);
+
+    const entt::entity entity{42u};
+    registry.emplace<int>(entity);
+    registry.emplace<char>(entity);
+
+    view.storage(registry.storage<int>());
+    view.storage<1u>(registry.storage<char>());
+
+    ASSERT_TRUE(view);
+    ASSERT_NE(view.storage<int>(), nullptr);
+    ASSERT_NE(view.storage<1u>(), nullptr);
+
+    ASSERT_EQ(view.size_hint(), 1u);
+    ASSERT_FALSE(view.contains(entity));
+
+    view.storage(registry.storage<char>("other"_hs));
+
+    ASSERT_EQ(view.size_hint(), 1u);
+    ASSERT_TRUE(view.contains(entity));
+
+    view.storage(registry.storage<int>("empty"_hs));
+
+    ASSERT_EQ(view.size_hint(), 0u);
+}
+
 TEST(View, Pipe) {
     entt::registry registry;
     const auto entity = registry.create();