Browse Source

sparse_set: remove (and range-remove) if exists

Michele Caini 4 years ago
parent
commit
1cafbcff38
3 changed files with 142 additions and 19 deletions
  1. 25 0
      src/entt/entity/sparse_set.hpp
  2. 53 3
      test/entt/entity/sparse_set.cpp
  3. 64 16
      test/entt/entity/storage.cpp

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

@@ -492,6 +492,31 @@ public:
         }
     }
 
+    /**
+     * @brief Removes an entity from a sparse set if it exists.
+     * @param entt A valid entity identifier.
+     * @param ud Optional user data that are forwarded as-is to derived classes.
+     */
+    void remove(const entity_type entt, void *ud = nullptr) {
+        if(contains(entt)) {
+            erase(entt, ud);
+        }
+    }
+
+    /**
+     * @brief Removes multiple entities from a sparse set if they exist.
+     * @tparam It Type of input iterator.
+     * @param first An iterator to the first element of the range of entities.
+     * @param last An iterator past the last element of the range of entities.
+     * @param ud Optional user data that are forwarded as-is to derived classes.
+     */
+    template<typename It>
+    void remove(It first, It last, void *ud = nullptr) {
+        for(; first != last; ++first) {
+            remove(*first, ud);
+        }
+    }
+
     /**
      * @copybrief swap_at
      *

+ 53 - 3
test/entt/entity/sparse_set.cpp

@@ -157,8 +157,10 @@ TEST(SparseSet, Erase) {
     entities[1] = entt::entity{42};
     entities[2] = entt::entity{9};
 
-    set.insert(std::begin(entities), std::end(entities));
-    set.erase(set.begin(), set.end());
+    ASSERT_TRUE(set.empty());
+
+    ASSERT_DEATH(set.erase(std::begin(entities), std::end(entities)), "");
+    ASSERT_DEATH(set.erase(entities[1]), "");
 
     ASSERT_TRUE(set.empty());
 
@@ -173,7 +175,11 @@ TEST(SparseSet, Erase) {
     ASSERT_FALSE(set.empty());
     ASSERT_EQ(*set.begin(), entt::entity{9});
 
-    set.clear();
+    set.erase(entities[2]);
+
+    ASSERT_DEATH(set.erase(entities[2]), "");
+    ASSERT_TRUE(set.empty());
+
     set.insert(std::begin(entities), std::end(entities));
     std::swap(entities[1], entities[2]);
     set.erase(entities, entities + 2u);
@@ -182,6 +188,50 @@ TEST(SparseSet, Erase) {
     ASSERT_EQ(*set.begin(), entt::entity{42});
 }
 
+TEST(SparseSet, Remove) {
+    entt::sparse_set set;
+    entt::entity entities[3];
+
+    entities[0] = entt::entity{3};
+    entities[1] = entt::entity{42};
+    entities[2] = entt::entity{9};
+
+    ASSERT_TRUE(set.empty());
+
+    set.remove(std::begin(entities), std::end(entities));
+    set.remove(entities[1]);
+
+    ASSERT_TRUE(set.empty());
+
+    set.insert(std::begin(entities), std::end(entities));
+    set.remove(set.begin(), set.end());
+
+    ASSERT_TRUE(set.empty());
+
+    set.insert(std::begin(entities), std::end(entities));
+    set.remove(entities, entities + 2u);
+
+    ASSERT_FALSE(set.empty());
+    ASSERT_EQ(*set.begin(), entt::entity{9});
+
+    set.remove(entities[2]);
+    set.remove(entities[2]);
+
+    ASSERT_TRUE(set.empty());
+
+    set.insert(entities, entities + 2u);
+    set.remove(std::begin(entities), std::end(entities));
+
+    ASSERT_TRUE(set.empty());
+
+    set.insert(std::begin(entities), std::end(entities));
+    std::swap(entities[1], entities[2]);
+    set.remove(entities, entities + 2u);
+
+    ASSERT_FALSE(set.empty());
+    ASSERT_EQ(*set.begin(), entt::entity{42});
+}
+
 TEST(SparseSet, Clear) {
     entt::sparse_set set;
 

+ 64 - 16
test/entt/entity/storage.cpp

@@ -131,34 +131,82 @@ TEST(Storage, InsertEmptyType) {
     ASSERT_EQ(pool.size(), 2u);
 }
 
+TEST(Storage, Erase) {
+    entt::storage<int> pool;
+    entt::entity entities[3];
+
+    entities[0] = entt::entity{3};
+    entities[1] = entt::entity{42};
+    entities[2] = entt::entity{9};
+
+    pool.emplace(entities[0]);
+    pool.emplace(entities[1]);
+    pool.emplace(entities[2]);
+    pool.erase(std::begin(entities), std::end(entities));
+
+    ASSERT_DEATH(pool.erase(std::begin(entities), std::end(entities)), "");
+    ASSERT_TRUE(pool.empty());
+
+    pool.emplace(entities[0], 0);
+    pool.emplace(entities[1], 1);
+    pool.emplace(entities[2], 2);
+    pool.erase(entities, entities + 2u);
+
+    ASSERT_FALSE(pool.empty());
+    ASSERT_EQ(*pool.begin(), 2);
+
+    pool.erase(entities[2]);
+
+    ASSERT_DEATH(pool.erase(entities[2]), "");
+    ASSERT_TRUE(pool.empty());
+
+    pool.emplace(entities[0], 0);
+    pool.emplace(entities[1], 1);
+    pool.emplace(entities[2], 2);
+    std::swap(entities[1], entities[2]);
+    pool.erase(entities, entities + 2u);
+
+    ASSERT_FALSE(pool.empty());
+    ASSERT_EQ(*pool.begin(), 1);
+}
+
 TEST(Storage, Remove) {
     entt::storage<int> pool;
-    entt::sparse_set &base = pool;
+    entt::entity entities[3];
 
-    pool.emplace(entt::entity{3});
-    pool.emplace(entt::entity{42});
-    base.erase(base.begin(), base.end());
+    entities[0] = entt::entity{3};
+    entities[1] = entt::entity{42};
+    entities[2] = entt::entity{9};
+
+    pool.emplace(entities[0]);
+    pool.emplace(entities[1]);
+    pool.emplace(entities[2]);
+    pool.remove(std::begin(entities), std::end(entities));
+    pool.remove(std::begin(entities), std::end(entities));
 
     ASSERT_TRUE(pool.empty());
 
-    pool.emplace(entt::entity{3}, 3);
-    pool.emplace(entt::entity{42}, 42);
-    pool.emplace(entt::entity{9}, 9);
-    base.erase(base.rbegin(), base.rbegin() + 2u);
+    pool.emplace(entities[0], 0);
+    pool.emplace(entities[1], 1);
+    pool.emplace(entities[2], 2);
+    pool.remove(entities, entities + 2u);
 
     ASSERT_FALSE(pool.empty());
-    ASSERT_EQ(*pool.begin(), 9);
+    ASSERT_EQ(*pool.begin(), 2);
 
-    pool.clear();
-    pool.emplace(entt::entity{3}, 3);
-    pool.emplace(entt::entity{42}, 42);
-    pool.emplace(entt::entity{9}, 9);
+    pool.remove(entities[2]);
+    pool.remove(entities[2]);
+
+    ASSERT_TRUE(pool.empty());
 
-    entt::entity entities[2]{entt::entity{3}, entt::entity{9}};
-    base.erase(std::begin(entities), std::end(entities));
+    pool.emplace(entities[0], 0);
+    pool.emplace(entities[1], 1);
+    pool.emplace(entities[2], 2);
+    std::swap(entities[1], entities[2]);
+    pool.remove(entities, entities + 2u);
 
     ASSERT_FALSE(pool.empty());
-    ASSERT_EQ(*pool.begin(), 42);
+    ASSERT_EQ(*pool.begin(), 1);
 }
 
 TEST(Storage, AggregatesMustWork) {