storage: fix cross range-erase can break when using built-in iterators (close #914)
This commit is contained in:
@@ -333,9 +333,11 @@ protected:
|
||||
*/
|
||||
void swap_and_pop(typename underlying_type::basic_iterator first, typename underlying_type::basic_iterator last) override {
|
||||
for(; first != last; ++first) {
|
||||
// cannot use first::index() because it would break with cross iterators
|
||||
const auto pos = index(*first);
|
||||
auto &elem = element_at(base_type::size() - 1u);
|
||||
// destroying on exit allows reentrant destructors
|
||||
[[maybe_unused]] auto unused = std::exchange(element_at(static_cast<size_type>(first.index())), std::move(elem));
|
||||
[[maybe_unused]] auto unused = std::exchange(element_at(pos), std::move(elem));
|
||||
std::destroy_at(std::addressof(elem));
|
||||
base_type::swap_and_pop(first, first + 1u);
|
||||
}
|
||||
@@ -348,8 +350,10 @@ protected:
|
||||
*/
|
||||
void in_place_pop(typename underlying_type::basic_iterator first, typename underlying_type::basic_iterator last) override {
|
||||
for(; first != last; ++first) {
|
||||
// cannot use first::index() because it would break with cross iterators
|
||||
const auto pos = index(*first);
|
||||
base_type::in_place_pop(first, first + 1u);
|
||||
std::destroy_at(std::addressof(element_at(static_cast<size_type>(first.index()))));
|
||||
std::destroy_at(std::addressof(element_at(pos)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -345,6 +345,21 @@ TEST(Storage, Erase) {
|
||||
ASSERT_EQ(*pool.begin(), 1);
|
||||
}
|
||||
|
||||
TEST(Storage, CrossErase) {
|
||||
entt::sparse_set set;
|
||||
entt::storage<int> pool;
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
|
||||
pool.emplace(entities[0u], 3);
|
||||
pool.emplace(entities[1u], 42);
|
||||
set.emplace(entities[1u]);
|
||||
pool.erase(set.begin(), set.end());
|
||||
|
||||
ASSERT_TRUE(pool.contains(entities[0u]));
|
||||
ASSERT_FALSE(pool.contains(entities[1u]));
|
||||
ASSERT_EQ(pool.raw()[0u][0u], 3);
|
||||
}
|
||||
|
||||
TEST(Storage, StableErase) {
|
||||
entt::storage<stable_type> pool;
|
||||
entt::entity entities[3u]{entt::entity{3}, entt::entity{42}, entt::entity{9}};
|
||||
@@ -439,6 +454,21 @@ TEST(Storage, StableErase) {
|
||||
ASSERT_EQ(pool.get(entities[2u]).value, 1);
|
||||
}
|
||||
|
||||
TEST(Storage, CrossStableErase) {
|
||||
entt::sparse_set set;
|
||||
entt::storage<stable_type> pool;
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
|
||||
pool.emplace(entities[0u], 3);
|
||||
pool.emplace(entities[1u], 42);
|
||||
set.emplace(entities[1u]);
|
||||
pool.erase(set.begin(), set.end());
|
||||
|
||||
ASSERT_TRUE(pool.contains(entities[0u]));
|
||||
ASSERT_FALSE(pool.contains(entities[1u]));
|
||||
ASSERT_EQ(pool.raw()[0u][0u].value, 3);
|
||||
}
|
||||
|
||||
TEST(Storage, Remove) {
|
||||
entt::storage<int> pool;
|
||||
entt::entity entities[3u]{entt::entity{3}, entt::entity{42}, entt::entity{9}};
|
||||
@@ -473,6 +503,21 @@ TEST(Storage, Remove) {
|
||||
ASSERT_EQ(*pool.begin(), 1);
|
||||
}
|
||||
|
||||
TEST(Storage, CrossRemove) {
|
||||
entt::sparse_set set;
|
||||
entt::storage<int> pool;
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
|
||||
pool.emplace(entities[0u], 3);
|
||||
pool.emplace(entities[1u], 42);
|
||||
set.emplace(entities[1u]);
|
||||
pool.remove(set.begin(), set.end());
|
||||
|
||||
ASSERT_TRUE(pool.contains(entities[0u]));
|
||||
ASSERT_FALSE(pool.contains(entities[1u]));
|
||||
ASSERT_EQ(pool.raw()[0u][0u], 3);
|
||||
}
|
||||
|
||||
TEST(Storage, StableRemove) {
|
||||
entt::storage<stable_type> pool;
|
||||
entt::entity entities[3u]{entt::entity{3}, entt::entity{42}, entt::entity{9}};
|
||||
@@ -570,6 +615,21 @@ TEST(Storage, StableRemove) {
|
||||
ASSERT_EQ(pool.get(entities[2u]).value, 1);
|
||||
}
|
||||
|
||||
TEST(Storage, CrossStableRemove) {
|
||||
entt::sparse_set set;
|
||||
entt::storage<stable_type> pool;
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
|
||||
pool.emplace(entities[0u], 3);
|
||||
pool.emplace(entities[1u], 42);
|
||||
set.emplace(entities[1u]);
|
||||
pool.remove(set.begin(), set.end());
|
||||
|
||||
ASSERT_TRUE(pool.contains(entities[0u]));
|
||||
ASSERT_FALSE(pool.contains(entities[1u]));
|
||||
ASSERT_EQ(pool.raw()[0u][0u].value, 3);
|
||||
}
|
||||
|
||||
TEST(Storage, TypeFromBase) {
|
||||
entt::storage<int> pool;
|
||||
entt::sparse_set &base = pool;
|
||||
|
||||
Reference in New Issue
Block a user