Browse Source

sparse_set: swap-only mode for easy identification

Michele Caini 2 years ago
parent
commit
4f0a119279

+ 3 - 1
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<typename Entity = entity, typename = std::allocator<Entity>>

+ 3 - 0
src/entt/entity/sparse_set.hpp

@@ -288,6 +288,9 @@ protected:
                 in_place_pop(first);
             }
             break;
+        case deletion_policy::swap_only:
+            // no-op
+            break;
         }
     }
 

+ 1 - 1
src/entt/entity/storage.hpp

@@ -1035,7 +1035,7 @@ public:
      * @param allocator The allocator to use.
      */
     explicit basic_storage(const allocator_type &allocator)
-        : base_type{type_id<value_type>(), deletion_policy::swap_and_pop, allocator},
+        : base_type{type_id<value_type>(), deletion_policy::swap_only, allocator},
           length{} {}
 
     /**

+ 96 - 0
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::entity>;
+
+    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::entity>;
+
+    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<entt::entity>;
 
@@ -810,6 +860,52 @@ TEST(SparseSet, CrossStableRemove) {
     ASSERT_EQ(set.data()[0u], entity[0u]);
 }
 
+TEST(SparseSet, SwapOnlyRemove) {
+    using traits_type = entt::entt_traits<entt::entity>;
+
+    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};
 

+ 1 - 1
test/entt/entity/storage_entity.cpp

@@ -9,7 +9,7 @@ TEST(StorageEntity, TypeAndPolicy) {
     entt::storage<entt::entity> pool;
 
     ASSERT_EQ(pool.type(), entt::type_id<entt::entity>());
-    ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_and_pop);
+    ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_only);
 }
 
 TEST(StorageEntity, Functionalities) {