diff --git a/TODO b/TODO index aebedc61c..321b14557 100644 --- a/TODO +++ b/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 -> view) diff --git a/src/entt/entity/view.hpp b/src/entt/entity/view.hpp index 94a9f2ba6..316d13a44 100644 --- a/src/entt/entity/view.hpp +++ b/src/entt/entity/view.hpp @@ -457,6 +457,13 @@ class basic_view, exclude_t, std::enable_if_t<(sizeof. } } + template + void storage_if(Type *elem) noexcept { + if(elem != nullptr) { + storage>(*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 value, std::tuple excl = {}) noexcept : basic_view{std::make_from_tuple(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>>> + basic_view(const basic_view &other) noexcept + : basic_view{} { + (storage_if(other.storage()), ...); + (storage_if(other.storage()), ...); + } + /** * @brief Forces a view to use a given element to drive iterations * @tparam Type Type of element to use to drive iterations. diff --git a/test/entt/entity/view.cpp b/test/entt/entity/view.cpp index dc0e1cdcf..482114f75 100644 --- a/test/entt/entity/view.cpp +++ b/test/entt/entity/view.cpp @@ -682,6 +682,54 @@ TEST(MultiStorageView, Functionalities) { ASSERT_FALSE(invalid); } +TEST(MultiStorageView, Conversion) { + entt::basic_view, const entt::storage>, entt::exclude_t, const entt::storage>> view1{}; + entt::basic_view, const entt::storage>, entt::exclude_t, const entt::storage>> view2{view1}; + entt::basic_view>, entt::exclude_t>> view3{view1}; + entt::basic_view>, entt::exclude_t<>> view4{view1}; + + ASSERT_FALSE(view1); + ASSERT_FALSE(view2); + ASSERT_FALSE(view3); + ASSERT_FALSE(view4); + + entt::storage istorage{}; + entt::storage cstorage{}; + entt::storage dstorage{}; + entt::storage 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::exclude_t>> view{}; auto iterable = view.each();