improved views (extended API + better performance)

This commit is contained in:
Michele Caini
2018-03-11 23:07:10 +01:00
parent f2eb0c8427
commit 1dd9da4dff
2 changed files with 118 additions and 20 deletions

View File

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

View File

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