Browse Source

dense_map: strong exception guarantee (emplace/insert)

Michele Caini 4 years ago
parent
commit
335f876a46
2 changed files with 19 additions and 4 deletions
  1. 4 4
      src/entt/container/dense_map.hpp
  2. 15 0
      test/entt/container/dense_map.cpp

+ 4 - 4
src/entt/container/dense_map.hpp

@@ -307,8 +307,8 @@ class dense_map {
             return std::make_pair(it, false);
         }
 
-        const auto next = std::exchange(sparse.first()[index], packed.first().size());
-        packed.first().emplace_back(next, std::piecewise_construct, std::forward_as_tuple(std::forward<Other>(key)), std::forward_as_tuple(std::forward<Args>(args)...));
+        packed.first().emplace_back(sparse.first()[index], std::piecewise_construct, std::forward_as_tuple(std::forward<Other>(key)), std::forward_as_tuple(std::forward<Args>(args)...));
+        sparse.first()[index] = packed.first().size() - 1u;
         rehash_if_required();
 
         return std::make_pair(--end(), true);
@@ -323,8 +323,8 @@ class dense_map {
             return std::make_pair(it, false);
         }
 
-        const auto next = std::exchange(sparse.first()[index], packed.first().size());
-        packed.first().emplace_back(next, std::forward<Other>(key), std::forward<Arg>(value));
+        packed.first().emplace_back(sparse.first()[index], std::forward<Other>(key), std::forward<Arg>(value));
+        sparse.first()[index] = packed.first().size() - 1u;
         rehash_if_required();
 
         return std::make_pair(--end(), true);

+ 15 - 0
test/entt/container/dense_map.cpp

@@ -1106,6 +1106,21 @@ TEST(DenseMap, ThrowingAllocator) {
     ASSERT_EQ(map.bucket_count(), minimum_bucket_count);
     ASSERT_THROW(map.reserve(2u * map.bucket_count()), packed_exception);
     ASSERT_EQ(map.bucket_count(), minimum_bucket_count);
+
+    packed_allocator::trigger_on_allocate = true;
+
+    ASSERT_THROW(map.emplace(0u, 0u), packed_exception);
+    ASSERT_FALSE(map.contains(0u));
+
+    packed_allocator::trigger_on_allocate = true;
+
+    ASSERT_THROW(map.emplace(std::piecewise_construct, std::make_tuple(0u), std::make_tuple(0u)), packed_exception);
+    ASSERT_FALSE(map.contains(0u));
+
+    packed_allocator::trigger_on_allocate = true;
+
+    ASSERT_THROW(map.insert_or_assign(0u, 0u), packed_exception);
+    ASSERT_FALSE(map.contains(0u));
 }
 
 #if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)