registry: create with hint (close #303)

This commit is contained in:
Michele Caini
2020-01-06 00:40:22 +01:00
parent dc2e44b2c0
commit d202bd3e50
2 changed files with 87 additions and 12 deletions

View File

@@ -68,7 +68,7 @@ class basic_registry {
template<typename... Args>
decltype(auto) assign(basic_registry &owner, const Entity entt, Args &&... args) {
decltype(auto) component = storage<Entity, Component>::construct(entt, std::forward<Args>(args)...);
decltype(auto) component = storage<entity_type, Component>::construct(entt, std::forward<Args>(args)...);
construction.publish(entt, owner, component);
return component;
}
@@ -76,7 +76,7 @@ class basic_registry {
template<typename It, typename... Args>
std::enable_if_t<std::is_same_v<typename std::iterator_traits<It>::value_type, Entity>, typename storage<Entity, Component>::reverse_iterator_type>
assign(basic_registry &owner, It first, It last, Args &&... args) {
auto it = storage<Entity, Component>::construct(first, last, std::forward<Args>(args)...);
auto it = storage<entity_type, Component>::construct(first, last, std::forward<Args>(args)...);
const auto end = it + (!construction.empty() * std::distance(first, last));
std::for_each(it, end, [this, &owner, &first](decltype(*it) component) {
@@ -88,14 +88,14 @@ class basic_registry {
void remove(basic_registry &owner, const Entity entt) {
destruction.publish(entt, owner);
storage<Entity, Component>::destroy(entt);
storage<entity_type, Component>::destroy(entt);
}
template<typename... Args>
decltype(auto) replace(basic_registry &owner, const Entity entt, Args &&... args) {
Component component{std::forward<Args>(args)...};
update.publish(entt, owner, component);
return (storage<Entity, Component>::get(entt) = std::move(component));
return (storage<entity_type, Component>::get(entt) = std::move(component));
}
private:
@@ -194,8 +194,7 @@ class basic_registry {
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 = entity_type{curr | version};
entities[curr] = entt;
entt = entities[curr] = entity_type{curr | version};
}
return entt;
@@ -205,9 +204,8 @@ class basic_registry {
// 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;
const auto node = to_integral(destroyed) | version;
entities[entt] = Entity{node};
destroyed = Entity{entt};
entities[entt] = entity_type{to_integral(destroyed) | version};
destroyed = entity_type{entt};
}
template<typename Component, typename... Args>
@@ -225,16 +223,16 @@ class basic_registry {
pdata.type_id = type_info<Component>::id();
pdata.pool = std::make_unique<pool_handler<Component>>(std::forward<Args>(args)...);
pdata.remove = [](sparse_set<Entity> &cpool, basic_registry &owner, const Entity entt) {
pdata.remove = [](sparse_set<entity_type> &cpool, basic_registry &owner, const entity_type entt) {
static_cast<pool_handler<Component> &>(cpool).remove(owner, entt);
};
if constexpr(std::is_copy_constructible_v<std::decay_t<Component>>) {
pdata.assure = [](basic_registry &other, const sparse_set<Entity> &cpool) {
pdata.assure = [](basic_registry &other, const sparse_set<entity_type> &cpool) {
other.assure<Component>(static_cast<const pool_handler<Component> &>(cpool));
};
pdata.stamp = [](basic_registry &other, const Entity dst, const sparse_set<Entity> &cpool, const Entity src) {
pdata.stamp = [](basic_registry &other, const entity_type dst, const sparse_set<entity_type> &cpool, const entity_type src) {
other.assign_or_replace<Component>(dst, static_cast<const pool_handler<Component> &>(cpool).get(src));
};
}
@@ -532,6 +530,50 @@ public:
}
}
/**
* @brief Creates a new entity and returns it.
*
* @sa create
*
* 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.
*/
template<typename... Component>
auto create(const entity_type hint) {
ENTT_ASSERT(hint != null);
entity_type entt;
if(const auto req = (to_integral(hint) & traits_type::entity_mask); !(req < entities.size())) {
entities.reserve(req + 1);
for(auto pos = entities.size(); pos < req; ++pos) {
entities.emplace_back(destroyed);
destroyed = entity_type(pos);
}
entt = entities.emplace_back(hint);
} else if(const auto curr = (to_integral(entities[req]) & traits_type::entity_mask); req == curr) {
entt = create();
} else {
auto *it = &destroyed;
for(; (to_integral(*it) & traits_type::entity_mask) != req; it = &entities[to_integral(*it) & traits_type::entity_mask]);
*it = entity_type{curr | (to_integral(*it) & (traits_type::version_mask << traits_type::entity_shift))};
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<Component>(entt)...));
}
}
/**
* @brief Destroys an entity and lets the registry recycle the identifier.
*

View File

@@ -1231,6 +1231,39 @@ TEST(Registry, CreateManyEntitiesWithComponentsAtOnceWithListener) {
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<int>(entt::entity{0}));
ASSERT_EQ(e0, entt::entity{0});
ASSERT_EQ(registry.version(e0), 0);
ASSERT_TRUE(registry.has<int>(e0));
ASSERT_FALSE(registry.has<char>(e0));
}
TEST(Registry, NonOwningGroupInterleaved) {
entt::registry registry;
typename entt::entity entity = entt::null;