Commit f8e0ff7f by Evan Brown Committed by Copybara-Service

Use trivial relocation for transfers in swisstable and b-tree.

PiperOrigin-RevId: 478547898
Change-Id: Ie20cd0a49df042be912888ee238333a5f5fa0404
parent d277a48d
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_ #define ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_
#include <cstddef> #include <cstddef>
#include <cstring>
#include <memory> #include <memory>
#include <new> #include <new>
#include <type_traits> #include <type_traits>
...@@ -32,7 +33,8 @@ template <class Policy, class = void> ...@@ -32,7 +33,8 @@ template <class Policy, class = void>
struct common_policy_traits { struct common_policy_traits {
// The actual object stored in the container. // The actual object stored in the container.
using slot_type = typename Policy::slot_type; 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 // PRECONDITION: `slot` is UNINITIALIZED
// POSTCONDITION: `slot` is INITIALIZED // POSTCONDITION: `slot` is INITIALIZED
...@@ -89,6 +91,17 @@ struct common_policy_traits { ...@@ -89,6 +91,17 @@ struct common_policy_traits {
template <class Alloc> template <class Alloc>
static void transfer_impl(Alloc* alloc, slot_type* new_slot, static void transfer_impl(Alloc* alloc, slot_type* new_slot,
slot_type* old_slot, char) { 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))); construct(alloc, new_slot, std::move(element(old_slot)));
destroy(alloc, old_slot); destroy(alloc, old_slot);
} }
......
...@@ -27,7 +27,7 @@ namespace container_internal { ...@@ -27,7 +27,7 @@ namespace container_internal {
namespace { namespace {
using ::testing::MockFunction; using ::testing::MockFunction;
using ::testing::Return; using ::testing::AnyNumber;
using ::testing::ReturnRef; using ::testing::ReturnRef;
using Slot = int; using Slot = int;
...@@ -101,9 +101,10 @@ TEST_F(Test, element) { ...@@ -101,9 +101,10 @@ TEST_F(Test, element) {
TEST_F(Test, without_transfer) { TEST_F(Test, without_transfer) {
int b = 42; int b = 42;
EXPECT_CALL(element, Call(&b)).WillOnce(::testing::ReturnRef(b)); EXPECT_CALL(element, Call(&a)).Times(AnyNumber()).WillOnce(ReturnRef(a));
EXPECT_CALL(construct, Call(&alloc, &a, b)); EXPECT_CALL(element, Call(&b)).WillOnce(ReturnRef(b));
EXPECT_CALL(destroy, Call(&alloc, &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); common_policy_traits<PolicyWithoutOptionalOps>::transfer(&alloc, &a, &b);
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstring>
#include <memory> #include <memory>
#include <new> #include <new>
#include <tuple> #include <tuple>
...@@ -340,7 +341,8 @@ template <class K, class V> ...@@ -340,7 +341,8 @@ template <class K, class V>
struct map_slot_policy { struct map_slot_policy {
using slot_type = map_slot_type<K, V>; using slot_type = map_slot_type<K, V>;
using value_type = std::pair<const 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: private:
static void emplace(slot_type* slot) { static void emplace(slot_type* slot) {
...@@ -424,6 +426,15 @@ struct map_slot_policy { ...@@ -424,6 +426,15 @@ struct map_slot_policy {
static void transfer(Allocator* alloc, slot_type* new_slot, static void transfer(Allocator* alloc, slot_type* new_slot,
slot_type* old_slot) { slot_type* old_slot) {
emplace(new_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) { if (kMutableKeys::value) {
absl::allocator_traits<Allocator>::construct( absl::allocator_traits<Allocator>::construct(
*alloc, &new_slot->mutable_value, std::move(old_slot->mutable_value)); *alloc, &new_slot->mutable_value, std::move(old_slot->mutable_value));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment