storage/view/group: reintroduce (opaque) ::raw functions as it ought to be

This commit is contained in:
Michele Caini
2021-05-17 11:59:51 +02:00
parent 8e5a048913
commit b062bbf58d
8 changed files with 187 additions and 84 deletions

View File

@@ -10,6 +10,7 @@
* [Type-less and bitset-free](#type-less-and-bitset-free)
* [Build your own](#build-your-own)
* [Pay per use](#pay-per-use)
* [All or nothing](#all-or-nothing)
* [Vademecum](#vademecum)
* [Pools](#pools)
* [The Registry, the Entity and the Component](#the-registry-the-entity-and-the-component)
@@ -118,6 +119,19 @@ performance where needed.
So far, this choice has proven to be a good one and I really hope it can be for
many others besides me.
## All or nothing
`EnTT` is such that a `T**` pointer (or whatever a custom pool returns) is
always available to directly access all the instances of a given component type
`T`.<br/>
I cannot say whether it will be useful or not to the reader, but it's worth to
mention it since it's one of the corner stones of this library.
Many of the tools described below give the possibility to get this information
and have been designed around this need.<br/>
The rest is experimentation and the desire to invent something new, hoping to
have succeeded.
# Vademecum
The registry to store, the views and the groups to iterate. That's all.
@@ -1237,11 +1251,12 @@ different in the two cases.
Single component views are specialized in order to give a boost in terms of
performance in all the situations. This kind of views can access the underlying
data structures directly and avoid superfluous checks. There is nothing as fast
as a single component view. In fact, they walk through a packed array of
components and return them one at a time.<br/>
Single component views offer a bunch of functionalities to get the number of
entities they are going to return and a raw access to the entity list. It's also
possible to ask a view if it contains a given entity.<br/>
as a single component view. In fact, they walk through a packed (actually paged)
array of components and return them one at a time.<br/>
Single component views also offer a bunch of functionalities to get the number
of entities they are going to return and a raw access to the entity list as well
as to the component list. It's also possible to ask a view if it contains a
given entity.<br/>
Refer to the inline documentation for all the details.
Multi component views iterate entities that have at least all the given
@@ -1435,8 +1450,9 @@ However, it's unlikely that users will be able to appreciate the impact of
groups on the other functionalities of a registry.
Groups offer a bunch of functionalities to get the number of entities they are
going to return and a raw access to the entity list. It's also possible to ask a
group if it contains a given entity.<br/>
going to return and a raw access to the entity list as well as to the component
list for owned components. It's also possible to ask a group if it contains a
given entity.<br/>
Refer to the inline documentation for all the details.
There is no need to store groups aside for they are extremely cheap to
@@ -1846,9 +1862,9 @@ When an empty type is detected, it's not instantiated in any case. Therefore,
only the entities to which it's assigned are made available.<br/>
There doesn't exist a way to _get_ empty types from a registry, views and groups
will never return instances for them (for example, during a call to `each`) and
some functions such as `try_get` aren't available for empty types. Finally, the
`sort` functionality will only accepts callbacks that require to return entities
rather than components:
some functions such as `try_get` or the raw access to the list of components
aren't available for empty types. Finally, the `sort` functionality will only
accepts callbacks that require to return entities rather than components:
```cpp
registry.sort<empty_type>([](const entt::entity lhs, const entt::entity rhs) {

View File

@@ -680,6 +680,22 @@ public:
return !*this || !*length;
}
/**
* @brief Direct access to the raw representation offered by the storage.
*
* @warning
* This function is only available for owned types.
*
* @tparam Component Type of component in which one is interested.
* @return A pointer to the array of components.
*/
template<typename Component>
[[nodiscard]] auto raw() const ENTT_NOEXCEPT {
static_assert((std::is_same_v<Component, Owned> || ...), "Non-owned type");
auto *cpool = std::get<storage_type<Component> *>(pools);
return cpool ? cpool->raw() : decltype(cpool->raw()){};
}
/**
* @brief Direct access to the list of entities.
*

View File

@@ -59,11 +59,12 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
using alloc_type = typename std::allocator_traits<Allocator>::template rebind_alloc<Type>;
using alloc_traits = std::allocator_traits<alloc_type>;
using alloc_pointer = typename alloc_traits::pointer;
using alloc_const_pointer = typename alloc_traits::const_pointer;
using bucket_alloc_type = typename std::allocator_traits<Allocator>::template rebind_alloc<alloc_pointer>;
using bucket_alloc_traits = std::allocator_traits<bucket_alloc_type>;
using bucket_alloc_pointer = typename bucket_alloc_traits::pointer;
using bucket_alloc_const_pointer = typename bucket_alloc_traits::const_pointer;
using bucket_alloc_const_pointer = typename std::allocator_traits<Allocator>::template rebind_alloc<alloc_const_pointer>::const_pointer;
using entity_alloc_type = typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>;
@@ -74,7 +75,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
class storage_iterator final {
friend class basic_storage<Entity, Type>;
storage_iterator(const bucket_alloc_const_pointer *ref, const typename traits_type::difference_type idx) ENTT_NOEXCEPT
storage_iterator(bucket_alloc_pointer const *ref, const typename traits_type::difference_type idx) ENTT_NOEXCEPT
: packed{ref}, index{idx}
{}
@@ -166,7 +167,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
}
private:
const bucket_alloc_const_pointer *packed;
bucket_alloc_pointer const *packed;
difference_type index;
};
@@ -270,6 +271,10 @@ public:
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Pointer type to contained elements. */
using pointer = bucket_alloc_pointer;
/*! @brief Constant pointer type to contained elements. */
using const_pointer = bucket_alloc_const_pointer;
/*! @brief Random access iterator type. */
using iterator = storage_iterator<Type>;
/*! @brief Constant random access iterator type. */
@@ -354,6 +359,19 @@ public:
count ? maybe_resize_packed(count) : reset_to_empty();
}
/**
* @brief Direct access to the array of objects.
* @return A pointer to the array of objects.
*/
[[nodiscard]] const_pointer raw() const ENTT_NOEXCEPT {
return packed;
}
/*! @copydoc raw */
[[nodiscard]] pointer raw() ENTT_NOEXCEPT {
return packed;
}
/**
* @brief Returns an iterator to the beginning.
*

View File

@@ -708,6 +708,14 @@ public:
return std::get<0>(pools)->empty();
}
/**
* @brief Direct access to the raw representation offered by the storage.
* @return A pointer to the array of components.
*/
[[nodiscard]] auto raw() const ENTT_NOEXCEPT {
return std::get<0>(pools)->raw();
}
/**
* @brief Direct access to the list of entities.
*

View File

@@ -53,7 +53,7 @@ TEST(NonOwningGroup, Functionalities) {
ASSERT_EQ(cgroup.get<const char>(entity), '2');
}
ASSERT_EQ(*(group.data() + 0), e1);
ASSERT_EQ(group.data()[0u], e1);
registry.erase<char>(e0);
registry.erase<char>(e1);
@@ -221,17 +221,17 @@ TEST(NonOwningGroup, Sort) {
registry.emplace<int>(e1, 1);
registry.emplace<int>(e2, 2);
ASSERT_EQ(*(group.data() + 0u), e0);
ASSERT_EQ(*(group.data() + 1u), e1);
ASSERT_EQ(*(group.data() + 2u), e2);
ASSERT_EQ(group.data()[0u], e0);
ASSERT_EQ(group.data()[1u], e1);
ASSERT_EQ(group.data()[2u], e2);
group.sort([](const entt::entity lhs, const entt::entity rhs) {
return entt::to_integral(lhs) < entt::to_integral(rhs);
});
ASSERT_EQ(*(group.data() + 0u), e2);
ASSERT_EQ(*(group.data() + 1u), e1);
ASSERT_EQ(*(group.data() + 2u), e0);
ASSERT_EQ(group.data()[0u], e2);
ASSERT_EQ(group.data()[1u], e1);
ASSERT_EQ(group.data()[2u], e0);
ASSERT_EQ((group.get<const int, unsigned int>(e0)), (std::make_tuple(0, 0u)));
ASSERT_EQ((group.get<const int, unsigned int>(e1)), (std::make_tuple(1, 1u)));
@@ -243,9 +243,9 @@ TEST(NonOwningGroup, Sort) {
return lhs > rhs;
});
ASSERT_EQ(*(group.data() + 0u), e0);
ASSERT_EQ(*(group.data() + 1u), e1);
ASSERT_EQ(*(group.data() + 2u), e2);
ASSERT_EQ(group.data()[0u], e0);
ASSERT_EQ(group.data()[1u], e1);
ASSERT_EQ(group.data()[2u], e2);
ASSERT_EQ((group.get<const int, unsigned int>(e0)), (std::make_tuple(0, 0u)));
ASSERT_EQ((group.get<const int, unsigned int>(e1)), (std::make_tuple(1, 1u)));
@@ -259,9 +259,9 @@ TEST(NonOwningGroup, Sort) {
return std::get<0>(lhs) < std::get<0>(rhs);
});
ASSERT_EQ(*(group.data() + 0u), e2);
ASSERT_EQ(*(group.data() + 1u), e1);
ASSERT_EQ(*(group.data() + 2u), e0);
ASSERT_EQ(group.data()[0u], e2);
ASSERT_EQ(group.data()[1u], e1);
ASSERT_EQ(group.data()[2u], e0);
ASSERT_EQ((group.get<const int, unsigned int>(e0)), (std::make_tuple(0, 0u)));
ASSERT_EQ((group.get<const int, unsigned int>(e1)), (std::make_tuple(1, 1u)));
@@ -665,8 +665,8 @@ TEST(OwningGroup, Functionalities) {
ASSERT_EQ(group.size(), 1u);
ASSERT_EQ(*(cgroup.rbegin() + 0), e1);
ASSERT_EQ(*(group.rbegin() + 0), e1);
ASSERT_EQ(cgroup.raw<const int>()[0u][0u], 42);
ASSERT_EQ(group.raw<int>()[0u][0u], 42);
for(auto entity: group) {
ASSERT_EQ(std::get<0>(cgroup.get<const int, const char>(entity)), 42);
@@ -674,7 +674,8 @@ TEST(OwningGroup, Functionalities) {
ASSERT_EQ(cgroup.get<const char>(entity), '2');
}
ASSERT_EQ(*(group.data() + 0), e1);
ASSERT_EQ(group.data()[0u], e1);
ASSERT_EQ(group.raw<int>()[0u][0u], 42);
registry.erase<char>(e0);
registry.erase<char>(e1);
@@ -705,6 +706,7 @@ TEST(OwningGroup, Invalid) {
ASSERT_TRUE(group.empty());
ASSERT_EQ(group.size(), 0u);
ASSERT_EQ(group.raw<const int>(), nullptr);
ASSERT_EQ(group.data(), nullptr);
ASSERT_EQ(group.begin(), group.end());
@@ -839,17 +841,21 @@ TEST(OwningGroup, SortOrdered) {
return group.get<boxed_int>(lhs).value < group.get<boxed_int>(rhs).value;
});
ASSERT_EQ(*(group.data() + 0u), entities[0]);
ASSERT_EQ(*(group.data() + 1u), entities[1]);
ASSERT_EQ(*(group.data() + 2u), entities[2]);
ASSERT_EQ(group.data()[0u], entities[0]);
ASSERT_EQ(group.data()[1u], entities[1]);
ASSERT_EQ(group.data()[2u], entities[2]);
ASSERT_EQ(group.data()[3u], entities[3]);
ASSERT_EQ(group.data()[4u], entities[4]);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 0u)).value, 12);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 1u)).value, 9);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 2u)).value, 6);
ASSERT_EQ(group.raw<boxed_int>()[0u][0u].value, 12);
ASSERT_EQ(group.raw<boxed_int>()[0u][1u].value, 9);
ASSERT_EQ(group.raw<boxed_int>()[0u][2u].value, 6);
ASSERT_EQ(group.raw<boxed_int>()[0u][3u].value, 1);
ASSERT_EQ(group.raw<boxed_int>()[0u][4u].value, 2);
ASSERT_EQ(group.get<char>(*(group.data() + 0u)), 'a');
ASSERT_EQ(group.get<char>(*(group.data() + 1u)), 'b');
ASSERT_EQ(group.get<char>(*(group.data() + 2u)), 'c');
ASSERT_EQ(group.raw<char>()[0u][0u], 'a');
ASSERT_EQ(group.raw<char>()[0u][1u], 'b');
ASSERT_EQ(group.raw<char>()[0u][2u], 'c');
ASSERT_EQ((group.get<boxed_int, char>(entities[0])), (std::make_tuple(boxed_int{12}, 'a')));
ASSERT_EQ((group.get<boxed_int, char>(entities[1])), (std::make_tuple(boxed_int{9}, 'b')));
@@ -882,17 +888,21 @@ TEST(OwningGroup, SortReverse) {
return lhs.value < rhs.value;
});
ASSERT_EQ(*(group.data() + 0u), entities[2]);
ASSERT_EQ(*(group.data() + 1u), entities[1]);
ASSERT_EQ(*(group.data() + 2u), entities[0]);
ASSERT_EQ(group.data()[0u], entities[2]);
ASSERT_EQ(group.data()[1u], entities[1]);
ASSERT_EQ(group.data()[2u], entities[0]);
ASSERT_EQ(group.data()[3u], entities[3]);
ASSERT_EQ(group.data()[4u], entities[4]);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 0u)).value, 12);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 1u)).value, 9);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 2u)).value, 6);
ASSERT_EQ(group.raw<boxed_int>()[0u][0u].value, 12);
ASSERT_EQ(group.raw<boxed_int>()[0u][1u].value, 9);
ASSERT_EQ(group.raw<boxed_int>()[0u][2u].value, 6);
ASSERT_EQ(group.raw<boxed_int>()[0u][3u].value, 1);
ASSERT_EQ(group.raw<boxed_int>()[0u][4u].value, 2);
ASSERT_EQ(group.get<char>(*(group.data() + 0u)), 'c');
ASSERT_EQ(group.get<char>(*(group.data() + 1u)), 'b');
ASSERT_EQ(group.get<char>(*(group.data() + 2u)), 'a');
ASSERT_EQ(group.raw<char>()[0u][0u], 'c');
ASSERT_EQ(group.raw<char>()[0u][1u], 'b');
ASSERT_EQ(group.raw<char>()[0u][2u], 'a');
ASSERT_EQ((group.get<boxed_int, char>(entities[0])), (std::make_tuple(boxed_int{6}, 'a')));
ASSERT_EQ((group.get<boxed_int, char>(entities[1])), (std::make_tuple(boxed_int{9}, 'b')));
@@ -933,29 +943,27 @@ TEST(OwningGroup, SortUnordered) {
return std::get<1>(lhs) < std::get<1>(rhs);
});
ASSERT_EQ(*(group.data() + 0u), entities[4]);
ASSERT_EQ(*(group.data() + 1u), entities[3]);
ASSERT_EQ(*(group.data() + 2u), entities[0]);
ASSERT_EQ(*(group.data() + 3u), entities[1]);
ASSERT_EQ(*(group.data() + 4u), entities[2]);
ASSERT_EQ(group.data()[0u], entities[4]);
ASSERT_EQ(group.data()[1u], entities[3]);
ASSERT_EQ(group.data()[2u], entities[0]);
ASSERT_EQ(group.data()[3u], entities[1]);
ASSERT_EQ(group.data()[4u], entities[2]);
ASSERT_EQ(group.data()[5u], entities[5]);
ASSERT_EQ(group.data()[6u], entities[6]);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 0u)).value, 12);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 1u)).value, 9);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 2u)).value, 6);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 3u)).value, 3);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 4u)).value, 1);
ASSERT_EQ(group.raw<boxed_int>()[0u][0u].value, 12);
ASSERT_EQ(group.raw<boxed_int>()[0u][1u].value, 9);
ASSERT_EQ(group.raw<boxed_int>()[0u][2u].value, 6);
ASSERT_EQ(group.raw<boxed_int>()[0u][3u].value, 3);
ASSERT_EQ(group.raw<boxed_int>()[0u][4u].value, 1);
ASSERT_EQ(group.raw<boxed_int>()[0u][5u].value, 4);
ASSERT_EQ(group.raw<boxed_int>()[0u][6u].value, 5);
ASSERT_EQ(group.get<char>(*(group.data() + 0u)), 'e');
ASSERT_EQ(group.get<char>(*(group.data() + 1u)), 'd');
ASSERT_EQ(group.get<char>(*(group.data() + 2u)), 'c');
ASSERT_EQ(group.get<char>(*(group.data() + 3u)), 'b');
ASSERT_EQ(group.get<char>(*(group.data() + 4u)), 'a');
ASSERT_EQ((group.get<boxed_int, char>(entities[0])), (std::make_tuple(boxed_int{6}, 'c')));
ASSERT_EQ((group.get<boxed_int, char>(entities[1])), (std::make_tuple(boxed_int{3}, 'b')));
ASSERT_EQ((group.get<boxed_int, char>(entities[2])), (std::make_tuple(boxed_int{1}, 'a')));
ASSERT_EQ((group.get<boxed_int, char>(entities[3])), (std::make_tuple(boxed_int{9}, 'd')));
ASSERT_EQ((group.get<boxed_int, char>(entities[4])), (std::make_tuple(boxed_int{12}, 'e')));
ASSERT_EQ(group.get<char>(group.data()[0u]), 'e');
ASSERT_EQ(group.get<char>(group.data()[1u]), 'd');
ASSERT_EQ(group.get<char>(group.data()[2u]), 'c');
ASSERT_EQ(group.get<char>(group.data()[3u]), 'b');
ASSERT_EQ(group.get<char>(group.data()[4u]), 'a');
ASSERT_FALSE(group.contains(entities[5]));
ASSERT_FALSE(group.contains(entities[6]));
@@ -980,15 +988,20 @@ TEST(OwningGroup, SortWithExclusionList) {
return lhs < rhs;
});
ASSERT_EQ(*(group.data() + 0u), entities[4]);
ASSERT_EQ(*(group.data() + 1u), entities[3]);
ASSERT_EQ(*(group.data() + 2u), entities[1]);
ASSERT_EQ(*(group.data() + 3u), entities[0]);
ASSERT_EQ(group.data()[0u], entities[4]);
ASSERT_EQ(group.data()[1u], entities[3]);
ASSERT_EQ(group.data()[2u], entities[1]);
ASSERT_EQ(group.data()[3u], entities[0]);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 0u)).value, 4);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 1u)).value, 3);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 2u)).value, 1);
ASSERT_EQ(group.get<boxed_int>(*(group.data() + 3u)).value, 0);
ASSERT_EQ(group.raw<boxed_int>()[0u][0u].value, 4);
ASSERT_EQ(group.raw<boxed_int>()[0u][1u].value, 3);
ASSERT_EQ(group.raw<boxed_int>()[0u][2u].value, 1);
ASSERT_EQ(group.raw<boxed_int>()[0u][3u].value, 0);
ASSERT_EQ(group.get<boxed_int>(entities[0]).value, 0);
ASSERT_EQ(group.get<boxed_int>(entities[1]).value, 1);
ASSERT_EQ(group.get<boxed_int>(entities[3]).value, 3);
ASSERT_EQ(group.get<boxed_int>(entities[4]).value, 4);
ASSERT_FALSE(group.contains(entities[2]));
}
@@ -1049,6 +1062,8 @@ TEST(OwningGroup, ConstNonConstAndAllInBetween) {
static_assert(std::is_same_v<decltype(group.get<int, const char, double, const float>({})), std::tuple<int &, const char &, double &, const float &>>);
static_assert(std::is_same_v<decltype(group.get({})), std::tuple<int &, const char &, double &, const float &>>);
static_assert(std::is_same_v<decltype(group.data()), const entt::entity *>);
static_assert(std::is_same_v<decltype(group.raw<const char>()), const char * const *>);
static_assert(std::is_same_v<decltype(group.raw<int>()), int **>);
group.each([](auto &&i, auto &&c, auto &&d, auto &&f) {
static_assert(std::is_same_v<decltype(i), int &>);

View File

@@ -14,6 +14,7 @@ TEST(Registry, NoEto) {
registry.emplace<empty_type>(entity);
registry.emplace<int>(entity, 42);
ASSERT_NE(registry.view<empty_type>().raw(), nullptr);
ASSERT_NE(registry.try_get<empty_type>(entity), nullptr);
ASSERT_EQ(registry.view<empty_type>().get(entity), std::as_const(registry).view<const empty_type>().get(entity));

View File

@@ -418,6 +418,22 @@ TEST(Storage, ConstReverseIterator) {
ASSERT_GE(cend, pool.crend());
}
TEST(Storage, Raw) {
entt::storage<int> pool;
pool.emplace(entt::entity{3}, 3);
pool.emplace(entt::entity{12}, 6);
pool.emplace(entt::entity{42}, 9);
ASSERT_EQ(pool.get(entt::entity{3}), 3);
ASSERT_EQ(std::as_const(pool).get(entt::entity{12}), 6);
ASSERT_EQ(pool.get(entt::entity{42}), 9);
ASSERT_EQ(pool.raw()[0u][0u], 3);
ASSERT_EQ(std::as_const(pool).raw()[0u][1u], 6);
ASSERT_EQ(pool.raw()[0u][2u], 9);
}
TEST(Storage, SortOrdered) {
entt::storage<boxed_int> pool;
entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
@@ -480,9 +496,9 @@ TEST(Storage, SortRange) {
pool.sort_n(2u, [](auto lhs, auto rhs) { return lhs.value < rhs.value; });
ASSERT_EQ(pool.rbegin()[0u], boxed_int{6});
ASSERT_EQ(pool.rbegin()[1u], boxed_int{3});
ASSERT_EQ(pool.rbegin()[2u], boxed_int{1});
ASSERT_EQ(pool.raw()[0u][0u], boxed_int{6});
ASSERT_EQ(pool.raw()[0u][1u], boxed_int{3});
ASSERT_EQ(pool.raw()[0u][2u], boxed_int{1});
ASSERT_EQ(pool.data()[0u], entt::entity{42});
ASSERT_EQ(pool.data()[1u], entt::entity{12});

View File

@@ -44,8 +44,11 @@ TEST(SingleComponentView, Functionalities) {
ASSERT_TRUE(cview.get<const char>(entity) == '1' || std::get<const char &>(cview.get(entity)) == '2');
}
ASSERT_EQ(*(view.data() + 0), e1);
ASSERT_EQ(*(view.data() + 1), e0);
ASSERT_EQ(view.data()[0u], e1);
ASSERT_EQ(view.data()[1u], e0);
ASSERT_EQ(view.raw()[0u][0u], '2');
ASSERT_EQ(cview.raw()[0u][1u], '1');
registry.erase<char>(e0);
registry.erase<char>(e1);
@@ -61,7 +64,7 @@ TEST(SingleComponentView, Functionalities) {
ASSERT_FALSE(invalid);
}
TEST(SingleComponentView, Data) {
TEST(SingleComponentView, RawData) {
entt::registry registry;
auto view = registry.view<int>();
auto cview = std::as_const(registry).view<const int>();
@@ -70,6 +73,8 @@ TEST(SingleComponentView, Data) {
ASSERT_EQ(view.size(), 0u);
ASSERT_EQ(cview.size(), 0u);
ASSERT_EQ(view.raw(), nullptr);
ASSERT_EQ(cview.raw(), nullptr);
ASSERT_EQ(view.data(), nullptr);
ASSERT_EQ(cview.data(), nullptr);
@@ -77,8 +82,10 @@ TEST(SingleComponentView, Data) {
ASSERT_NE(view.size(), 0u);
ASSERT_NE(cview.size(), 0u);
ASSERT_EQ(*view.data(), entity);
ASSERT_EQ(*cview.data(), entity);
ASSERT_EQ(view.raw()[0u][0u], 42);
ASSERT_EQ(cview.raw()[0u][0u], 42);
ASSERT_EQ(view.data()[0u], entity);
ASSERT_EQ(cview.data()[0u], entity);
registry.destroy(entity);
@@ -98,6 +105,7 @@ TEST(SingleComponentView, LazyTypeFromConstRegistry) {
ASSERT_TRUE(cview);
ASSERT_TRUE(eview);
ASSERT_NE(cview.raw(), nullptr);
ASSERT_NE(eview.data(), nullptr);
ASSERT_FALSE(cview.empty());
@@ -218,10 +226,15 @@ TEST(SingleComponentView, ConstNonConstAndAllInBetween) {
ASSERT_EQ(view.size(), 1u);
ASSERT_EQ(cview.size(), 1u);
static_assert(std::is_same_v<decltype(view.raw()), int **>);
static_assert(std::is_same_v<decltype(cview.raw()), const int * const *>);
static_assert(std::is_same_v<decltype(view.get<int>({})), int &>);
static_assert(std::is_same_v<decltype(view.get({})), std::tuple<int &>>);
static_assert(std::is_same_v<decltype(view.raw()), int **>);
static_assert(std::is_same_v<decltype(cview.get<const int>({})), const int &>);
static_assert(std::is_same_v<decltype(cview.get({})), std::tuple<const int &>>);
static_assert(std::is_same_v<decltype(cview.raw()), const int * const *>);
view.each([](auto &&i) {
static_assert(std::is_same_v<decltype(i), int &>);