Browse Source

view: support converting views

skypjack 2 months ago
parent
commit
e504310399
3 changed files with 67 additions and 1 deletions
  1. 0 1
      TODO
  2. 19 0
      src/entt/entity/view.hpp
  3. 48 0
      test/entt/entity/view.cpp

+ 0 - 1
TODO

@@ -32,4 +32,3 @@ TODO:
 * archetype-like a-là EnTT support (see my own notes)
 * meta: conversion_helper machinery has lot of room for improvements
 * organizer: view/storage only based model, no registry
-* view conversion function (i.e. view<T, const U, V> -> view<const T, V>)

+ 19 - 0
src/entt/entity/view.hpp

@@ -457,6 +457,13 @@ class basic_view<get_t<Get...>, exclude_t<Exclude...>, std::enable_if_t<(sizeof.
         }
     }
 
+    template<typename Type>
+    void storage_if(Type *elem) noexcept {
+        if(elem != nullptr) {
+            storage<index_of<typename Type::element_type>>(*elem);
+        }
+    }
+
 public:
     /*! @brief Common type among all storage types. */
     using common_type = base_type::common_type;
@@ -492,6 +499,18 @@ public:
     basic_view(std::tuple<Get &...> value, std::tuple<Exclude &...> excl = {}) noexcept
         : basic_view{std::make_from_tuple<basic_view>(std::tuple_cat(value, excl))} {}
 
+    /**
+     * @brief Constructs a view from a convertible counterpart.
+     * @tparam Args Storage types managed by the other view.
+     * @param other A view to convert from.
+     */
+    template<typename... Args, typename = std::enable_if_t<!std::is_same_v<basic_view, basic_view<Args...>>>>
+    basic_view(const basic_view<Args...> &other) noexcept
+        : basic_view{} {
+        (storage_if(other.storage<typename Get::element_type>()), ...);
+        (storage_if(other.storage<typename Exclude::element_type>()), ...);
+    }
+
     /**
      * @brief Forces a view to use a given element to drive iterations
      * @tparam Type Type of element to use to drive iterations.

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

@@ -682,6 +682,54 @@ TEST(MultiStorageView, Functionalities) {
     ASSERT_FALSE(invalid);
 }
 
+TEST(MultiStorageView, Conversion) {
+    entt::basic_view<entt::get_t<entt::storage<int>, const entt::storage<char>>, entt::exclude_t<entt::storage<double>, const entt::storage<float>>> view1{};
+    entt::basic_view<entt::get_t<const entt::storage<int>, const entt::storage<char>>, entt::exclude_t<const entt::storage<double>, const entt::storage<float>>> view2{view1};
+    entt::basic_view<entt::get_t<entt::storage<int>>, entt::exclude_t<const entt::storage<double>>> view3{view1};
+    entt::basic_view<entt::get_t<const entt::storage<char>>, entt::exclude_t<>> view4{view1};
+
+    ASSERT_FALSE(view1);
+    ASSERT_FALSE(view2);
+    ASSERT_FALSE(view3);
+    ASSERT_FALSE(view4);
+
+    entt::storage<int> istorage{};
+    entt::storage<char> cstorage{};
+    entt::storage<double> dstorage{};
+    entt::storage<float> fstorage{};
+
+    view1.storage(istorage);
+    view1.storage(cstorage);
+    view1.storage(dstorage);
+    view1.storage(fstorage);
+
+    view2 = view1;
+    view3 = view1;
+    view4 = view1;
+
+    ASSERT_TRUE(view1);
+    ASSERT_TRUE(view2);
+    ASSERT_TRUE(view3);
+    ASSERT_TRUE(view4);
+
+    ASSERT_EQ(0u, view1.size_hint());
+    ASSERT_EQ(0u, view2.size_hint());
+    ASSERT_EQ(0u, view3.size_hint());
+    ASSERT_EQ(0u, view4.size());
+
+    const entt::entity entity{1};
+
+    istorage.emplace(entity);
+    cstorage.emplace(entity);
+    dstorage.emplace(entity);
+    fstorage.emplace(entity);
+
+    ASSERT_EQ(1u, view1.size_hint());
+    ASSERT_EQ(1u, view2.size_hint());
+    ASSERT_EQ(1u, view3.size_hint());
+    ASSERT_EQ(1u, view4.size());
+}
+
 TEST(MultiStorageView, InvalidView) {
     entt::basic_view<entt::get_t<entt::storage<int>>, entt::exclude_t<entt::storage<char>>> view{};
     auto iterable = view.each();