sparse_set: fix cross range-erase can break when using built-in iterators (close #913)
This commit is contained in:
@@ -240,12 +240,14 @@ protected:
|
||||
*/
|
||||
virtual void swap_and_pop(basic_iterator first, basic_iterator last) {
|
||||
for(; first != last; ++first) {
|
||||
sparse_ref(packed.back()) = entity_traits::combine(static_cast<typename entity_traits::entity_type>(first.index()), entity_traits::to_integral(packed.back()));
|
||||
const auto entt = std::exchange(packed[first.index()], packed.back());
|
||||
auto &self = sparse_ref(*first);
|
||||
const auto entt = entity_traits::to_entity(self);
|
||||
sparse_ref(packed.back()) = entity_traits::combine(entt, entity_traits::to_integral(packed.back()));
|
||||
packed[static_cast<size_type>(entt)] = packed.back();
|
||||
// unnecessary but it helps to detect nasty bugs
|
||||
ENTT_ASSERT((packed.back() = tombstone, true), "");
|
||||
// lazy self-assignment guard
|
||||
sparse_ref(entt) = null;
|
||||
self = null;
|
||||
packed.pop_back();
|
||||
}
|
||||
}
|
||||
@@ -257,8 +259,8 @@ protected:
|
||||
*/
|
||||
virtual void in_place_pop(basic_iterator first, basic_iterator last) {
|
||||
for(; first != last; ++first) {
|
||||
sparse_ref(*first) = null;
|
||||
packed[first.index()] = std::exchange(free_list, entity_traits::combine(static_cast<typename entity_traits::entity_type>(first.index()), entity_traits::reserved));
|
||||
const auto entt = entity_traits::to_entity(std::exchange(sparse_ref(*first), null));
|
||||
packed[static_cast<size_type>(entt)] = std::exchange(free_list, entity_traits::combine(entt, entity_traits::reserved));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -428,6 +428,22 @@ TEST(SparseSetDeathTest, Erase) {
|
||||
ASSERT_DEATH(set.erase(entt::null), "");
|
||||
}
|
||||
|
||||
TEST(SparseSet, CrossErase) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::sparse_set set;
|
||||
entt::sparse_set other;
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
|
||||
set.insert(std::begin(entities), std::end(entities));
|
||||
other.emplace(entities[1u]);
|
||||
set.erase(other.begin(), other.end());
|
||||
|
||||
ASSERT_TRUE(set.contains(entities[0u]));
|
||||
ASSERT_FALSE(set.contains(entities[1u]));
|
||||
ASSERT_EQ(set.data()[0u], entities[0u]);
|
||||
}
|
||||
|
||||
TEST(SparseSet, StableErase) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
@@ -552,6 +568,22 @@ TEST(SparseSetDeathTest, StableErase) {
|
||||
ASSERT_DEATH(set.erase(entt::null), "");
|
||||
}
|
||||
|
||||
TEST(SparseSet, CrossStableErase) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::sparse_set set{entt::deletion_policy::in_place};
|
||||
entt::sparse_set other{entt::deletion_policy::in_place};
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
|
||||
set.insert(std::begin(entities), std::end(entities));
|
||||
other.emplace(entities[1u]);
|
||||
set.erase(other.begin(), other.end());
|
||||
|
||||
ASSERT_TRUE(set.contains(entities[0u]));
|
||||
ASSERT_FALSE(set.contains(entities[1u]));
|
||||
ASSERT_EQ(set.data()[0u], entities[0u]);
|
||||
}
|
||||
|
||||
TEST(SparseSet, Remove) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
@@ -609,6 +641,22 @@ TEST(SparseSet, Remove) {
|
||||
ASSERT_EQ(set.remove(entt::null), 0u);
|
||||
}
|
||||
|
||||
TEST(SparseSet, CrossRemove) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::sparse_set set;
|
||||
entt::sparse_set other;
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
|
||||
set.insert(std::begin(entities), std::end(entities));
|
||||
other.emplace(entities[1u]);
|
||||
set.remove(other.begin(), other.end());
|
||||
|
||||
ASSERT_TRUE(set.contains(entities[0u]));
|
||||
ASSERT_FALSE(set.contains(entities[1u]));
|
||||
ASSERT_EQ(set.data()[0u], entities[0u]);
|
||||
}
|
||||
|
||||
TEST(SparseSet, StableRemove) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
@@ -739,6 +787,22 @@ TEST(SparseSet, StableRemove) {
|
||||
ASSERT_EQ(set.remove(entt::null), 0u);
|
||||
}
|
||||
|
||||
TEST(SparseSet, CrossStableRemove) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::sparse_set set{entt::deletion_policy::in_place};
|
||||
entt::sparse_set other{entt::deletion_policy::in_place};
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
|
||||
set.insert(std::begin(entities), std::end(entities));
|
||||
other.emplace(entities[1u]);
|
||||
set.remove(other.begin(), other.end());
|
||||
|
||||
ASSERT_TRUE(set.contains(entities[0u]));
|
||||
ASSERT_FALSE(set.contains(entities[1u]));
|
||||
ASSERT_EQ(set.data()[0u], entities[0u]);
|
||||
}
|
||||
|
||||
TEST(SparseSet, Compact) {
|
||||
entt::sparse_set set{entt::deletion_policy::in_place};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user