performance improvement

This commit is contained in:
Michele Caini
2018-04-26 09:21:04 +02:00
parent caa8d16371
commit 08dc2fcf33
9 changed files with 303 additions and 128 deletions

View File

@@ -1068,7 +1068,7 @@ All of them have pros and cons to take in consideration. In particular:
* Once prepared, creating and destroying them isn't expensive at all because
they don't have any type of initialization.
* They are the best tool for iterating entities for mmultiple components and
* They are the best tool for iterating entities for multiple components when
most entities have them all.
Cons:
@@ -1100,12 +1100,21 @@ All of them have pros and cons to take in consideration. In particular:
To sum up and as a rule of thumb:
* Use a raw view to iterate components only (no entities) for a given type.
* Use a standard view to iterate entities for a single component.
* Use a standard view to iterate entities for multiple components when a
significantly low number of entities have one of the components.
* Use a standard view to iterate entities and components for a single type.
* Use a standard view to iterate entities and components for multiple types when
the number of types is low. Standard views are really optimized and persistent
views won't add much in this case.
* Use a standard view to iterate entities and components for multiple types when
a significantly low number of entities have one of the components.
* Use a standard view in all those cases where a persistent view would give a
boost to performance but the iteration isn't performed frequently.
* Prepare and use a persistent view in all the other cases.
* Prepare and use a persistent view when you want to iterate only entities for
multiple components.
* Prepare and use a persistent view when you want to iterate entities for
multiple components and each component is assigned to a great number of
entities but the intersection between the sets of entities is small.
* Prepare and use a persistent view in all the cases where a standard view
wouldn't fit well otherwise.
To easily iterate entities and components, all the views offer the common
`begin` and `end` member functions that allow users to use a view in a typical

3
TODO
View File

@@ -5,7 +5,8 @@
* define basic reactive systems (track entities to which component is attached, track entities from which component is removed, and so on)
* define systems as composable mixins (initializazion, reactive, update, whatever) with flexible auto-detected arguments (registry, views, etc)
* does it worth it to add an optional functor to the member functions of snapshot so as to filter out instances and entities?
* allow for custom sort functions on registry/view sort (unlikely std::sort is the best function ever in game programming)
* ease the assignment of tags as string (use a template class with a non-type template parameter behind the scene)
* dictionary based dependency class (templates copied over) + prefabs (shared state/copy-on-write)
* prototype entities, a really interesting feature (see #56)
* "singleton mode" for tags (see #66)
* AOB

View File

@@ -143,7 +143,7 @@ struct Actor {
* @return A reference to the instance of the tag owned by the actor.
*/
template<typename Tag>
Tag & get(tag_t) ENTT_NOEXCEPT {
inline Tag & get(tag_t) ENTT_NOEXCEPT {
return const_cast<Tag &>(const_cast<const Actor *>(this)->get<Tag>(tag_t{}));
}
@@ -163,7 +163,7 @@ struct Actor {
* @return A reference to the instance of the component owned by the actor.
*/
template<typename Component>
Component & get() ENTT_NOEXCEPT {
inline Component & get() ENTT_NOEXCEPT {
return const_cast<Component &>(const_cast<const Actor *>(this)->get<Component>());
}
@@ -179,7 +179,7 @@ struct Actor {
* @brief Returns a reference to the underlying registry.
* @return A reference to the underlying registry.
*/
registry_type & registry() ENTT_NOEXCEPT {
inline registry_type & registry() ENTT_NOEXCEPT {
return const_cast<registry_type &>(const_cast<const Actor *>(this)->registry());
}

View File

@@ -44,14 +44,15 @@ class Registry {
template<typename... Component>
static void creating(Registry &registry, Entity entity) {
const auto ttype = handler_family::type<Component...>();
return registry.has<Component...>(entity) ? registry.handlers[ttype]->construct(entity) : void();
if(registry.has<Component...>(entity)) {
registry.handlers[handler_family::type<Component...>()]->construct(entity);
}
}
template<typename... Component>
static void destroying(Registry &registry, Entity entity) {
auto &handler = registry.handlers[handler_family::type<Component...>()];
return handler->has(entity) ? handler->destroy(entity) : void();
auto &handler = *registry.handlers[handler_family::type<Component...>()];
return handler.has(entity) ? handler.destroy(entity) : void();
}
struct Attachee {
@@ -85,7 +86,7 @@ class Registry {
}
template<typename Component>
SparseSet<Entity, Component> & pool() ENTT_NOEXCEPT {
inline SparseSet<Entity, Component> & pool() ENTT_NOEXCEPT {
return const_cast<SparseSet<Entity, Component> &>(const_cast<const Registry *>(this)->pool<Component>());
}
@@ -153,7 +154,7 @@ public:
* @return Runtime numeric identifier of the given type of tag.
*/
template<typename Tag>
tag_type type(tag_t) const ENTT_NOEXCEPT {
static tag_type type(tag_t) ENTT_NOEXCEPT {
return tag_family::type<Tag>();
}
@@ -170,7 +171,7 @@ public:
* @return Runtime numeric identifier of the given type of component.
*/
template<typename Component>
component_type type() const ENTT_NOEXCEPT {
static component_type type() ENTT_NOEXCEPT {
return component_family::type<Component>();
}
@@ -280,7 +281,7 @@ public:
* @return A pointer to the array of components of the given type.
*/
template<typename Component>
Component * raw() ENTT_NOEXCEPT {
inline Component * raw() ENTT_NOEXCEPT {
return const_cast<Component *>(const_cast<const Registry *>(this)->raw<Component>());
}
@@ -619,7 +620,7 @@ public:
* @return A reference to the tag.
*/
template<typename Tag>
Tag & get() ENTT_NOEXCEPT {
inline Tag & get() ENTT_NOEXCEPT {
return const_cast<Tag &>(const_cast<const Registry *>(this)->get<Tag>());
}
@@ -659,7 +660,7 @@ public:
* @return A reference to the component owned by the entity.
*/
template<typename Component>
Component & get(entity_type entity) ENTT_NOEXCEPT {
inline Component & get(entity_type entity) ENTT_NOEXCEPT {
return const_cast<Component &>(const_cast<const Registry *>(this)->get<Component>(entity));
}

View File

@@ -470,7 +470,7 @@ class ContinuousLoader final {
each(archive, [&archive, member..., this](auto entity) {
entity = restore(entity);
auto &tag = registry.template assign<Tag>(entt::tag_t{}, entity);
auto &tag = registry.template assign<Tag>(tag_t{}, entity);
archive(tag);
using accumulator_type = int[];

View File

@@ -692,7 +692,7 @@ public:
* @param entity A valid entity identifier.
* @return The object associated to the entity.
*/
object_type & get(entity_type entity) ENTT_NOEXCEPT {
inline object_type & get(entity_type entity) ENTT_NOEXCEPT {
return const_cast<object_type &>(const_cast<const SparseSet *>(this)->get(entity));
}

View File

@@ -5,39 +5,19 @@
namespace entt {
/**
* @brief Tag class type.
*
* An empty class type used to disambiguate the overloads of some member
* functions.
*/
/*! @brief Tag class type used to disambiguate overloads. */
struct tag_t final {};
/**
* @brief Persistent view type.
*
* An empty class type used to disambiguate the overloads of some member
* functions.
*/
/*! @brief Persistent view type used to disambiguate overloads. */
struct persistent_t final {};
/**
* @brief Raw view type.
*
* An empty class type used to disambiguate the overloads of some member
* functions.
*/
/*! @brief Raw view type used to disambiguate overloads. */
struct raw_t final {};
/**
* @brief Break type.
*
* An empty class type used to disambiguate the overloads of some member
* functions.
*/
/*! @brief Break type used to disambiguate overloads. */
struct break_t final {};

View File

@@ -9,6 +9,7 @@
#include <algorithm>
#include <type_traits>
#include "../config/config.h"
#include "../core/ident.hpp"
#include "entt_traits.hpp"
#include "sparse_set.hpp"
@@ -247,7 +248,7 @@ public:
* @return The component assigned to the entity.
*/
template<typename Comp>
Comp & get(entity_type entity) ENTT_NOEXCEPT {
inline Comp & get(entity_type entity) ENTT_NOEXCEPT {
return const_cast<Comp &>(const_cast<const PersistentView *>(this)->get<Comp>(entity));
}
@@ -339,9 +340,9 @@ public:
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) {
std::for_each(view.begin(), view.end(), [&func, this](const auto entity) {
func(entity, std::get<pool_type<Component> &>(pools).get(entity)...);
inline void each(Func func) {
const_cast<const PersistentView *>(this)->each([&func](entity_type entity, const Component &... component) {
func(entity, const_cast<Component &>(component)...);
});
}
@@ -428,6 +429,28 @@ class View final {
using pattern_type = std::tuple<pool_type<Component> &...>;
using traits_type = entt_traits<Entity>;
template<typename...>
struct ComponentList {};
template<typename, typename, typename = ComponentList<>, typename = void>
struct SplitComponentListBy;
template<typename Comp, typename Next, typename... Other, typename... Types>
struct SplitComponentListBy<Comp, ComponentList<Next, Other...>, ComponentList<Types...>, std::enable_if_t<std::is_same<Comp, Next>::value>> {
using pre_type = ComponentList<Types...>;
using post_type = ComponentList<Other...>;
};
template<typename Comp, typename Next, typename... Other, typename... Types>
struct SplitComponentListBy<Comp, ComponentList<Next, Other...>, ComponentList<Types...>, std::enable_if_t<!std::is_same<Comp, Next>::value>>
: SplitComponentListBy<Comp, ComponentList<Other...>, ComponentList<Types..., Next>> {};
template<typename Comp>
using PreList = typename SplitComponentListBy<Comp, ComponentList<Component...>>::pre_type;
template<typename Comp>
using PostList = typename SplitComponentListBy<Comp, ComponentList<Component...>>::post_type;
class Iterator {
using size_type = typename view_type::size_type;
@@ -498,11 +521,32 @@ class View final {
};
View(pool_type<Component> &... pools) ENTT_NOEXCEPT
: pools{pools...}, view{nullptr}, unchecked{}
: pools{pools...}, view{nullptr}, unchecked{}, idx{}
{
reset();
}
template<typename Comp, typename... Pre, typename... Post, typename Func>
void each(Func func, ComponentList<Pre...>, ComponentList<Post...>) const {
const auto extent = std::min({ std::get<pool_type<Component> &>(pools).extent()... });
auto &pool = std::get<pool_type<Comp> &>(pools);
std::for_each(pool.view_type::cbegin(), pool.view_type::cend(), [&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
func(entity, std::get<pool_type<Pre> &>(pools).get(entity)..., *(raw)++, std::get<pool_type<Post> &>(pools).get(entity)...);
}
}
});
}
public:
/*! @brief Input iterator type. */
using iterator_type = Iterator;
@@ -663,7 +707,7 @@ public:
* @return The component assigned to the entity.
*/
template<typename Comp>
Comp & get(entity_type entity) ENTT_NOEXCEPT {
inline Comp & get(entity_type entity) ENTT_NOEXCEPT {
return const_cast<Comp &>(const_cast<const View *>(this)->get<Comp>(entity));
}
@@ -732,22 +776,11 @@ public:
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) const {
const auto extent = std::min({ std::get<pool_type<Component> &>(pools).extent()... });
std::for_each(view->cbegin(), view->cend(), [&func, extent, this](const auto entity) {
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, std::get<pool_type<Component> &>(pools).get(entity)...);
}
}
});
inline void each(Func func) const {
constexpr auto indexes = ident<Component...>;
using accumulator_type = int[];
accumulator_type accumulator = { (indexes.template get<Component>() == idx ? (each<Component>(std::move(func), PreList<Component>{}, PostList<Component>{}), 0) : 0)... };
(void)accumulator;
}
/**
@@ -767,7 +800,7 @@ public:
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) {
inline void each(Func func) {
const_cast<const View *>(this)->each([&func](entity_type entity, const Component &... component) {
func(entity, const_cast<Component &>(component)...);
});
@@ -786,18 +819,18 @@ public:
void reset() {
using accumulator_type = size_type[];
size_type sz = std::max({ std::get<pool_type<Component> &>(pools).size()... }) + std::size_t{1};
size_type pos{};
size_type next{};
auto probe = [this](auto sz, const auto &pool) {
return pool.size() < sz ? (view = &pool, pool.size()) : sz;
};
auto filter = [this](auto pos, const auto &pool) {
return (view != &pool) ? (unchecked[pos++] = &pool, pos) : pos;
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<pool_type<Component> &>(pools)))... };
accumulator_type filtering = { (pos = filter(pos, std::get<pool_type<Component> &>(pools)))... };
accumulator_type filtering = { (next = filter(next, std::get<pool_type<Component> &>(pools)))... };
(void)filtering;
(void)probing;
@@ -807,6 +840,7 @@ private:
const pattern_type pools;
const view_type *view;
unchecked_type unchecked;
size_type idx;
};
@@ -915,7 +949,7 @@ public:
*
* @return A pointer to the array of components.
*/
raw_type * raw() ENTT_NOEXCEPT {
inline raw_type * raw() ENTT_NOEXCEPT {
return const_cast<raw_type *>(const_cast<const View *>(this)->raw());
}
@@ -1053,7 +1087,7 @@ public:
* @param entity A valid entity identifier.
* @return The component assigned to the entity.
*/
Component & get(entity_type entity) ENTT_NOEXCEPT {
inline Component & get(entity_type entity) ENTT_NOEXCEPT {
return const_cast<Component &>(const_cast<const View *>(this)->get(entity));
}
@@ -1074,8 +1108,8 @@ public:
*/
template<typename Func>
void each(Func func) const {
std::for_each(pool.view_type::cbegin(), pool.view_type::cend(), [&func, this](const auto entity) {
func(entity, pool.get(entity));
std::for_each(pool.view_type::cbegin(), pool.view_type::cend(), [&func, raw = pool.cbegin()](const auto entity) mutable {
func(entity, *(raw++));
});
}
@@ -1095,9 +1129,9 @@ public:
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) {
std::for_each(pool.view_type::begin(), pool.view_type::end(), [&func, this](const auto entity) {
func(entity, pool.get(entity));
inline void each(Func func) {
const_cast<const View *>(this)->each([&func](entity_type entity, const Component &component) {
func(entity, const_cast<Component &>(component));
});
}
@@ -1211,7 +1245,7 @@ public:
*
* @return A pointer to the array of components.
*/
raw_type * raw() ENTT_NOEXCEPT {
inline raw_type * raw() ENTT_NOEXCEPT {
return const_cast<raw_type *>(const_cast<const RawView *>(this)->raw());
}

View File

@@ -77,13 +77,11 @@ TEST(Benchmark, IterateCreateDeleteSingleComponent) {
registry.assign<Position>(entity);
}
view.each([&](auto entity, auto &position) {
(void)position;
for(auto entity: view) {
if(rand() % 2 == 0) {
registry.destroy(entity);
}
});
}
}
timer.elapsed();
@@ -99,9 +97,16 @@ TEST(Benchmark, IterateSingleComponent1M) {
registry.assign<Position>(entity);
}
Timer timer;
registry.view<Position>().each([](auto, auto &) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position>().each(func);
timer.elapsed();
};
test([](auto, const auto &) {});
test([](auto, auto &position) {
position.x = {};
});
}
TEST(Benchmark, IterateSingleComponentRaw1M) {
@@ -114,11 +119,16 @@ TEST(Benchmark, IterateSingleComponentRaw1M) {
registry.assign<Position>(entity);
}
Timer timer;
for(auto &&component: registry.view<Position>(entt::raw_t{})) {
(void)component;
}
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position>(entt::raw_t{}).each(func);
timer.elapsed();
};
test([](const auto &) {});
test([](auto &position) {
position.x = {};
});
}
TEST(Benchmark, IterateTwoComponents1M) {
@@ -132,9 +142,17 @@ TEST(Benchmark, IterateTwoComponents1M) {
registry.assign<Velocity>(entity);
}
Timer timer;
registry.view<Position, Velocity>().each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity>().each(func);
timer.elapsed();
};
test([](auto, const auto &...) {});
test([](auto, auto &position, auto &velocity) {
position.x = {};
velocity.x = {};
});
}
TEST(Benchmark, IterateTwoComponents1MHalf) {
@@ -151,9 +169,17 @@ TEST(Benchmark, IterateTwoComponents1MHalf) {
}
}
Timer timer;
registry.view<Position, Velocity>().each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity>().each(func);
timer.elapsed();
};
test([](auto, const auto &...) {});
test([](auto, auto &position, auto &velocity) {
position.x = {};
velocity.x = {};
});
}
TEST(Benchmark, IterateTwoComponents1MOne) {
@@ -170,9 +196,17 @@ TEST(Benchmark, IterateTwoComponents1MOne) {
}
}
Timer timer;
registry.view<Position, Velocity>().each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity>().each(func);
timer.elapsed();
};
test([](auto, const auto &...) {});
test([](auto, auto &position, auto &velocity) {
position.x = {};
velocity.x = {};
});
}
TEST(Benchmark, IterateTwoComponentsPersistent1M) {
@@ -187,9 +221,17 @@ TEST(Benchmark, IterateTwoComponentsPersistent1M) {
registry.assign<Velocity>(entity);
}
Timer timer;
registry.view<Position, Velocity>(entt::persistent_t{}).each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity>(entt::persistent_t{}).each(func);
timer.elapsed();
};
test([](auto, const auto &...) {});
test([](auto, auto &position, auto &velocity) {
position.x = {};
velocity.x = {};
});
}
TEST(Benchmark, IterateFiveComponents1M) {
@@ -206,9 +248,20 @@ TEST(Benchmark, IterateFiveComponents1M) {
registry.assign<Comp<3>>(entity);
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each(func);
timer.elapsed();
};
test([](auto, const auto &...) {});
test([](auto, auto &position, auto &velocity, auto &comp1, auto &comp2, auto &comp3) {
position.x = {};
velocity.x = {};
comp1.x = {};
comp2.x = {};
comp3.x = {};
});
}
TEST(Benchmark, IterateFiveComponents1MHalf) {
@@ -228,9 +281,20 @@ TEST(Benchmark, IterateFiveComponents1MHalf) {
}
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each(func);
timer.elapsed();
};
test([](auto, const auto &...) {});
test([](auto, auto &position, auto &velocity, auto &comp1, auto &comp2, auto &comp3) {
position.x = {};
velocity.x = {};
comp1.x = {};
comp2.x = {};
comp3.x = {};
});
}
TEST(Benchmark, IterateFiveComponents1MOne) {
@@ -250,9 +314,20 @@ TEST(Benchmark, IterateFiveComponents1MOne) {
}
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>().each(func);
timer.elapsed();
};
test([](auto, const auto &...) {});
test([](auto, auto &position, auto &velocity, auto &comp1, auto &comp2, auto &comp3) {
position.x = {};
velocity.x = {};
comp1.x = {};
comp2.x = {};
comp3.x = {};
});
}
TEST(Benchmark, IterateFiveComponentsPersistent1M) {
@@ -270,9 +345,20 @@ TEST(Benchmark, IterateFiveComponentsPersistent1M) {
registry.assign<Comp<3>>(entity);
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>(entt::persistent_t{}).each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>>(entt::persistent_t{}).each(func);
timer.elapsed();
};
test([](auto, const auto &...) {});
test([](auto, auto &position, auto &velocity, auto &comp1, auto &comp2, auto &comp3) {
position.x = {};
velocity.x = {};
comp1.x = {};
comp2.x = {};
comp3.x = {};
});
}
TEST(Benchmark, IterateTenComponents1M) {
@@ -294,9 +380,25 @@ TEST(Benchmark, IterateTenComponents1M) {
registry.assign<Comp<8>>(entity);
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each(func);
timer.elapsed();
};
test([](auto, const auto &...) {});
test([](auto, auto &position, auto &velocity, auto &comp1, auto &comp2, auto &comp3, auto &comp4, auto &comp5, auto &comp6, auto &comp7, auto &comp8) {
position.x = {};
velocity.x = {};
comp1.x = {};
comp2.x = {};
comp3.x = {};
comp4.x = {};
comp5.x = {};
comp6.x = {};
comp7.x = {};
comp8.x = {};
});
}
TEST(Benchmark, IterateTenComponents1MHalf) {
@@ -321,9 +423,25 @@ TEST(Benchmark, IterateTenComponents1MHalf) {
}
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each(func);
timer.elapsed();
};
test([](auto, auto &...) {});
test([](auto, auto &position, auto &velocity, auto &comp1, auto &comp2, auto &comp3, auto &comp4, auto &comp5, auto &comp6, auto &comp7, auto &comp8) {
position.x = {};
velocity.x = {};
comp1.x = {};
comp2.x = {};
comp3.x = {};
comp4.x = {};
comp5.x = {};
comp6.x = {};
comp7.x = {};
comp8.x = {};
});
}
TEST(Benchmark, IterateTenComponents1MOne) {
@@ -348,9 +466,25 @@ TEST(Benchmark, IterateTenComponents1MOne) {
}
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>().each(func);
timer.elapsed();
};
test([](auto, const auto &...) {});
test([](auto, auto &position, auto &velocity, auto &comp1, auto &comp2, auto &comp3, auto &comp4, auto &comp5, auto &comp6, auto &comp7, auto &comp8) {
position.x = {};
velocity.x = {};
comp1.x = {};
comp2.x = {};
comp3.x = {};
comp4.x = {};
comp5.x = {};
comp6.x = {};
comp7.x = {};
comp8.x = {};
});
}
TEST(Benchmark, IterateTenComponentsPersistent1M) {
@@ -373,9 +507,25 @@ TEST(Benchmark, IterateTenComponentsPersistent1M) {
registry.assign<Comp<8>>(entity);
}
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>(entt::persistent_t{}).each([](auto, auto &...) {});
timer.elapsed();
auto test = [&registry](auto func) {
Timer timer;
registry.view<Position, Velocity, Comp<1>, Comp<2>, Comp<3>, Comp<4>, Comp<5>, Comp<6>, Comp<7>, Comp<8>>(entt::persistent_t{}).each(func);
timer.elapsed();
};
test([](auto, const auto &...) {});
test([](auto, auto &position, auto &velocity, auto &comp1, auto &comp2, auto &comp3, auto &comp4, auto &comp5, auto &comp6, auto &comp7, auto &comp8) {
position.x = {};
velocity.x = {};
comp1.x = {};
comp2.x = {};
comp3.x = {};
comp4.x = {};
comp5.x = {};
comp6.x = {};
comp7.x = {};
comp8.x = {};
});
}
TEST(Benchmark, SortSingle) {