Skip to content

Commit

Permalink
storage: emplace/insert -> generate, for storage entity
Browse files Browse the repository at this point in the history
  • Loading branch information
skypjack committed Jan 20, 2025
1 parent fae3345 commit 15c3ac2
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 103 deletions.
3 changes: 2 additions & 1 deletion TODO
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ TODO:
- get/reset placeholder to position after saving/loading (avoid long lookup)
- allow skipping/reserving entity identifiers
- documentation for reserved entities
* storage entity: no emplace/insert, rename and add a fast range-push from above
* storage entity: fast range-push from above
* table: pop back to support swap and pop, single column access, empty type optimization
* checkout tools workflow
* entity based component_traits
Expand All @@ -38,3 +38,4 @@ TODO:
* sparse_set shrink_to_fit argument for sparse array shrink policy (none, empty, deep, whatever)
* any cdynamic to support const ownership construction
* return meta context from meta objects
* review sigh_mixin::insert, maybe bugged (ie with pointer stability enabled)
83 changes: 45 additions & 38 deletions src/entt/entity/mixin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,48 +294,59 @@ class basic_sigh_mixin final: public Type {
}

/**
* @brief Emplace elements into a storage.
*
* The behavior of this operation depends on the underlying storage type
* (for example, components vs entities).<br/>
* Refer to the specific documentation for more details.
*
* @return Whatever the underlying storage returns.
* @brief Creates a new identifier or recycles a destroyed one.
* @return A valid identifier.
*/
auto emplace() {
const auto entt = underlying_type::emplace();
auto generate() {
const auto entt = underlying_type::generate();
construction.publish(owner_or_assert(), entt);
return entt;
}

/**
* @brief Emplace elements into a storage.
*
* The behavior of this operation depends on the underlying storage type
* (for example, components vs entities).<br/>
* Refer to the specific documentation for more details.
*
* @brief Creates a new identifier or recycles a destroyed one.
* @param hint Required identifier.
* @return A valid identifier.
*/
entity_type generate(const entity_type hint) {
const auto entt = underlying_type::generate(hint);
construction.publish(owner_or_assert(), entt);
return entt;
}

/**
* @brief Assigns each element in a range an identifier.
* @tparam It Type of mutable 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.
*/
template<typename It>
void generate(It first, It last) {
underlying_type::generate(first, last);

if(auto &reg = owner_or_assert(); !construction.empty()) {
for(; first != last; ++first) {
construction.publish(reg, *first);
}
}
}

/**
* @brief Assigns an entity to a storage and constructs its object.
* @tparam Args Types of arguments to forward to the underlying storage.
* @param hint A valid identifier.
* @param entt A valid identifier.
* @param args Parameters to forward to the underlying storage.
* @return Whatever the underlying storage returns.
* @return A reference to the newly created object.
*/
template<typename... Args>
std::conditional_t<std::is_same_v<typename underlying_type::element_type, entity_type>, entity_type, decltype(std::declval<underlying_type>().get({}))>
emplace(const entity_type hint, Args &&...args) {
if constexpr(std::is_same_v<typename underlying_type::element_type, entity_type>) {
const auto entt = underlying_type::emplace(hint, std::forward<Args>(args)...);
construction.publish(owner_or_assert(), entt);
return entt;
} else {
underlying_type::emplace(hint, std::forward<Args>(args)...);
construction.publish(owner_or_assert(), hint);
return this->get(hint);
}
decltype(auto) emplace(const entity_type entt, Args &&...args) {
underlying_type::emplace(entt, std::forward<Args>(args)...);
construction.publish(owner_or_assert(), entt);
return this->get(entt);
}

/**
* @brief Patches the given instance for an entity.
* @brief Updates the instance assigned to a given entity in-place.
* @tparam Func Types of the function objects to invoke.
* @param entt A valid identifier.
* @param func Valid function objects.
Expand All @@ -349,16 +360,12 @@ class basic_sigh_mixin final: public Type {
}

/**
* @brief Emplace elements into a storage.
*
* The behavior of this operation depends on the underlying storage type
* (for example, components vs entities).<br/>
* Refer to the specific documentation for more details.
*
* @tparam It Iterator type (as required by the underlying storage type).
* @brief Assigns one or more entities to a storage and constructs their
* objects from a given instance.
* @tparam It Type of input iterator.
* @tparam Args Types of arguments to forward to the underlying storage.
* @param first An iterator to the first element of the range.
* @param last An iterator past the last element of the range.
* @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 forward to the underlying storage.
*/
template<typename It, typename... Args>
Expand Down
6 changes: 3 additions & 3 deletions src/entt/entity/registry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ class basic_registry {
* @return A valid identifier.
*/
[[nodiscard]] entity_type create() {
return entities.emplace();
return entities.generate();
}

/**
Expand All @@ -510,7 +510,7 @@ class basic_registry {
* @return A valid identifier.
*/
[[nodiscard]] entity_type create(const entity_type hint) {
return entities.emplace(hint);
return entities.generate(hint);
}

/**
Expand All @@ -524,7 +524,7 @@ class basic_registry {
*/
template<typename It>
void create(It first, It last) {
entities.insert(std::move(first), std::move(last));
entities.generate(std::move(first), std::move(last));
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/entt/entity/snapshot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ class basic_snapshot_loader {

for(entity_type entity = null; length; --length) {
archive(entity);
storage.emplace(entity);
storage.generate(entity);
}

storage.free_list(count);
Expand All @@ -247,7 +247,7 @@ class basic_snapshot_loader {

while(length--) {
if(archive(entt); entt != null) {
const auto entity = other.contains(entt) ? entt : other.emplace(entt);
const auto entity = other.contains(entt) ? entt : other.generate(entt);
ENTT_ASSERT(entity == entt, "Entity not available for use");

if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
Expand Down
56 changes: 44 additions & 12 deletions src/entt/entity/storage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ class basic_storage<Entity, Entity, Allocator>
* @return Iterator pointing to the emplaced element.
*/
underlying_iterator try_emplace(const Entity hint, const bool, const void *) override {
return base_type::find(emplace(hint));
return base_type::find(generate(hint));
}

public:
Expand Down Expand Up @@ -1113,7 +1113,7 @@ class basic_storage<Entity, Entity, Allocator>
* @brief Creates a new identifier or recycles a destroyed one.
* @return A valid identifier.
*/
entity_type emplace() {
entity_type generate() {
const auto len = base_type::free_list();
const auto entt = (len == base_type::size()) ? next() : base_type::data()[len];
return *base_type::try_emplace(entt, true);
Expand All @@ -1128,14 +1128,52 @@ class basic_storage<Entity, Entity, Allocator>
* @param hint Required identifier.
* @return A valid identifier.
*/
entity_type emplace(const entity_type hint) {
entity_type generate(const entity_type hint) {
if(hint != null && hint != tombstone) {
if(const auto curr = traits_type::construct(traits_type::to_entity(hint), base_type::current(hint)); curr == tombstone || !(base_type::index(curr) < base_type::free_list())) {
return *base_type::try_emplace(hint, true);
}
}

return emplace();
return generate();
}

/**
* @brief Assigns each element in a range an identifier.
* @tparam It Type of mutable 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.
*/
template<typename It>
void generate(It first, It last) {
for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first) {
*first = *base_type::try_emplace(base_type::data()[base_type::free_list()], true);
}

for(; first != last; ++first) {
*first = *base_type::try_emplace(next(), true);
}
}

/**
* @brief Creates a new identifier or recycles a destroyed one.
* @return A valid identifier.
*/
[[deprecated("use ::generate() instead")]] entity_type emplace() {
return generate();
}

/**
* @brief Creates a new identifier or recycles a destroyed one.
*
* If the requested identifier isn't in use, the suggested one is used.
* Otherwise, a new identifier is returned.
*
* @param hint Required identifier.
* @return A valid identifier.
*/
[[deprecated("use ::generate(hint) instead")]] entity_type emplace(const entity_type hint) {
return generate(hint);
}

/**
Expand All @@ -1157,14 +1195,8 @@ class basic_storage<Entity, Entity, Allocator>
* @param last An iterator past the last element of the range to generate.
*/
template<typename It>
void insert(It first, It last) {
for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first) {
*first = *base_type::try_emplace(base_type::data()[base_type::free_list()], true);
}

for(; first != last; ++first) {
*first = *base_type::try_emplace(next(), true);
}
[[deprecated("use ::generate(first, last) instead")]] void insert(It first, It last) {
generate(std::move(first), std::move(last));
}

/**
Expand Down
6 changes: 3 additions & 3 deletions test/entt/entity/sigh_mixin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,11 @@ TEST(SighMixin, StorageEntity) {
ASSERT_EQ(on_construct, 3u);
ASSERT_EQ(on_destroy, 3u);

pool.emplace();
pool.emplace(entt::entity{0});
pool.generate();
pool.generate(entt::entity{0});

std::array<entt::entity, 1u> entity{};
pool.insert(entity.begin(), entity.end());
pool.generate(entity.begin(), entity.end());

ASSERT_EQ(on_construct, 6u);
ASSERT_EQ(on_destroy, 3u);
Expand Down
Loading

0 comments on commit 15c3ac2

Please sign in to comment.