improved views (extended API + better performance)
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#define ENTT_ENTITY_VIEW_HPP
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
@@ -78,7 +79,7 @@ class PersistentView final {
|
||||
{}
|
||||
|
||||
public:
|
||||
/*! Input iterator type. */
|
||||
/*! @brief Input iterator type. */
|
||||
using iterator_type = typename view_type::iterator_type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename view_type::entity_type;
|
||||
@@ -146,6 +147,15 @@ public:
|
||||
return view.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a view contains an entity.
|
||||
* @param entity A valid entity identifier.
|
||||
* @return True if the view contains the given entity, false otherwise.
|
||||
*/
|
||||
bool contains(entity_type entity) const noexcept {
|
||||
return view.has(entity) && (view.data()[view.get(entity)] == entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the component assigned to the given entity.
|
||||
*
|
||||
@@ -165,6 +175,7 @@ public:
|
||||
*/
|
||||
template<typename Comp>
|
||||
const Comp & get(entity_type entity) const noexcept {
|
||||
assert(contains(entity));
|
||||
return std::get<pool_type<Comp> &>(pools).get(entity);
|
||||
}
|
||||
|
||||
@@ -210,6 +221,7 @@ public:
|
||||
template<typename... Comp>
|
||||
std::enable_if_t<(sizeof...(Comp) > 1), std::tuple<const Comp &...>>
|
||||
get(entity_type entity) const noexcept {
|
||||
assert(contains(entity));
|
||||
return std::tuple<const Comp &...>{get<Comp>(entity)...};
|
||||
}
|
||||
|
||||
@@ -233,6 +245,7 @@ public:
|
||||
template<typename... Comp>
|
||||
std::enable_if_t<(sizeof...(Comp) > 1), std::tuple<Comp &...>>
|
||||
get(entity_type entity) noexcept {
|
||||
assert(contains(entity));
|
||||
return std::tuple<Comp &...>{get<Comp>(entity)...};
|
||||
}
|
||||
|
||||
@@ -253,7 +266,7 @@ public:
|
||||
*/
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
for(auto entity: *this) {
|
||||
for(auto entity: view) {
|
||||
func(entity, get<Component>(entity)...);
|
||||
}
|
||||
}
|
||||
@@ -367,13 +380,13 @@ class View final {
|
||||
inline bool valid() const noexcept {
|
||||
const auto entity = *begin;
|
||||
const auto sz = size_type(entity & traits_type::entity_mask);
|
||||
auto i = unchecked.size();
|
||||
auto pos = unchecked.size();
|
||||
|
||||
if(sz < extent) {
|
||||
for(; i && unchecked[i-1]->fast(entity); --i);
|
||||
for(; pos && unchecked[pos-1]->fast(entity); --pos);
|
||||
}
|
||||
|
||||
return !i;
|
||||
return !pos;
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -435,7 +448,7 @@ class View final {
|
||||
}
|
||||
|
||||
public:
|
||||
/*! Input iterator type. */
|
||||
/*! @brief Input iterator type. */
|
||||
using iterator_type = Iterator;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename view_type::entity_type;
|
||||
@@ -489,6 +502,23 @@ public:
|
||||
return Iterator{unchecked, extent, view->end(), view->end()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a view contains an entity.
|
||||
* @param entity A valid entity identifier.
|
||||
* @return True if the view contains the given entity, false otherwise.
|
||||
*/
|
||||
bool contains(entity_type entity) const noexcept {
|
||||
const auto extent = std::min({ std::get<pool_type<Component> &>(pools).extent()... });
|
||||
const auto sz = size_type(entity & traits_type::entity_mask);
|
||||
auto pos = unchecked.size();
|
||||
|
||||
if(sz < extent && view->has(entity) && (view->data()[view->get(entity)] == entity)) {
|
||||
for(; pos && unchecked[pos-1]->fast(entity); --pos);
|
||||
}
|
||||
|
||||
return !pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the component assigned to the given entity.
|
||||
*
|
||||
@@ -508,6 +538,7 @@ public:
|
||||
*/
|
||||
template<typename Comp>
|
||||
const Comp & get(entity_type entity) const noexcept {
|
||||
assert(contains(entity));
|
||||
return std::get<pool_type<Comp> &>(pools).get(entity);
|
||||
}
|
||||
|
||||
@@ -553,6 +584,7 @@ public:
|
||||
template<typename... Comp>
|
||||
std::enable_if_t<(sizeof...(Comp) > 1), std::tuple<const Comp &...>>
|
||||
get(entity_type entity) const noexcept {
|
||||
assert(contains(entity));
|
||||
return std::tuple<const Comp &...>{get<Comp>(entity)...};
|
||||
}
|
||||
|
||||
@@ -576,6 +608,7 @@ public:
|
||||
template<typename... Comp>
|
||||
std::enable_if_t<(sizeof...(Comp) > 1), std::tuple<Comp &...>>
|
||||
get(entity_type entity) noexcept {
|
||||
assert(contains(entity));
|
||||
return std::tuple<Comp &...>{get<Comp>(entity)...};
|
||||
}
|
||||
|
||||
@@ -596,8 +629,20 @@ public:
|
||||
*/
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
for(auto entity: *this) {
|
||||
func(entity, get<Component>(entity)...);
|
||||
const auto extent = std::min({ std::get<pool_type<Component> &>(pools).extent()... });
|
||||
|
||||
for(auto entity: *view) {
|
||||
const auto sz = size_type(entity & traits_type::entity_mask);
|
||||
|
||||
if(sz < extent) {
|
||||
auto pos = unchecked.size();
|
||||
|
||||
for(; pos && unchecked[pos-1]->fast(entity); --pos);
|
||||
|
||||
if(!pos) {
|
||||
func(entity, get<Component>(entity)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,6 +746,7 @@ class View<Entity, Component> final {
|
||||
/*! @brief A registry is allowed to create views. */
|
||||
friend class Registry<Entity>;
|
||||
|
||||
using view_type = SparseSet<Entity>;
|
||||
using pool_type = SparseSet<Entity, Component>;
|
||||
|
||||
View(pool_type &pool) noexcept
|
||||
@@ -708,13 +754,13 @@ class View<Entity, Component> final {
|
||||
{}
|
||||
|
||||
public:
|
||||
/*! Input iterator type. */
|
||||
/*! @brief Input iterator type. */
|
||||
using iterator_type = typename pool_type::iterator_type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename pool_type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename pool_type::size_type;
|
||||
/*! Type of the component iterated by the view. */
|
||||
/*! @brief Type of the component iterated by the view. */
|
||||
using raw_type = typename pool_type::object_type;
|
||||
|
||||
/**
|
||||
@@ -810,6 +856,15 @@ public:
|
||||
return pool.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a view contains an entity.
|
||||
* @param entity A valid entity identifier.
|
||||
* @return True if the view contains the given entity, false otherwise.
|
||||
*/
|
||||
bool contains(entity_type entity) const noexcept {
|
||||
return pool.has(entity) && (pool.data()[pool.view_type::get(entity)] == entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the component assigned to the given entity.
|
||||
*
|
||||
@@ -826,6 +881,7 @@ public:
|
||||
* @return The component assigned to the entity.
|
||||
*/
|
||||
const Component & get(entity_type entity) const noexcept {
|
||||
assert(contains(entity));
|
||||
return pool.get(entity);
|
||||
}
|
||||
|
||||
@@ -864,7 +920,7 @@ public:
|
||||
*/
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
for(auto entity: *this) {
|
||||
for(auto entity: pool) {
|
||||
func(entity, get(entity));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,20 @@ TEST(View, SingleComponent) {
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
}
|
||||
|
||||
TEST(View, SingleComponentContains) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
auto e0 = registry.create<int>();
|
||||
auto e1 = registry.create<int>();
|
||||
|
||||
registry.destroy(e0);
|
||||
|
||||
auto view = registry.view<int>();
|
||||
|
||||
ASSERT_FALSE(view.contains(e0));
|
||||
ASSERT_TRUE(view.contains(e1));
|
||||
}
|
||||
|
||||
TEST(View, SingleComponentEmpty) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
@@ -96,9 +110,9 @@ TEST(View, MultipleComponent) {
|
||||
ASSERT_EQ(view.begin()+1, view.end());
|
||||
ASSERT_EQ(view.size(), decltype(view.size()){1});
|
||||
|
||||
view.get<char>(e0) = '1';
|
||||
view.get<char>(e1) = '2';
|
||||
view.get<int>(e1) = 42;
|
||||
registry.get<char>(e0) = '1';
|
||||
registry.get<char>(e1) = '2';
|
||||
registry.get<int>(e1) = 42;
|
||||
|
||||
for(auto entity: view) {
|
||||
const auto &cview = static_cast<const decltype(view) &>(view);
|
||||
@@ -114,6 +128,20 @@ TEST(View, MultipleComponent) {
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
}
|
||||
|
||||
TEST(View, MultipleComponentContains) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
auto e0 = registry.create<int, char>();
|
||||
auto e1 = registry.create<int, char>();
|
||||
|
||||
registry.destroy(e0);
|
||||
|
||||
auto view = registry.view<int, char>();
|
||||
|
||||
ASSERT_FALSE(view.contains(e0));
|
||||
ASSERT_TRUE(view.contains(e1));
|
||||
}
|
||||
|
||||
TEST(View, MultipleComponentEmpty) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
@@ -170,9 +198,9 @@ TEST(PersistentView, Prepare) {
|
||||
|
||||
ASSERT_EQ(view.size(), typename decltype(view)::size_type{1});
|
||||
|
||||
view.get<char>(e0) = '1';
|
||||
view.get<char>(e1) = '2';
|
||||
view.get<int>(e1) = 42;
|
||||
registry.get<char>(e0) = '1';
|
||||
registry.get<char>(e1) = '2';
|
||||
registry.get<int>(e1) = 42;
|
||||
|
||||
for(auto entity: view) {
|
||||
const auto &cview = static_cast<const decltype(view) &>(view);
|
||||
@@ -211,9 +239,9 @@ TEST(PersistentView, NoPrepare) {
|
||||
|
||||
ASSERT_EQ(view.size(), typename decltype(view)::size_type{1});
|
||||
|
||||
view.get<char>(e0) = '1';
|
||||
view.get<char>(e1) = '2';
|
||||
view.get<int>(e1) = 42;
|
||||
registry.get<char>(e0) = '1';
|
||||
registry.get<char>(e1) = '2';
|
||||
registry.get<int>(e1) = 42;
|
||||
|
||||
for(auto entity: view) {
|
||||
const auto &cview = static_cast<const decltype(view) &>(view);
|
||||
@@ -230,6 +258,20 @@ TEST(PersistentView, NoPrepare) {
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
}
|
||||
|
||||
TEST(PersistentView, Contains) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
auto e0 = registry.create<int, char>();
|
||||
auto e1 = registry.create<int, char>();
|
||||
|
||||
registry.destroy(e0);
|
||||
|
||||
auto view = registry.persistent<int, char>();
|
||||
|
||||
ASSERT_FALSE(view.contains(e0));
|
||||
ASSERT_TRUE(view.contains(e1));
|
||||
}
|
||||
|
||||
TEST(PersistentView, Empty) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user