Browse Source

sparse_set: fixed a throwing case that could leave the set in an inconsistent state

Michele Caini 4 years ago
parent
commit
40aabe76c7
2 changed files with 9 additions and 1 deletions
  1. 1 1
      src/entt/entity/sparse_set.hpp
  2. 8 0
      test/entt/entity/sparse_set.cpp

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

@@ -274,8 +274,8 @@ protected:
         ENTT_ASSERT(entity_traits::to_version(elem) == entity_traits::to_version(tombstone), "Slot not available");
         ENTT_ASSERT(entity_traits::to_version(elem) == entity_traits::to_version(tombstone), "Slot not available");
 
 
         if(free_list == null) {
         if(free_list == null) {
-            elem = entity_traits::combine(static_cast<typename entity_traits::entity_type>(packed.size()), entity_traits::to_integral(entt));
             packed.push_back(entt);
             packed.push_back(entt);
+            elem = entity_traits::combine(static_cast<typename entity_traits::entity_type>(packed.size() - 1u), entity_traits::to_integral(entt));
         } else {
         } else {
             elem = entity_traits::combine(entity_traits::to_integral(free_list), entity_traits::to_integral(entt));
             elem = entity_traits::combine(entity_traits::to_integral(free_list), entity_traits::to_integral(entt));
             free_list = std::exchange(packed[static_cast<size_type>(entity_traits::to_entity(free_list))], entt);
             free_list = std::exchange(packed[static_cast<size_type>(entity_traits::to_entity(free_list))], entt);

+ 8 - 0
test/entt/entity/sparse_set.cpp

@@ -1246,6 +1246,14 @@ TEST(SparseSet, ThrowingAllocator) {
     ASSERT_TRUE(set.contains(entt::entity{0}));
     ASSERT_TRUE(set.contains(entt::entity{0}));
     ASSERT_EQ(set.capacity(), 1u);
     ASSERT_EQ(set.capacity(), 1u);
 
 
+    test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
+
+    ASSERT_THROW(set.emplace(entt::entity{1}), test::throwing_allocator<entt::entity>::exception_type);
+    ASSERT_EQ(set.extent(), ENTT_SPARSE_PAGE);
+    ASSERT_TRUE(set.contains(entt::entity{0}));
+    ASSERT_FALSE(set.contains(entt::entity{1}));
+    ASSERT_EQ(set.capacity(), 1u);
+
     entt::entity entities[2u]{entt::entity{1}, entt::entity{ENTT_SPARSE_PAGE}};
     entt::entity entities[2u]{entt::entity{1}, entt::entity{ENTT_SPARSE_PAGE}};
     test::throwing_allocator<entt::entity>::trigger_after_allocate = true;
     test::throwing_allocator<entt::entity>::trigger_after_allocate = true;