batch creation returns iterators and no longer raw pointers

This commit is contained in:
Michele Caini
2019-08-21 17:36:56 +02:00
parent 57f8d90e38
commit ece4480200
7 changed files with 53 additions and 43 deletions

2
TODO
View File

@@ -28,3 +28,5 @@ TODO
* make meta work across boundaries
- inline variables are fine here, only the head represents a problem
- we should always resolve by looking into the list of types when working across boundaries, no direct resolve
* review stomp signature: first, last, other, from <-- the registry "acquires" the other entity
* create from prototype (literally a stomp with batch creation)

View File

@@ -86,28 +86,16 @@ class basic_registry {
}
template<typename It>
Component * batch(basic_registry &registry, It first, It last) {
Component *component = nullptr;
auto batch(basic_registry &registry, It first, It last) {
auto it = storage<Entity, Component>::batch(first, last);
if constexpr(std::is_empty_v<Component>) {
storage<Entity, Component>::batch(first, last);
if(!construction.empty()) {
std::for_each(first, last, [this, &registry](const auto entt) {
construction.publish(entt, registry, Component{});
});
}
} else {
component = storage<Entity, Component>::batch(first, last);
if(!construction.empty()) {
std::for_each(first, last, [this, &registry, component](const auto entt) mutable {
construction.publish(entt, registry, *(component++));
});
}
if(!construction.empty()) {
std::for_each(first, last, [this, &registry, it](const auto entt) mutable {
construction.publish(entt, registry, *(it++));
});
}
return component;
return it;
}
void remove(basic_registry &registry, const Entity entt) {
@@ -599,7 +587,7 @@ public:
* @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 pointers to the arrays of components just created and
* containing the iterators to the lists of components just created and
* sorted the same of the entities otherwise.
*/
template<typename... Component, typename It>

View File

@@ -318,7 +318,8 @@ public:
* `end()`.
*
* @note
* Input iterators stay true to the order imposed by a call to `respect`.
* Random access iterators stay true to the order imposed by a call to
* `respect`.
*
* @return An iterator to the first entity of the internal packed array.
*/
@@ -335,7 +336,8 @@ public:
* iterator results in undefined behavior.
*
* @note
* Input iterators stay true to the order imposed by a call to `respect`.
* Random access iterators stay true to the order imposed by a call to
* `respect`.
*
* @return An iterator to the element following the last entity of the
* internal packed array.
@@ -417,7 +419,7 @@ public:
*/
template<typename It>
void batch(It first, It last) {
std::for_each(first, last, [this, next = direct.size()](const auto entt) mutable {
std::for_each(std::make_reverse_iterator(last), std::make_reverse_iterator(first), [this, next = direct.size()](const auto entt) mutable {
ENTT_ASSERT(!has(entt));
auto [page, offset] = index(entt);
assure(page);

View File

@@ -28,7 +28,8 @@ namespace entt {
*
* @note
* Entities and objects have the same order. It's guaranteed both in case of raw
* access (either to entities or objects) and when using input iterators.
* access (either to entities or objects) and when using random or input access
* iterators.
*
* @note
* Internal data structures arrange elements to maximize performance. Because of
@@ -215,8 +216,8 @@ public:
* the storage is empty, the returned iterator will be equal to `end()`.
*
* @note
* Input iterators stay true to the order imposed by a call to either `sort`
* or `respect`.
* Random access iterators stay true to the order imposed by a call to
* either `sort` or `respect`.
*
* @return An iterator to the first instance of the given type.
*/
@@ -244,8 +245,8 @@ public:
* results in undefined behavior.
*
* @note
* Input iterators stay true to the order imposed by a call to either `sort`
* or `respect`.
* Random access iterators stay true to the order imposed by a call to
* either `sort` or `respect`.
*
* @return An iterator to the element following the last instance of the
* given type.
@@ -345,16 +346,16 @@ public:
* @tparam It Type of forward iterator.
* @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.
* @return A pointer to the array of instances just created and sorted the
* @return An iterator to the list of instances just created and sorted the
* same of the entities.
*/
template<typename It>
object_type * batch(It first, It last) {
iterator_type batch(It first, It last) {
const auto length = last - first;
instances.resize(instances.size() + length);
// entity goes after component in case constructor throws
underlying_type::batch(first, last);
return instances.data() + instances.size() - length;
return begin();
}
/**
@@ -645,6 +646,27 @@ public:
ENTT_ASSERT(underlying_type::has(entt));
return {};
}
/**
* @brief Assigns one or more entities to a storage.
*
* @warning
* Attempting to assign an entity that already belongs to the storage
* results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* storage already contains the given entity.
*
* @tparam It Type of forward iterator.
* @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.
* @return An iterator to the list of instances just created and sorted the
* same of the entities.
*/
template<typename It>
iterator_type batch(It first, It last) {
underlying_type::batch(first, last);
return begin();
}
};
/*! @copydoc basic_storage */

View File

@@ -1138,10 +1138,6 @@ TEST(Registry, CreateManyEntitiesWithComponentsAtOnce) {
ASSERT_FALSE(registry.empty<char>());
ASSERT_FALSE(registry.empty<empty_type>());
ASSERT_NE(iptr, nullptr);
ASSERT_NE(cptr, nullptr);
ASSERT_EQ(eptr, nullptr);
ASSERT_EQ(registry.size<int>(), entt::registry::size_type{3});
ASSERT_EQ(registry.size<char>(), entt::registry::size_type{3});
ASSERT_EQ(registry.size<empty_type>(), entt::registry::size_type{3});

View File

@@ -116,7 +116,7 @@ TEST(SparseSet, Pagination) {
TEST(SparseSet, BatchAdd) {
entt::sparse_set<entt::entity> set;
entt::sparse_set<entt::entity>::entity_type entities[2];
entt::entity entities[2];
entities[0] = entt::entity{3};
entities[1] = entt::entity{42};
@@ -135,8 +135,8 @@ TEST(SparseSet, BatchAdd) {
ASSERT_FALSE(set.empty());
ASSERT_EQ(set.size(), 4u);
ASSERT_EQ(set.get(entt::entity{12}), 0u);
ASSERT_EQ(set.get(entities[0]), 1u);
ASSERT_EQ(set.get(entities[1]), 2u);
ASSERT_EQ(set.get(entities[0]), 2u);
ASSERT_EQ(set.get(entities[1]), 1u);
ASSERT_EQ(set.get(entt::entity{24}), 3u);
}

View File

@@ -96,14 +96,14 @@ TEST(Storage, EmptyType) {
TEST(Storage, BatchAdd) {
entt::storage<entt::entity, int> pool;
entt::storage<entt::entity, int>::entity_type entities[2];
entt::entity entities[2];
entities[0] = entt::entity{3};
entities[1] = entt::entity{42};
pool.reserve(4);
pool.construct(entt::entity{12}, 21);
auto *component = pool.batch(std::begin(entities), std::end(entities));
auto it = pool.batch(std::begin(entities), std::end(entities));
pool.construct(entt::entity{24}, 42);
ASSERT_TRUE(pool.has(entities[0]));
@@ -120,8 +120,8 @@ TEST(Storage, BatchAdd) {
ASSERT_EQ(pool.get(entities[1]), 0);
ASSERT_EQ(pool.get(entt::entity{24}), 42);
component[0] = 1;
component[1] = 2;
it[0] = 1;
it[1] = 2;
ASSERT_EQ(pool.get(entities[0]), 1);
ASSERT_EQ(pool.get(entities[1]), 2);
@@ -129,7 +129,7 @@ TEST(Storage, BatchAdd) {
TEST(Storage, BatchAddEmptyType) {
entt::storage<entt::entity, empty_type> pool;
entt::storage<entt::entity, empty_type>::entity_type entities[2];
entt::entity entities[2];
entities[0] = entt::entity{3};
entities[1] = entt::entity{42};