Browse Source

sparse_set: added ::emplace_back

Michele Caini 4 years ago
parent
commit
e4fb293b55
2 changed files with 70 additions and 13 deletions
  1. 24 12
      src/entt/entity/sparse_set.hpp
  2. 46 1
      test/entt/entity/sparse_set.cpp

+ 24 - 12
src/entt/entity/sparse_set.hpp

@@ -556,7 +556,7 @@ public:
     }
 
     /**
-     * @brief Assigns an entity to a sparse set.
+     * @brief Appends an entity to a sparse set.
      *
      * @warning
      * Attempting to assign an entity that already belongs to the sparse set
@@ -565,23 +565,35 @@ public:
      * @param entt A valid entity identifier.
      * @return The slot used for insertion.
      */
-    size_type emplace(const entity_type entt) {
+    size_type emplace_back(const entity_type entt) {
         ENTT_ASSERT(!contains(entt), "Set already contains entity");
 
-        if(free_list == null) {
-            if(count == reserved) {
-                const size_type sz = static_cast<size_type>(reserved * growth_factor);
-                resize_packed(sz + !(sz > reserved));
-            }
+        if(count == reserved) {
+            const size_type sz = static_cast<size_type>(reserved * growth_factor);
+            resize_packed(sz + !(sz > reserved));
+        }
 
-            assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(count));
-            packed[count] = entt;
+        assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(count));
+        packed[count] = entt;
+        return count++;
+    }
 
-            return count++;
+    /**
+     * @brief Assigns an entity to a sparse set.
+     *
+     * @warning
+     * Attempting to assign an entity that already belongs to the sparse set
+     * results in undefined behavior.
+     *
+     * @param entt A valid entity identifier.
+     * @return The slot used for insertion.
+     */
+    size_type emplace(const entity_type entt) {
+        if(free_list == null) {
+            return emplace_back(entt);
         } else {
+            ENTT_ASSERT(!contains(entt), "Set already contains entity");
             const auto pos = size_type{traits_type::to_entity(free_list)};
-            move_and_pop(count, pos);
-            // TODO no guarantees
             sparse[page(entt)][offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(pos));
             free_list = std::exchange(packed[pos], entt);
             return pos;

+ 46 - 1
test/entt/entity/sparse_set.cpp

@@ -175,8 +175,42 @@ TEST(SparseSet, Pagination) {
     ASSERT_EQ(set.extent(), 2 * ENTT_SPARSE_PAGE);
 }
 
+TEST(SparseSet, Emplace) {
+    entt::sparse_set set{entt::deletion_policy::in_place};
+    entt::entity entities[2u];
+
+    entities[0u] = entt::entity{3};
+    entities[1u] = entt::entity{42};
+
+    ASSERT_TRUE(set.empty());
+
+    set.emplace(entities[0u]);
+    set.erase(entities[0u]);
+
+    set.emplace_back(entities[0u]);
+    set.emplace(entities[1u]);
+
+    ASSERT_DEATH(set.emplace_back(entities[1u]), "");
+    ASSERT_DEATH(set.emplace(entities[0u]), "");
+
+    ASSERT_EQ(set.at(0u), entities[1u]);
+    ASSERT_EQ(set.at(1u), entities[0u]);
+    ASSERT_EQ(set.index(entities[0u]), 1u);
+    ASSERT_EQ(set.index(entities[1u]), 0u);
+
+    set.erase(std::begin(entities), std::end(entities));
+    set.emplace(entities[1u]);
+    set.emplace_back(entities[0u]);
+
+    ASSERT_EQ(set.at(0u), entities[1u]);
+    ASSERT_EQ(set.at(1u), static_cast<entt::entity>(entt::null));
+    ASSERT_EQ(set.at(2u), entities[0u]);
+    ASSERT_EQ(set.index(entities[0u]), 2u);
+    ASSERT_EQ(set.index(entities[1u]), 0u);
+}
+
 TEST(SparseSet, Insert) {
-    entt::sparse_set set;
+    entt::sparse_set set{entt::deletion_policy::in_place};
     entt::entity entities[2u];
 
     entities[0u] = entt::entity{3};
@@ -204,6 +238,17 @@ TEST(SparseSet, Insert) {
     ASSERT_EQ(set.data()[set.index(entities[0u])], entities[0u]);
     ASSERT_EQ(set.data()[set.index(entities[1u])], entities[1u]);
     ASSERT_EQ(set.data()[set.index(entt::entity{24})], entt::entity{24});
+
+    set.erase(std::begin(entities), std::end(entities));
+    set.insert(std::rbegin(entities), std::rend(entities));
+
+    ASSERT_EQ(set.size(), 6u);
+    ASSERT_TRUE(set.at(1u) == entt::tombstone);
+    ASSERT_TRUE(set.at(2u) == entt::tombstone);
+    ASSERT_EQ(set.at(4u), entities[1u]);
+    ASSERT_EQ(set.at(5u), entities[0u]);
+    ASSERT_EQ(set.index(entities[0u]), 5u);
+    ASSERT_EQ(set.index(entities[1u]), 4u);
 }
 
 TEST(SparseSet, Erase) {