sparse_set: added ::emplace_back

This commit is contained in:
Michele Caini
2021-06-29 12:37:39 +02:00
parent d3df64ef4b
commit e4fb293b55
2 changed files with 71 additions and 14 deletions

View File

@@ -555,6 +555,29 @@ public:
return packed[pos];
}
/**
* @brief Appends an entity to a sparse set.
*
* @warning
* Attempting to assign an entity that already belongs to the sparse set
* results in undefined behavior.
*
* @param entt A valid entity identifier.
* @return The slot used for insertion.
*/
size_type emplace_back(const entity_type entt) {
ENTT_ASSERT(!contains(entt), "Set already contains entity");
if(count == reserved) {
const size_type sz = static_cast<size_type>(reserved * growth_factor);
resize_packed(sz + !(sz > reserved));
}
assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(count));
packed[count] = entt;
return count++;
}
/**
* @brief Assigns an entity to a sparse set.
*
@@ -566,22 +589,11 @@ public:
* @return The slot used for insertion.
*/
size_type emplace(const entity_type entt) {
ENTT_ASSERT(!contains(entt), "Set already contains entity");
if(free_list == null) {
if(count == reserved) {
const size_type sz = static_cast<size_type>(reserved * growth_factor);
resize_packed(sz + !(sz > reserved));
}
assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(count));
packed[count] = entt;
return count++;
return emplace_back(entt);
} else {
ENTT_ASSERT(!contains(entt), "Set already contains entity");
const auto pos = size_type{traits_type::to_entity(free_list)};
move_and_pop(count, pos);
// TODO no guarantees
sparse[page(entt)][offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(pos));
free_list = std::exchange(packed[pos], entt);
return pos;

View File

@@ -175,8 +175,42 @@ TEST(SparseSet, Pagination) {
ASSERT_EQ(set.extent(), 2 * ENTT_SPARSE_PAGE);
}
TEST(SparseSet, Emplace) {
entt::sparse_set set{entt::deletion_policy::in_place};
entt::entity entities[2u];
entities[0u] = entt::entity{3};
entities[1u] = entt::entity{42};
ASSERT_TRUE(set.empty());
set.emplace(entities[0u]);
set.erase(entities[0u]);
set.emplace_back(entities[0u]);
set.emplace(entities[1u]);
ASSERT_DEATH(set.emplace_back(entities[1u]), "");
ASSERT_DEATH(set.emplace(entities[0u]), "");
ASSERT_EQ(set.at(0u), entities[1u]);
ASSERT_EQ(set.at(1u), entities[0u]);
ASSERT_EQ(set.index(entities[0u]), 1u);
ASSERT_EQ(set.index(entities[1u]), 0u);
set.erase(std::begin(entities), std::end(entities));
set.emplace(entities[1u]);
set.emplace_back(entities[0u]);
ASSERT_EQ(set.at(0u), entities[1u]);
ASSERT_EQ(set.at(1u), static_cast<entt::entity>(entt::null));
ASSERT_EQ(set.at(2u), entities[0u]);
ASSERT_EQ(set.index(entities[0u]), 2u);
ASSERT_EQ(set.index(entities[1u]), 0u);
}
TEST(SparseSet, Insert) {
entt::sparse_set set;
entt::sparse_set set{entt::deletion_policy::in_place};
entt::entity entities[2u];
entities[0u] = entt::entity{3};
@@ -204,6 +238,17 @@ TEST(SparseSet, Insert) {
ASSERT_EQ(set.data()[set.index(entities[0u])], entities[0u]);
ASSERT_EQ(set.data()[set.index(entities[1u])], entities[1u]);
ASSERT_EQ(set.data()[set.index(entt::entity{24})], entt::entity{24});
set.erase(std::begin(entities), std::end(entities));
set.insert(std::rbegin(entities), std::rend(entities));
ASSERT_EQ(set.size(), 6u);
ASSERT_TRUE(set.at(1u) == entt::tombstone);
ASSERT_TRUE(set.at(2u) == entt::tombstone);
ASSERT_EQ(set.at(4u), entities[1u]);
ASSERT_EQ(set.at(5u), entities[0u]);
ASSERT_EQ(set.index(entities[0u]), 5u);
ASSERT_EQ(set.index(entities[1u]), 4u);
}
TEST(SparseSet, Erase) {