diff options
-rw-r--r-- | absl/container/internal/common_policy_traits.h | 15 | ||||
-rw-r--r-- | absl/container/internal/common_policy_traits_test.cc | 9 | ||||
-rw-r--r-- | absl/container/internal/container_memory.h | 13 |
3 files changed, 31 insertions, 6 deletions
diff --git a/absl/container/internal/common_policy_traits.h b/absl/container/internal/common_policy_traits.h index cc2e89ba..c99e68f4 100644 --- a/absl/container/internal/common_policy_traits.h +++ b/absl/container/internal/common_policy_traits.h @@ -16,6 +16,7 @@ #define ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_ #include <cstddef> +#include <cstring> #include <memory> #include <new> #include <type_traits> @@ -32,7 +33,8 @@ template <class Policy, class = void> struct common_policy_traits { // The actual object stored in the container. using slot_type = typename Policy::slot_type; - + using reference = decltype(Policy::element(std::declval<slot_type*>())); + using value_type = typename std::remove_reference<reference>::type; // PRECONDITION: `slot` is UNINITIALIZED // POSTCONDITION: `slot` is INITIALIZED @@ -89,6 +91,17 @@ struct common_policy_traits { template <class Alloc> static void transfer_impl(Alloc* alloc, slot_type* new_slot, slot_type* old_slot, char) { +#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 + if (absl::is_trivially_relocatable<value_type>()) { + // TODO(b/247130232): remove cast after fixing class-memaccess warning. + std::memcpy(static_cast<void*>( + std::launder(const_cast<std::remove_const_t<value_type>*>( + &element(new_slot)))), + &element(old_slot), sizeof(value_type)); + return; + } +#endif + construct(alloc, new_slot, std::move(element(old_slot))); destroy(alloc, old_slot); } diff --git a/absl/container/internal/common_policy_traits_test.cc b/absl/container/internal/common_policy_traits_test.cc index 768d870e..5eaa4aae 100644 --- a/absl/container/internal/common_policy_traits_test.cc +++ b/absl/container/internal/common_policy_traits_test.cc @@ -27,7 +27,7 @@ namespace container_internal { namespace { using ::testing::MockFunction; -using ::testing::Return; +using ::testing::AnyNumber; using ::testing::ReturnRef; using Slot = int; @@ -101,9 +101,10 @@ TEST_F(Test, element) { TEST_F(Test, without_transfer) { int b = 42; - EXPECT_CALL(element, Call(&b)).WillOnce(::testing::ReturnRef(b)); - EXPECT_CALL(construct, Call(&alloc, &a, b)); - EXPECT_CALL(destroy, Call(&alloc, &b)); + EXPECT_CALL(element, Call(&a)).Times(AnyNumber()).WillOnce(ReturnRef(a)); + EXPECT_CALL(element, Call(&b)).WillOnce(ReturnRef(b)); + EXPECT_CALL(construct, Call(&alloc, &a, b)).Times(AnyNumber()); + EXPECT_CALL(destroy, Call(&alloc, &b)).Times(AnyNumber()); common_policy_traits<PolicyWithoutOptionalOps>::transfer(&alloc, &a, &b); } diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h index 00e9f6d7..c29c533b 100644 --- a/absl/container/internal/container_memory.h +++ b/absl/container/internal/container_memory.h @@ -17,6 +17,7 @@ #include <cassert> #include <cstddef> +#include <cstring> #include <memory> #include <new> #include <tuple> @@ -340,7 +341,8 @@ template <class K, class V> struct map_slot_policy { using slot_type = map_slot_type<K, V>; using value_type = std::pair<const K, V>; - using mutable_value_type = std::pair<K, V>; + using mutable_value_type = + std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>; private: static void emplace(slot_type* slot) { @@ -424,6 +426,15 @@ struct map_slot_policy { static void transfer(Allocator* alloc, slot_type* new_slot, slot_type* old_slot) { emplace(new_slot); +#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 + if (absl::is_trivially_relocatable<value_type>()) { + // TODO(b/247130232): remove cast after fixing class-memaccess warning. + std::memcpy(static_cast<void*>(std::launder(&new_slot->value)), + &old_slot->value, sizeof(value_type)); + return; + } +#endif + if (kMutableKeys::value) { absl::allocator_traits<Allocator>::construct( *alloc, &new_slot->mutable_value, std::move(old_slot->mutable_value)); |