diff --git a/src/entt/entity/sparse_set.hpp b/src/entt/entity/sparse_set.hpp index a6a5cfdd2..0f96c2133 100644 --- a/src/entt/entity/sparse_set.hpp +++ b/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 + void remove(It first, It last, void *ud = nullptr) { + for(; first != last; ++first) { + remove(*first, ud); + } + } + /** * @copybrief swap_at * diff --git a/test/entt/entity/sparse_set.cpp b/test/entt/entity/sparse_set.cpp index 0cdfcc929..a8039ee55 100644 --- a/test/entt/entity/sparse_set.cpp +++ b/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; diff --git a/test/entt/entity/storage.cpp b/test/entt/entity/storage.cpp index aaeede502..4d0157af0 100644 --- a/test/entt/entity/storage.cpp +++ b/test/entt/entity/storage.cpp @@ -131,34 +131,82 @@ TEST(Storage, InsertEmptyType) { ASSERT_EQ(pool.size(), 2u); } +TEST(Storage, Erase) { + entt::storage 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 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]); - entt::entity entities[2]{entt::entity{3}, entt::entity{9}}; - base.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); + 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) {