diff --git a/src/entt/entity/fwd.hpp b/src/entt/entity/fwd.hpp index 0b054683b6..771cd13f8e 100644 --- a/src/entt/entity/fwd.hpp +++ b/src/entt/entity/fwd.hpp @@ -17,7 +17,9 @@ enum class deletion_policy : std::uint8_t { /*! @brief Swap-and-pop deletion policy. */ swap_and_pop = 0u, /*! @brief In-place deletion policy. */ - in_place = 1u + in_place = 1u, + /*! @brief Swap-only deletion policy. */ + swap_only = 2u }; template> diff --git a/src/entt/entity/sparse_set.hpp b/src/entt/entity/sparse_set.hpp index e8d818728f..3d17e58f08 100644 --- a/src/entt/entity/sparse_set.hpp +++ b/src/entt/entity/sparse_set.hpp @@ -288,6 +288,9 @@ class basic_sparse_set { in_place_pop(first); } break; + case deletion_policy::swap_only: + // no-op + break; } } diff --git a/src/entt/entity/storage.hpp b/src/entt/entity/storage.hpp index 25a56ca8ea..074ffe7bee 100644 --- a/src/entt/entity/storage.hpp +++ b/src/entt/entity/storage.hpp @@ -1035,7 +1035,7 @@ class basic_storage * @param allocator The allocator to use. */ explicit basic_storage(const allocator_type &allocator) - : base_type{type_id(), deletion_policy::swap_and_pop, allocator}, + : base_type{type_id(), deletion_policy::swap_only, allocator}, length{} {} /** diff --git a/test/entt/entity/sparse_set.cpp b/test/entt/entity/sparse_set.cpp index ca3d8f98dc..38066e1fff 100644 --- a/test/entt/entity/sparse_set.cpp +++ b/test/entt/entity/sparse_set.cpp @@ -595,6 +595,56 @@ TEST(SparseSet, CrossStableErase) { ASSERT_EQ(set.data()[0u], entity[0u]); } +TEST(SparseSet, SwapOnlyErase) { + using traits_type = entt::entt_traits; + + entt::sparse_set set{entt::deletion_policy::swap_only}; + entt::entity entity[3u]{entt::entity{3}, entt::entity{42}, traits_type::construct(9, 3)}; + + ASSERT_EQ(set.policy(), entt::deletion_policy::swap_only); + ASSERT_TRUE(set.empty()); + + set.push(std::begin(entity), std::end(entity)); + set.erase(set.begin(), set.end()); + + ASSERT_FALSE(set.empty()); + ASSERT_EQ(set.size(), 3u); + + set.erase(entity[2u]); + + ASSERT_FALSE(set.empty()); + ASSERT_EQ(set.size(), 3u); + + ASSERT_EQ(set.at(0u), entity[0u]); + ASSERT_EQ(set.at(1u), entity[1u]); + ASSERT_EQ(set.at(2u), entity[2u]); +} + +ENTT_DEBUG_TEST(SparseSetDeathTest, SwapOnlyErase) { + using traits_type = entt::entt_traits; + + entt::sparse_set set{entt::deletion_policy::swap_only}; + entt::entity entity[2u]{entt::entity{42}, traits_type::construct(9, 3)}; + + ASSERT_DEATH(set.erase(std::begin(entity), std::end(entity)), ""); + ASSERT_DEATH(set.erase(entt::null), ""); +} + +TEST(SparseSet, CrossSwapOnlyErase) { + entt::sparse_set set{entt::deletion_policy::swap_only}; + entt::sparse_set other{entt::deletion_policy::swap_only}; + entt::entity entity[2u]{entt::entity{3}, entt::entity{42}}; + + set.push(std::begin(entity), std::end(entity)); + other.push(entity[1u]); + set.erase(other.begin(), other.end()); + + ASSERT_TRUE(set.contains(entity[0u])); + ASSERT_TRUE(set.contains(entity[1u])); + ASSERT_EQ(set.data()[0u], entity[0u]); + ASSERT_EQ(set.data()[1u], entity[1u]); +} + TEST(SparseSet, Remove) { using traits_type = entt::entt_traits; @@ -810,6 +860,52 @@ TEST(SparseSet, CrossStableRemove) { ASSERT_EQ(set.data()[0u], entity[0u]); } +TEST(SparseSet, SwapOnlyRemove) { + using traits_type = entt::entt_traits; + + entt::sparse_set set{entt::deletion_policy::swap_only}; + entt::entity entity[3u]{entt::entity{3}, entt::entity{42}, traits_type::construct(9, 3)}; + + ASSERT_EQ(set.policy(), entt::deletion_policy::swap_only); + ASSERT_TRUE(set.empty()); + + ASSERT_EQ(set.remove(std::begin(entity), std::end(entity)), 0u); + ASSERT_FALSE(set.remove(entity[1u])); + + ASSERT_TRUE(set.empty()); + + set.push(std::begin(entity), std::end(entity)); + + ASSERT_EQ(set.remove(set.begin(), set.end()), 3u); + ASSERT_EQ(set.remove(set.begin(), set.end()), 3u); + ASSERT_FALSE(set.empty()); + ASSERT_EQ(set.size(), 3u); + + ASSERT_TRUE(set.remove(entity[2u])); + ASSERT_TRUE(set.remove(entity[2u])); + ASSERT_FALSE(set.empty()); + ASSERT_EQ(set.size(), 3u); + + ASSERT_EQ(set.at(0u), entity[0u]); + ASSERT_EQ(set.at(1u), entity[1u]); + ASSERT_EQ(set.at(2u), entity[2u]); +} + +TEST(SparseSet, CrossSwapOnlyRemove) { + entt::sparse_set set{entt::deletion_policy::swap_only}; + entt::sparse_set other{entt::deletion_policy::swap_only}; + entt::entity entity[2u]{entt::entity{3}, entt::entity{42}}; + + set.push(std::begin(entity), std::end(entity)); + other.push(entity[1u]); + set.remove(other.begin(), other.end()); + + ASSERT_TRUE(set.contains(entity[0u])); + ASSERT_TRUE(set.contains(entity[1u])); + ASSERT_EQ(set.data()[0u], entity[0u]); + ASSERT_EQ(set.data()[1u], entity[1u]); +} + TEST(SparseSet, Compact) { entt::sparse_set set{entt::deletion_policy::in_place}; diff --git a/test/entt/entity/storage_entity.cpp b/test/entt/entity/storage_entity.cpp index d7ced8077f..7cc057b119 100644 --- a/test/entt/entity/storage_entity.cpp +++ b/test/entt/entity/storage_entity.cpp @@ -9,7 +9,7 @@ TEST(StorageEntity, TypeAndPolicy) { entt::storage pool; ASSERT_EQ(pool.type(), entt::type_id()); - ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_and_pop); + ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_only); } TEST(StorageEntity, Functionalities) {