diff --git a/TODO b/TODO index b19fdf246..a4dc9ce17 100644 --- a/TODO +++ b/TODO @@ -13,9 +13,9 @@ * static reflection, hint: template<> meta_type_t: meta_descriptor * add meta support to registry (eg entity for each component and opaque get) * allow for custom stamp functions -* merge create() and create(hint), is it a viable solution? * observer: user defined filters (eg .replace or .group) * use underlying_type as entity type within pools and registry? it would make different registries work together flawlessy * can we write a bool conv func for entt::entity that silently compares it to null? +* stamp makes sense only when the list of components is empty * any-of rule for views/groups (eg entity has A and any of B/C/D) - get -> all, exclude -> none diff --git a/docs/md/entity.md b/docs/md/entity.md index b7e9939b4..7d0a4f710 100644 --- a/docs/md/entity.md +++ b/docs/md/entity.md @@ -172,10 +172,6 @@ auto view = registry.view(); registry.destroy(view.begin(), view.end()); ``` -In all cases, the `create` member function accepts also a list of default -constructible component types to assign to the entities before to return. It's a -faster alternative to the creation and subsequent assignment of components. - When an entity is destroyed, the registry can freely reuse it internally with a slightly different identifier. In particular, the version of an entity is increased after destruction.
diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 1e1d8e486..30ad0cc67 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -183,31 +183,6 @@ class basic_registry { } }; - auto generate() { - Entity entt; - - if(destroyed == null) { - entt = entities.emplace_back(entity_type(entities.size())); - // traits_type::entity_mask is reserved to allow for null identifiers - ENTT_ASSERT(to_integral(entt) < traits_type::entity_mask); - } else { - const auto curr = to_integral(destroyed); - const auto version = to_integral(entities[curr]) & (traits_type::version_mask << traits_type::entity_shift); - destroyed = entity_type{to_integral(entities[curr]) & traits_type::entity_mask}; - entt = entities[curr] = entity_type{curr | version}; - } - - return entt; - } - - void release(const Entity entity) { - // lengthens the implicit list of destroyed entities - const auto entt = to_integral(entity) & traits_type::entity_mask; - const auto version = ((to_integral(entity) >> traits_type::entity_shift) + 1) << traits_type::entity_shift; - entities[entt] = entity_type{to_integral(destroyed) | version}; - destroyed = entity_type{entt}; - } - template const pool_handler & assure(Args &&... args) const { static std::size_t index{pools.size()}; @@ -476,33 +451,28 @@ public: /** * @brief Creates a new entity and returns it. * - * There are two kinds of entity identifiers: + * There are two kinds of possible entity identifiers: * * * Newly created ones in case no entities have been previously destroyed. * * Recycled ones with updated versions. * - * Users should not care about the type of the returned entity identifier. - * In case entity identifers are stored around, the `valid` member - * function can be used to know if they are still valid or the entity has - * been destroyed and potentially recycled.
- * The returned entity has assigned the given components, if any. - * - * The components must be at least default constructible. A compilation - * error will occur otherwhise. - * - * @tparam Component Types of components to assign to the entity. - * @return A valid entity identifier if the component list is empty, a tuple - * containing the entity identifier and the references to the components - * just created otherwise. + * @return A valid entity identifier. */ - template - auto create() { - if constexpr(sizeof...(Component) == 0) { - return generate(); + entity_type create() { + entity_type entt; + + if(destroyed == null) { + entt = entities.emplace_back(entity_type(entities.size())); + // traits_type::entity_mask is reserved to allow for null identifiers + ENTT_ASSERT(to_integral(entt) < traits_type::entity_mask); } else { - const entity_type entt = generate(); - return std::tuple_cat(std::make_tuple(entt), std::forward_as_tuple(assign(entt)...)); + const auto curr = to_integral(destroyed); + const auto version = to_integral(entities[curr]) & (traits_type::version_mask << traits_type::entity_shift); + destroyed = entity_type{to_integral(entities[curr]) & traits_type::entity_mask}; + entt = entities[curr] = entity_type{curr | version}; } + + return entt; } /** @@ -510,24 +480,13 @@ public: * * @sa create * - * The components must be at least move and default insertable. A - * compilation error will occur otherwhise. - * - * @tparam Component Types of components to assign to the entity. * @tparam It Type of forward iterator. * @param first An iterator to the first element of the range to generate. * @param last An iterator past the last element of the range to generate. - * @return No return value if the component list is empty, a tuple - * containing the iterators to the lists of components just created and - * sorted the same of the entities otherwise. */ - template - auto create(It first, It last) { - std::generate(first, last, [this]() { return generate(); }); - - if constexpr(sizeof...(Component) > 0) { - return std::make_tuple(assure().assign(*this, first, last)...); - } + template + void create(It first, It last) { + std::generate(first, last, [this]() { return create(); }); } /** @@ -538,14 +497,11 @@ public: * If the requested entity isn't in use, the suggested identifier is created * and returned. Otherwise, a new one will be generated for this purpose. * - * @tparam Component Types of components to assign to the entity. * @param hint A desired entity identifier. - * @return A valid entity identifier if the component list is empty, a tuple - * containing the entity identifier and the references to the components - * just created otherwise. + * @return A valid entity identifier. */ template - auto create(const entity_type hint) { + entity_type create(const entity_type hint) { ENTT_ASSERT(hint != null); entity_type entt; @@ -559,7 +515,7 @@ public: entt = entities.emplace_back(hint); } else if(const auto curr = (to_integral(entities[req]) & traits_type::entity_mask); req == curr) { - entt = generate(); + entt = create(); } else { auto *it = &destroyed; for(; (to_integral(*it) & traits_type::entity_mask) != req; it = &entities[to_integral(*it) & traits_type::entity_mask]); @@ -567,20 +523,14 @@ public: entt = entities[req] = hint; } - if constexpr(sizeof...(Component) == 0) { - return entt; - } else { - return std::tuple_cat(std::make_tuple(entt), std::forward_as_tuple(assign(entt)...)); - } + return entt; } /** * @brief Destroys an entity and lets the registry recycle the identifier. * * When an entity is destroyed, its version is updated and the identifier - * can be recycled at any time. In case entity identifers are stored around, - * the `valid` member function can be used to know if they are still valid - * or the entity has been destroyed and potentially recycled. + * can be recycled at any time. * * @warning * In case there are listeners that observe the destruction of components @@ -607,7 +557,12 @@ public: // just a way to protect users from listeners that attach components ENTT_ASSERT(orphan(entity)); - release(entity); + + // lengthens the implicit list of destroyed entities + const auto entt = to_integral(entity) & traits_type::entity_mask; + const auto version = ((to_integral(entity) >> traits_type::entity_shift) + 1) << traits_type::entity_shift; + entities[entt] = entity_type{to_integral(destroyed) | version}; + destroyed = entity_type{entt}; } /** @@ -658,10 +613,10 @@ public: * * @tparam Component Type of component to create. * @tparam It Type of input iterator. - * @tparam Args Types of arguments to use to construct the component. + * @tparam Args Types of arguments to use to construct the components. * @param first An iterator to the first element of the range of entities. * @param last An iterator past the last element of the range of entities. - * @param args Parameters to use to initialize the component. + * @param args Parameters to use to initialize the components. * @return An iterator to the list of components just created. */ template diff --git a/test/benchmark/benchmark.cpp b/test/benchmark/benchmark.cpp index a4c74d523..133d490f8 100644 --- a/test/benchmark/benchmark.cpp +++ b/test/benchmark/benchmark.cpp @@ -114,7 +114,9 @@ TEST(Benchmark, ConstructManyWithComponents) { std::cout << "Constructing 1000000 entities at once with components" << std::endl; timer timer; - registry.create(entities.begin(), entities.end()); + registry.create(entities.begin(), entities.end()); + registry.assign(entities.begin(), entities.end()); + registry.assign(entities.begin(), entities.end()); timer.elapsed(); } diff --git a/test/entt/entity/group.cpp b/test/entt/entity/group.cpp index a2cfdbf67..f27cd9fde 100644 --- a/test/entt/entity/group.cpp +++ b/test/entt/entity/group.cpp @@ -468,7 +468,11 @@ TEST(NonOwningGroup, TrackEntitiesOnComponentDestruction) { TEST(NonOwningGroup, Less) { entt::registry registry; - const auto entity = std::get<0>(registry.create>()); + const auto entity = registry.create(); + + registry.assign(entity); + registry.assign(entity); + registry.assign>(entity); registry.group(entt::get>).less([entity](const auto entt, int, char) { ASSERT_EQ(entity, entt); @@ -1040,7 +1044,11 @@ TEST(OwningGroup, TrackEntitiesOnComponentDestruction) { TEST(OwningGroup, Less) { entt::registry registry; - const auto entity = std::get<0>(registry.create>()); + const auto entity = registry.create(); + + registry.assign(entity); + registry.assign(entity); + registry.assign>(entity); registry.group(entt::get>).less([entity](const auto entt, int, char) { ASSERT_EQ(entity, entt); diff --git a/test/entt/entity/observer.cpp b/test/entt/entity/observer.cpp index 4c3ec9e12..ea13807fe 100644 --- a/test/entt/entity/observer.cpp +++ b/test/entt/entity/observer.cpp @@ -14,7 +14,8 @@ TEST(Observer, Functionalities) { ASSERT_EQ(observer.data(), nullptr); ASSERT_EQ(observer.begin(), observer.end()); - const auto entity = std::get<0>(registry.create()); + const auto entity = registry.create(); + registry.assign(entity); ASSERT_EQ(observer.size(), 1u); ASSERT_FALSE(observer.empty()); @@ -263,7 +264,8 @@ TEST(Observer, CrossRulesCornerCase) { TEST(Observer, Each) { entt::registry registry; entt::observer observer{registry, entt::collector.group()}; - const auto entity = std::get<0>(registry.create()); + const auto entity = registry.create(); + registry.assign(entity); ASSERT_FALSE(observer.empty()); ASSERT_EQ(observer.size(), 1u); diff --git a/test/entt/entity/registry.cpp b/test/entt/entity/registry.cpp index 2466e6927..73205d50b 100644 --- a/test/entt/entity/registry.cpp +++ b/test/entt/entity/registry.cpp @@ -279,6 +279,93 @@ TEST(Registry, RawData) { ASSERT_EQ(*std::as_const(registry).data(), entity); } +TEST(Registry, CreateManyEntitiesAtOnce) { + entt::registry registry; + entt::entity entities[3]; + + const auto entity = registry.create(); + registry.destroy(registry.create()); + registry.destroy(entity); + registry.destroy(registry.create()); + + registry.create(std::begin(entities), std::end(entities)); + + ASSERT_TRUE(registry.valid(entities[0])); + ASSERT_TRUE(registry.valid(entities[1])); + ASSERT_TRUE(registry.valid(entities[2])); + + ASSERT_EQ(registry.entity(entities[0]), entt::entity{0}); + ASSERT_EQ(registry.version(entities[0]), entt::registry::version_type{2}); + + ASSERT_EQ(registry.entity(entities[1]), entt::entity{1}); + ASSERT_EQ(registry.version(entities[1]), entt::registry::version_type{1}); + + ASSERT_EQ(registry.entity(entities[2]), entt::entity{2}); + ASSERT_EQ(registry.version(entities[2]), entt::registry::version_type{0}); +} + +TEST(Registry, CreateWithHint) { + entt::registry registry; + auto e3 = registry.create(entt::entity{3}); + auto e2 = registry.create(entt::entity{3}); + + ASSERT_EQ(e2, entt::entity{2}); + ASSERT_FALSE(registry.valid(entt::entity{1})); + ASSERT_EQ(e3, entt::entity{3}); + + registry.destroy(e2); + + ASSERT_EQ(registry.version(e2), 0); + ASSERT_EQ(registry.current(e2), 1); + + e2 = registry.create(); + auto e1 = registry.create(entt::entity{2}); + + ASSERT_EQ(registry.entity(e2), entt::entity{2}); + ASSERT_EQ(registry.version(e2), 1); + + ASSERT_EQ(registry.entity(e1), entt::entity{1}); + ASSERT_EQ(registry.version(e1), 0); + + registry.destroy(e1); + registry.destroy(e2); + auto e0 = registry.create(entt::entity{0}); + + ASSERT_EQ(e0, entt::entity{0}); + ASSERT_EQ(registry.version(e0), 0); +} + +TEST(Registry, CreateDestroyEntities) { + entt::registry registry; + entt::entity pre{}, post{}; + + for(int i = 0; i < 10; ++i) { + const auto entity = registry.create(); + registry.assign(entity); + } + + registry.reset(); + + for(int i = 0; i < 7; ++i) { + const auto entity = registry.create(); + registry.assign(entity); + if(i == 3) { pre = entity; } + } + + registry.reset(); + + for(int i = 0; i < 5; ++i) { + const auto entity = registry.create(); + if(i == 3) { post = entity; } + } + + ASSERT_FALSE(registry.valid(pre)); + ASSERT_TRUE(registry.valid(post)); + ASSERT_NE(registry.version(pre), registry.version(post)); + ASSERT_EQ(registry.version(pre) + 1, registry.version(post)); + ASSERT_EQ(registry.current(pre), registry.current(post)); +} + TEST(Registry, CreateDestroyCornerCase) { entt::registry registry; @@ -316,9 +403,9 @@ TEST(Registry, Each) { entt::registry::size_type match; registry.create(); - registry.create(); + registry.assign(registry.create()); registry.create(); - registry.create(); + registry.assign(registry.create()); registry.create(); tot = 0u; @@ -367,9 +454,9 @@ TEST(Registry, Orphans) { entt::registry registry; entt::registry::size_type tot{}; - registry.create(); + registry.assign(registry.create()); registry.create(); - registry.create(); + registry.assign(registry.create()); registry.orphans([&](auto) { ++tot; }); ASSERT_EQ(tot, 1u); @@ -385,37 +472,6 @@ TEST(Registry, Orphans) { ASSERT_EQ(tot, 0u); } -TEST(Registry, CreateDestroyEntities) { - entt::registry registry; - entt::entity pre{}, post{}; - - for(int i = 0; i < 10; ++i) { - const auto entity = registry.create(); - registry.assign(entity); - } - - registry.reset(); - - for(int i = 0; i < 7; ++i) { - const auto entity = registry.create(); - registry.assign(entity); - if(i == 3) { pre = entity; } - } - - registry.reset(); - - for(int i = 0; i < 5; ++i) { - const auto entity = registry.create(); - if(i == 3) { post = entity; } - } - - ASSERT_FALSE(registry.valid(pre)); - ASSERT_TRUE(registry.valid(post)); - ASSERT_NE(registry.version(pre), registry.version(post)); - ASSERT_EQ(registry.version(pre) + 1, registry.version(post)); - ASSERT_EQ(registry.current(pre), registry.current(post)); -} - TEST(Registry, View) { entt::registry registry; auto mview = registry.view(); @@ -444,10 +500,14 @@ TEST(Registry, View) { TEST(Registry, NonOwningGroupInitOnFirstUse) { entt::registry registry; + auto create = [&](auto... component) { + const auto entity = registry.create(); + (registry.assign(entity, component), ...); + }; - std::get<2>(registry.create()) = 'c'; - registry.create(); - std::get<2>(registry.create()) = 'c'; + create(0, 'c'); + create(0); + create(0, 'c'); std::size_t cnt{}; auto group = registry.group<>(entt::get); @@ -460,10 +520,14 @@ TEST(Registry, NonOwningGroupInitOnFirstUse) { TEST(Registry, NonOwningGroupInitOnAssign) { entt::registry registry; auto group = registry.group<>(entt::get); + auto create = [&](auto... component) { + const auto entity = registry.create(); + (registry.assign(entity, component), ...); + }; - std::get<2>(registry.create()) = 'c'; - registry.create(); - std::get<2>(registry.create()) = 'c'; + create(0, 'c'); + create(0); + create(0, 'c'); std::size_t cnt{}; group.each([&cnt](auto...) { ++cnt; }); @@ -474,10 +538,14 @@ TEST(Registry, NonOwningGroupInitOnAssign) { TEST(Registry, FullOwningGroupInitOnFirstUse) { entt::registry registry; + auto create = [&](auto... component) { + const auto entity = registry.create(); + (registry.assign(entity, component), ...); + }; - std::get<2>(registry.create()) = 'c'; - registry.create(); - std::get<2>(registry.create()) = 'c'; + create(0, 'c'); + create(0); + create(0, 'c'); std::size_t cnt{}; auto group = registry.group(); @@ -492,10 +560,14 @@ TEST(Registry, FullOwningGroupInitOnFirstUse) { TEST(Registry, FullOwningGroupInitOnAssign) { entt::registry registry; auto group = registry.group(); + auto create = [&](auto... component) { + const auto entity = registry.create(); + (registry.assign(entity, component), ...); + }; - std::get<2>(registry.create()) = 'c'; - registry.create(); - std::get<2>(registry.create()) = 'c'; + create(0, 'c'); + create(0); + create(0, 'c'); std::size_t cnt{}; group.each([&cnt](auto...) { ++cnt; }); @@ -508,10 +580,14 @@ TEST(Registry, FullOwningGroupInitOnAssign) { TEST(Registry, PartialOwningGroupInitOnFirstUse) { entt::registry registry; + auto create = [&](auto... component) { + const auto entity = registry.create(); + (registry.assign(entity, component), ...); + }; - std::get<2>(registry.create()) = 'c'; - registry.create(); - std::get<2>(registry.create()) = 'c'; + create(0, 'c'); + create(0); + create(0, 'c'); std::size_t cnt{}; auto group = registry.group(entt::get); @@ -527,10 +603,14 @@ TEST(Registry, PartialOwningGroupInitOnFirstUse) { TEST(Registry, PartialOwningGroupInitOnAssign) { entt::registry registry; auto group = registry.group(entt::get); + auto create = [&](auto... component) { + const auto entity = registry.create(); + (registry.assign(entity, component), ...); + }; - std::get<2>(registry.create()) = 'c'; - registry.create(); - std::get<2>(registry.create()) = 'c'; + create(0, 'c'); + create(0); + create(0, 'c'); std::size_t cnt{}; group.each([&cnt](auto...) { ++cnt; }); @@ -669,7 +749,9 @@ TEST(Registry, NestedGroups) { entt::registry registry; entt::entity entities[10]; - registry.create(std::begin(entities), std::end(entities)); + registry.create(std::begin(entities), std::end(entities)); + registry.assign(std::begin(entities), std::end(entities)); + registry.assign(std::begin(entities), std::end(entities)); const auto g1 = registry.group(entt::get, entt::exclude); ASSERT_TRUE(g1.sortable()); @@ -1118,152 +1200,6 @@ TEST(Registry, RangeRemove) { ASSERT_TRUE(registry.has(e2)); } -TEST(Registry, CreateManyEntitiesAtOnce) { - entt::registry registry; - entt::entity entities[3]; - - const auto entity = registry.create(); - registry.destroy(registry.create()); - registry.destroy(entity); - registry.destroy(registry.create()); - - registry.create(std::begin(entities), std::end(entities)); - - ASSERT_TRUE(registry.valid(entities[0])); - ASSERT_TRUE(registry.valid(entities[1])); - ASSERT_TRUE(registry.valid(entities[2])); - - ASSERT_EQ(registry.entity(entities[0]), entt::entity{0}); - ASSERT_EQ(registry.version(entities[0]), entt::registry::version_type{2}); - - ASSERT_EQ(registry.entity(entities[1]), entt::entity{1}); - ASSERT_EQ(registry.version(entities[1]), entt::registry::version_type{1}); - - ASSERT_EQ(registry.entity(entities[2]), entt::entity{2}); - ASSERT_EQ(registry.version(entities[2]), entt::registry::version_type{0}); -} - -TEST(Registry, CreateAnEntityWithComponents) { - entt::registry registry; - auto &&[entity, ivalue, cvalue, evalue] = registry.create(); - // suppress warnings - (void)evalue; - - ASSERT_FALSE(registry.empty()); - ASSERT_FALSE(registry.empty()); - ASSERT_FALSE(registry.empty()); - - ASSERT_EQ(registry.size(), entt::registry::size_type{1}); - ASSERT_EQ(registry.size(), entt::registry::size_type{1}); - ASSERT_EQ(registry.size(), entt::registry::size_type{1}); - - ASSERT_TRUE((registry.has(entity))); - - ivalue = 42; - cvalue = 'c'; - - ASSERT_EQ(registry.get(entity), 42); - ASSERT_EQ(registry.get(entity), 'c'); -} - -TEST(Registry, CreateManyEntitiesWithComponentsAtOnce) { - entt::registry registry; - entt::entity entities[3]; - - const auto entity = registry.create(); - registry.destroy(registry.create()); - registry.destroy(entity); - registry.destroy(registry.create()); - - const auto [iptr, cptr, eptr] = registry.create(std::begin(entities), std::end(entities)); - static_assert(std::is_same_v); - - ASSERT_FALSE(registry.empty()); - ASSERT_FALSE(registry.empty()); - ASSERT_FALSE(registry.empty()); - - ASSERT_EQ(registry.size(), entt::registry::size_type{3}); - ASSERT_EQ(registry.size(), entt::registry::size_type{3}); - ASSERT_EQ(registry.size(), entt::registry::size_type{3}); - - ASSERT_TRUE(registry.valid(entities[0])); - ASSERT_TRUE(registry.valid(entities[1])); - ASSERT_TRUE(registry.valid(entities[2])); - - ASSERT_EQ(registry.entity(entities[0]), entt::entity{0}); - ASSERT_EQ(registry.version(entities[0]), entt::registry::version_type{2}); - - ASSERT_EQ(registry.entity(entities[1]), entt::entity{1}); - ASSERT_EQ(registry.version(entities[1]), entt::registry::version_type{1}); - - ASSERT_EQ(registry.entity(entities[2]), entt::entity{2}); - ASSERT_EQ(registry.version(entities[2]), entt::registry::version_type{0}); - - ASSERT_TRUE((registry.has(entities[0]))); - ASSERT_TRUE((registry.has(entities[1]))); - ASSERT_TRUE((registry.has(entities[2]))); - - for(auto i = 0; i < 3; ++i) { - iptr[i] = i; - cptr[i] = char('a'+i); - } - - for(auto i = 0; i < 3; ++i) { - ASSERT_EQ(registry.get(entities[i]), i); - ASSERT_EQ(registry.get(entities[i]), char('a'+i)); - } -} - -TEST(Registry, CreateManyEntitiesWithComponentsAtOnceWithListener) { - entt::registry registry; - entt::entity entities[3]; - listener listener; - - registry.on_construct().connect<&listener::incr>(listener); - registry.create(std::begin(entities), std::end(entities)); - - ASSERT_EQ(listener.counter, 3); - - registry.on_construct().disconnect<&listener::incr>(listener); - registry.on_construct().connect<&listener::incr>(listener); - registry.create(std::begin(entities), std::end(entities)); - - ASSERT_EQ(listener.counter, 6); -} - -TEST(Registry, CreateWithHint) { - entt::registry registry; - auto e3 = registry.create(entt::entity{3}); - auto e2 = registry.create(entt::entity{3}); - - ASSERT_EQ(e2, entt::entity{2}); - ASSERT_FALSE(registry.valid(entt::entity{1})); - ASSERT_EQ(e3, entt::entity{3}); - - registry.destroy(e2); - - ASSERT_EQ(registry.version(e2), 0); - ASSERT_EQ(registry.current(e2), 1); - - e2 = registry.create(); - auto e1 = registry.create(entt::entity{2}); - - ASSERT_EQ(registry.entity(e2), entt::entity{2}); - ASSERT_EQ(registry.version(e2), 1); - - ASSERT_EQ(registry.entity(e1), entt::entity{1}); - ASSERT_EQ(registry.version(e1), 0); - - registry.destroy(e1); - registry.destroy(e2); - auto e0 = std::get<0>(registry.create(entt::entity{0})); - - ASSERT_EQ(e0, entt::entity{0}); - ASSERT_EQ(registry.version(e0), 0); - ASSERT_TRUE(registry.has(e0)); - ASSERT_FALSE(registry.has(e0)); -} - TEST(Registry, NonOwningGroupInterleaved) { entt::registry registry; typename entt::entity entity = entt::null; diff --git a/test/entt/entity/view.cpp b/test/entt/entity/view.cpp index ca626e4d5..1fe93b58d 100644 --- a/test/entt/entity/view.cpp +++ b/test/entt/entity/view.cpp @@ -192,8 +192,14 @@ TEST(SingleComponentView, Find) { TEST(SingleComponentView, Less) { entt::registry registry; - const auto entity = std::get<0>(registry.create>()); - registry.create(); + auto create = [&](auto... component) { + const auto entity = registry.create(); + (registry.assign(entity, component), ...); + return entity; + }; + + const auto entity = create(0, entt::tag<"empty"_hs>{}); + create('c'); registry.view>().less([entity](const auto entt) { ASSERT_EQ(entity, entt); @@ -526,8 +532,16 @@ TEST(MultiComponentView, ExcludedComponents) { TEST(MultiComponentView, Less) { entt::registry registry; - const auto entity = std::get<0>(registry.create>()); - registry.create(); + + const auto entity = registry.create(); + registry.assign(entity); + registry.assign(entity); + registry.assign(entity); + registry.assign>(entity); + + const auto other = registry.create(); + registry.assign(other); + registry.assign(other); registry.view>().less([entity](const auto entt, int, char) { ASSERT_EQ(entity, entt);