diff --git a/src/entt/entity/sparse_set.hpp b/src/entt/entity/sparse_set.hpp index 826089553..dad342e01 100644 --- a/src/entt/entity/sparse_set.hpp +++ b/src/entt/entity/sparse_set.hpp @@ -530,6 +530,14 @@ public: return packed.empty(); } + /** + * @brief Checks whether a sparse set is fully packed. + * @return True if the sparse set is fully packed, false otherwise. + */ + [[nodiscard]] bool contiguous() const noexcept { + return (free_list == null); + } + /** * @brief Direct access to the internal packed array. * @return A pointer to the internal packed array. diff --git a/test/entt/entity/sparse_set.cpp b/test/entt/entity/sparse_set.cpp index 60aa8f791..a462edf32 100644 --- a/test/entt/entity/sparse_set.cpp +++ b/test/entt/entity/sparse_set.cpp @@ -26,6 +26,7 @@ TEST(SparseSet, Functionalities) { ASSERT_EQ(set.capacity(), 42u); ASSERT_TRUE(set.empty()); ASSERT_EQ(set.size(), 0u); + ASSERT_TRUE(set.contiguous()); ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end()); ASSERT_EQ(set.begin(), set.end()); ASSERT_FALSE(set.contains(entt::entity{0})); @@ -40,6 +41,7 @@ TEST(SparseSet, Functionalities) { ASSERT_FALSE(set.empty()); ASSERT_EQ(set.size(), 1u); + ASSERT_TRUE(set.contiguous()); ASSERT_NE(std::as_const(set).begin(), std::as_const(set).end()); ASSERT_NE(set.begin(), set.end()); ASSERT_FALSE(set.contains(entt::entity{0})); @@ -54,6 +56,7 @@ TEST(SparseSet, Functionalities) { ASSERT_TRUE(set.empty()); ASSERT_EQ(set.size(), 0u); + ASSERT_TRUE(set.contiguous()); ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end()); ASSERT_EQ(set.begin(), set.end()); ASSERT_FALSE(set.contains(entt::entity{0})); @@ -73,6 +76,7 @@ TEST(SparseSet, Functionalities) { ASSERT_TRUE(set.empty()); ASSERT_EQ(set.size(), 0u); + ASSERT_TRUE(set.contiguous()); ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end()); ASSERT_EQ(set.begin(), set.end()); ASSERT_FALSE(set.contains(entt::entity{0})); @@ -915,6 +919,64 @@ TEST(SparseSet, Clear) { ASSERT_EQ(set.find(entt::entity{9}), set.end()); } +TEST(SparseSet, Contiguous) { + entt::sparse_set swap_and_pop{entt::deletion_policy::swap_and_pop}; + entt::sparse_set in_place{entt::deletion_policy::in_place}; + + const entt::entity entity{42}; + const entt::entity other{3}; + + ASSERT_TRUE(swap_and_pop.contiguous()); + ASSERT_TRUE(in_place.contiguous()); + + swap_and_pop.push(entity); + in_place.push(entity); + + swap_and_pop.push(other); + in_place.push(other); + + ASSERT_TRUE(swap_and_pop.contiguous()); + ASSERT_TRUE(in_place.contiguous()); + + swap_and_pop.erase(entity); + in_place.erase(entity); + + ASSERT_TRUE(swap_and_pop.contiguous()); + ASSERT_FALSE(in_place.contiguous()); + + swap_and_pop.push(entity); + in_place.push(entity); + + ASSERT_TRUE(swap_and_pop.contiguous()); + ASSERT_TRUE(in_place.contiguous()); + + swap_and_pop.erase(other); + in_place.erase(other); + + ASSERT_TRUE(swap_and_pop.contiguous()); + ASSERT_FALSE(in_place.contiguous()); + + in_place.compact(); + + ASSERT_TRUE(swap_and_pop.contiguous()); + ASSERT_TRUE(in_place.contiguous()); + + swap_and_pop.push(other); + in_place.push(other); + + swap_and_pop.erase(entity); + in_place.erase(entity); + + ASSERT_TRUE(swap_and_pop.contiguous()); + ASSERT_FALSE(in_place.contiguous()); + + swap_and_pop.clear(); + in_place.clear(); + + ASSERT_TRUE(swap_and_pop.contiguous()); + ASSERT_TRUE(in_place.contiguous()); +} + TEST(SparseSet, Iterator) { using iterator = typename entt::sparse_set::iterator;