diff --git a/README.md b/README.md
index e5d076856..b355fbefa 100644
--- a/README.md
+++ b/README.md
@@ -1276,9 +1276,9 @@ entities available for each component and pick up a reference to the smallest
set of candidates in order to speed up iterations.
They offer fewer functionalities than their companion views for single
component. In particular, a multi component standard view exposes utility
-functions to reset its internal state (optimization purposes) and to get the
-estimated number of entities it is going to return. It's also possible to ask a
-view if it contains a given entity.
+functions to get the estimated number of entities it is going to return and to
+know whether it's empty or not. It's also possible to ask a view if it contains
+a given entity.
Refer to the [official documentation](https://skypjack.github.io/entt/) for all
the details.
diff --git a/src/entt/entity/view.hpp b/src/entt/entity/view.hpp
index b58cf0bb5..9e724ec72 100644
--- a/src/entt/entity/view.hpp
+++ b/src/entt/entity/view.hpp
@@ -9,7 +9,6 @@
#include
#include
#include "../config/config.h"
-#include "../core/ident.hpp"
#include "entt_traits.hpp"
#include "sparse_set.hpp"
@@ -432,16 +431,13 @@ class View final {
class Iterator {
using size_type = typename view_type::size_type;
- inline bool valid() const ENTT_NOEXCEPT {
+ bool valid() const ENTT_NOEXCEPT {
const auto entity = *begin;
const auto sz = size_type(entity & traits_type::entity_mask);
- auto pos = unchecked.size();
- if(sz < extent) {
- for(; pos && unchecked[pos-1]->fast(entity); --pos);
- }
-
- return !pos;
+ return sz < extent && std::all_of(unchecked.cbegin(), unchecked.cend(), [entity](const view_type *view) {
+ return view->fast(entity);
+ });
}
public:
@@ -499,42 +495,46 @@ class View final {
};
View(pool_type &... pools) ENTT_NOEXCEPT
- : pools{pools...}, view{nullptr}, unchecked{}, idx{}
- {
- reset();
+ : pools{pools...}
+ {}
+
+ template
+ const pool_type & pool() const ENTT_NOEXCEPT {
+ return std::get &>(pools);
}
- template
- inline std::enable_if_t::value, const Other &>
- get(const It &it, Entity) const { return *it; }
+ template
+ inline pool_type & pool() ENTT_NOEXCEPT {
+ return const_cast &>(const_cast(this)->pool());
+ }
- template
- inline std::enable_if_t::value, const Other &>
- get(const It &, Entity entity) const { return std::get &>(pools).get(entity); }
-
- template
- void each(Func func) const {
- const auto extent = std::min({ std::get &>(pools).extent()... });
- auto &pool = std::get &>(pools);
-
- std::for_each(pool.view_type::cbegin(), pool.view_type::cend(), [func = std::move(func), raw = pool.cbegin(), extent, this](const auto entity) mutable {
- 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) {
- // avoided indirections due to the sparse set for the pivot (this-> required because of GCC 6)
- func(entity, this->get(raw, entity)...);
- }
- }
-
- ++raw;
+ const view_type * candidate() const ENTT_NOEXCEPT {
+ return std::min({ static_cast(&pool())... }, [](const auto *lhs, const auto *rhs) {
+ return lhs->size() < rhs->size();
});
}
+ unchecked_type unchecked(const view_type *view) const ENTT_NOEXCEPT {
+ unchecked_type other{};
+ std::size_t pos{};
+ using accumulator_type = const view_type *[];
+ accumulator_type accumulator = { (&pool() == view ? view : other[pos++] = &pool())... };
+ (void)accumulator;
+ return other;
+ }
+
+ typename view_type::size_type extent() const ENTT_NOEXCEPT {
+ return std::min({ pool().extent()... });
+ }
+
+ template
+ inline std::enable_if_t::value, const Other &>
+ get(const typename pool_type::const_iterator_type &it, Entity) const ENTT_NOEXCEPT { return *it; }
+
+ template
+ inline std::enable_if_t::value, const Other &>
+ get(const typename pool_type::const_iterator_type &, Entity entity) const ENTT_NOEXCEPT { return pool().get(entity); }
+
public:
/*! @brief Input iterator type. */
using iterator_type = Iterator;
@@ -550,7 +550,7 @@ public:
* @return Estimated number of entities that have the given components.
*/
size_type size() const ENTT_NOEXCEPT {
- return view->size();
+ return std::min({ pool().size()... });
}
/**
@@ -558,7 +558,7 @@ public:
* @return True if the view is definitely empty, false otherwise.
*/
bool empty() const ENTT_NOEXCEPT {
- return view->empty();
+ return std::max({ pool().empty()... });
}
/**
@@ -576,8 +576,8 @@ public:
* @return An iterator to the first entity that has the given components.
*/
const_iterator_type cbegin() const ENTT_NOEXCEPT {
- const auto extent = std::min({ std::get &>(pools).extent()... });
- return iterator_type{ unchecked, extent, view->cbegin(), view->cend() };
+ const auto *view = candidate();
+ return iterator_type{ unchecked(view), extent(), view->cbegin(), view->cend() };
}
/**
@@ -614,8 +614,8 @@ public:
* given components.
*/
const_iterator_type cend() const ENTT_NOEXCEPT {
- const auto extent = std::min({ std::get &>(pools).extent()... });
- return iterator_type{ unchecked, extent, view->cend(), view->cend() };
+ const auto *view = candidate();
+ return iterator_type{ unchecked(view), extent(), view->cend(), view->cend() };
}
/**
@@ -643,15 +643,8 @@ public:
* @return True if the view contains the given entity, false otherwise.
*/
bool contains(entity_type entity) const ENTT_NOEXCEPT {
- const auto extent = std::min({ std::get &>(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;
+ return sz < extent() && std::min({ (pool().has(entity) && (pool().data()[pool().view_type::get(entity)] == entity))... });
}
/**
@@ -674,7 +667,7 @@ public:
template
const Comp & get(entity_type entity) const ENTT_NOEXCEPT {
assert(contains(entity));
- return std::get &>(pools).get(entity);
+ return pool().get(entity);
}
/**
@@ -764,10 +757,23 @@ public:
* @param func A valid function object.
*/
template
- inline void each(Func func) const {
- constexpr auto indexes = ident;
+ void each(Func func) const {
+ auto iterate = [&func, this](const auto &cpool) {
+ std::for_each(cpool.view_type::cbegin(), cpool.view_type::cend(), [&func, raw = cpool.cbegin(), unchecked = this->unchecked(&cpool), extent = this->extent(), this](const auto entity) mutable {
+ const auto sz = size_type(entity & traits_type::entity_mask);
+
+ if(sz < extent && std::all_of(unchecked.cbegin(), unchecked.cend(), [entity](const view_type *view) { return view->fast(entity); })) {
+ // avoided indirections due to the sparse set for the pivot type
+ func(entity, this->get::object_type, Component>(raw, entity)...);
+ }
+
+ ++raw;
+ });
+ };
+
+ const auto *view = candidate();
using accumulator_type = int[];
- accumulator_type accumulator = { (indexes.template get() == idx ? (each(std::move(func)), 0) : 0)... };
+ accumulator_type accumulator = { (&pool() == view ? (iterate(pool()), 0) : 0)... };
(void)accumulator;
}
@@ -794,41 +800,8 @@ public:
});
}
- /**
- * @brief Resets the view and reinitializes it.
- *
- * A multi component view keeps a reference to the smallest set of candidate
- * entities to iterate. Resetting a view means querying the underlying data
- * structures and reinitializing the view.
- * Use it only if copies of views are stored around and there is a
- * possibility that a component has become the best candidate in the
- * meantime.
- */
- void reset() {
- using accumulator_type = size_type[];
- size_type sz = std::max({ std::get &>(pools).size()... }) + std::size_t{1};
- size_type next{};
-
- auto probe = [this](auto sz, const auto &pool) {
- return pool.size() < sz ? (view = &pool, pool.size()) : sz;
- };
-
- auto filter = [this](auto next, const auto &pool) {
- return (view == &pool) ? (idx = next) : (unchecked[next++] = &pool, next);
- };
-
- accumulator_type probing = { (sz = probe(sz, std::get &>(pools)))... };
- accumulator_type filtering = { (next = filter(next, std::get &>(pools)))... };
-
- (void)filtering;
- (void)probing;
- }
-
private:
const pattern_type pools;
- const view_type *view;
- unchecked_type unchecked;
- size_type idx;
};
diff --git a/test/entt/entity/view.cpp b/test/entt/entity/view.cpp
index 230503a39..c335820af 100644
--- a/test/entt/entity/view.cpp
+++ b/test/entt/entity/view.cpp
@@ -175,10 +175,6 @@ TEST(View, MultipleComponent) {
registry.remove(e0);
registry.remove(e1);
- view.reset();
-
- ASSERT_EQ(view.begin(), view.end());
- ASSERT_TRUE(view.empty());
}
TEST(View, MultipleComponentBeginEnd) {