view: support converting views

This commit is contained in:
skypjack
2025-12-16 16:14:59 +01:00
parent 8d64106372
commit e504310399
3 changed files with 67 additions and 1 deletions

1
TODO
View File

@@ -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>)

View File

@@ -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.

View File

@@ -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();