summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--absl/container/BUILD.bazel2
-rw-r--r--absl/container/CMakeLists.txt2
-rw-r--r--absl/container/flat_hash_map.h4
-rw-r--r--absl/container/flat_hash_map_test.cc38
-rw-r--r--absl/container/internal/container_memory.h22
-rw-r--r--absl/container/internal/container_memory_test.cc32
6 files changed, 84 insertions, 16 deletions
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index 5b69ae6b..8585d882 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -268,6 +268,7 @@ cc_test(
":unordered_map_members_test",
":unordered_map_modifiers_test",
"//absl/log:check",
+ "//absl/meta:type_traits",
"//absl/types:any",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
@@ -401,6 +402,7 @@ cc_test(
deps = [
":container_memory",
":test_instance_tracker",
+ "//absl/meta:type_traits",
"//absl/strings",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 96cdf59c..e5cf13b1 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -305,6 +305,7 @@ absl_cc_test(
absl::check
absl::flat_hash_map
absl::hash_generator_testing
+ absl::type_traits
absl::unordered_map_constructor_test
absl::unordered_map_lookup_test
absl::unordered_map_members_test
@@ -450,6 +451,7 @@ absl_cc_test(
absl::container_memory
absl::strings
absl::test_instance_tracker
+ absl::type_traits
GTest::gmock_main
)
diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h
index 5304477d..acd013b0 100644
--- a/absl/container/flat_hash_map.h
+++ b/absl/container/flat_hash_map.h
@@ -579,9 +579,9 @@ struct FlatHashMapPolicy {
}
template <class Allocator>
- static void transfer(Allocator* alloc, slot_type* new_slot,
+ static auto transfer(Allocator* alloc, slot_type* new_slot,
slot_type* old_slot) {
- slot_policy::transfer(alloc, new_slot, old_slot);
+ return slot_policy::transfer(alloc, new_slot, old_slot);
}
template <class F, class... Args>
diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc
index e6acbea2..d90fe9d5 100644
--- a/absl/container/flat_hash_map_test.cc
+++ b/absl/container/flat_hash_map_test.cc
@@ -14,14 +14,20 @@
#include "absl/container/flat_hash_map.h"
+#include <cstddef>
#include <memory>
+#include <type_traits>
+#include <utility>
+#include <vector>
+#include "gtest/gtest.h"
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/unordered_map_constructor_test.h"
#include "absl/container/internal/unordered_map_lookup_test.h"
#include "absl/container/internal/unordered_map_members_test.h"
#include "absl/container/internal/unordered_map_modifiers_test.h"
#include "absl/log/check.h"
+#include "absl/meta/type_traits.h"
#include "absl/types/any.h"
namespace absl {
@@ -102,6 +108,34 @@ TEST(FlatHashMap, StandardLayout) {
}
}
+TEST(FlatHashMap, Relocatability) {
+ static_assert(absl::is_trivially_relocatable<int>::value, "");
+ static_assert(
+ absl::is_trivially_relocatable<std::pair<const int, int>>::value, "");
+ static_assert(
+ std::is_same<decltype(absl::container_internal::FlatHashMapPolicy<
+ int, int>::transfer<std::allocator<char>>(nullptr,
+ nullptr,
+ nullptr)),
+ std::true_type>::value,
+ "");
+
+ struct NonRelocatable {
+ NonRelocatable() = default;
+ NonRelocatable(NonRelocatable&&) {}
+ NonRelocatable& operator=(NonRelocatable&&) { return *this; }
+ void* self = nullptr;
+ };
+
+ EXPECT_FALSE(absl::is_trivially_relocatable<NonRelocatable>::value);
+ EXPECT_TRUE(
+ (std::is_same<decltype(absl::container_internal::FlatHashMapPolicy<
+ int, NonRelocatable>::
+ transfer<std::allocator<char>>(nullptr, nullptr,
+ nullptr)),
+ std::false_type>::value));
+}
+
// gcc becomes unhappy if this is inside the method, so pull it out here.
struct balast {};
@@ -150,9 +184,7 @@ struct Hash {
struct Eq {
using is_transparent = void;
- bool operator()(size_t lhs, size_t rhs) const {
- return lhs == rhs;
- }
+ bool operator()(size_t lhs, size_t rhs) const { return lhs == rhs; }
bool operator()(size_t lhs, const LazyInt& rhs) const {
return lhs == rhs.value;
}
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h
index f59ca4ee..3262d4eb 100644
--- a/absl/container/internal/container_memory.h
+++ b/absl/container/internal/container_memory.h
@@ -122,10 +122,10 @@ auto TupleRefImpl(T&& t, absl::index_sequence<Is...>)
// Returns a tuple of references to the elements of the input tuple. T must be a
// tuple.
template <class T>
-auto TupleRef(T&& t) -> decltype(
- TupleRefImpl(std::forward<T>(t),
- absl::make_index_sequence<
- std::tuple_size<typename std::decay<T>::type>::value>())) {
+auto TupleRef(T&& t) -> decltype(TupleRefImpl(
+ std::forward<T>(t),
+ absl::make_index_sequence<
+ std::tuple_size<typename std::decay<T>::type>::value>())) {
return TupleRefImpl(
std::forward<T>(t),
absl::make_index_sequence<
@@ -156,8 +156,8 @@ void ConstructFromTuple(Alloc* alloc, T* ptr, Tuple&& t) {
// Constructs T using the args specified in the tuple and calls F with the
// constructed value.
template <class T, class Tuple, class F>
-decltype(std::declval<F>()(std::declval<T>())) WithConstructed(
- Tuple&& t, F&& f) {
+decltype(std::declval<F>()(std::declval<T>())) WithConstructed(Tuple&& t,
+ F&& f) {
return memory_internal::WithConstructedImpl<T>(
std::forward<Tuple>(t),
absl::make_index_sequence<
@@ -423,16 +423,19 @@ struct map_slot_policy {
}
template <class Allocator>
- static void transfer(Allocator* alloc, slot_type* new_slot,
+ static auto transfer(Allocator* alloc, slot_type* new_slot,
slot_type* old_slot) {
+ auto is_relocatable =
+ typename absl::is_trivially_relocatable<value_type>::type();
+
emplace(new_slot);
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
- if (absl::is_trivially_relocatable<value_type>()) {
+ if (is_relocatable) {
// TODO(b/247130232,b/251814870): remove casts after fixing warnings.
std::memcpy(static_cast<void*>(std::launder(&new_slot->value)),
static_cast<const void*>(&old_slot->value),
sizeof(value_type));
- return;
+ return is_relocatable;
}
#endif
@@ -444,6 +447,7 @@ struct map_slot_policy {
std::move(old_slot->value));
}
destroy(alloc, old_slot);
+ return is_relocatable;
}
};
diff --git a/absl/container/internal/container_memory_test.cc b/absl/container/internal/container_memory_test.cc
index fb9c4dde..c1e57834 100644
--- a/absl/container/internal/container_memory_test.cc
+++ b/absl/container/internal/container_memory_test.cc
@@ -14,8 +14,11 @@
#include "absl/container/internal/container_memory.h"
+#include <cstddef>
#include <cstdint>
+#include <memory>
#include <tuple>
+#include <type_traits>
#include <typeindex>
#include <typeinfo>
#include <utility>
@@ -23,6 +26,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/container/internal/test_instance_tracker.h"
+#include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h"
namespace absl {
@@ -219,8 +223,7 @@ TEST(DecomposePair, NotDecomposable) {
ADD_FAILURE() << "Must not be called";
return 'A';
};
- EXPECT_STREQ("not decomposable",
- TryDecomposePair(f));
+ EXPECT_STREQ("not decomposable", TryDecomposePair(f));
EXPECT_STREQ("not decomposable",
TryDecomposePair(f, std::piecewise_construct, std::make_tuple(),
std::make_tuple(0.5)));
@@ -251,6 +254,31 @@ TEST(MapSlotPolicy, ConstKeyAndValue) {
EXPECT_EQ(tracker.copies(), 0);
}
+TEST(MapSlotPolicy, TransferReturnsTrue) {
+ {
+ using slot_policy = map_slot_policy<int, float>;
+ EXPECT_TRUE(
+ (std::is_same<decltype(slot_policy::transfer<std::allocator<char>>(
+ nullptr, nullptr, nullptr)),
+ std::true_type>::value));
+ }
+ {
+ struct NonRelocatable {
+ NonRelocatable() = default;
+ NonRelocatable(NonRelocatable&&) {}
+ NonRelocatable& operator=(NonRelocatable&&) { return *this; }
+ void* self = nullptr;
+ };
+
+ EXPECT_FALSE(absl::is_trivially_relocatable<NonRelocatable>::value);
+ using slot_policy = map_slot_policy<int, NonRelocatable>;
+ EXPECT_TRUE(
+ (std::is_same<decltype(slot_policy::transfer<std::allocator<char>>(
+ nullptr, nullptr, nullptr)),
+ std::false_type>::value));
+ }
+}
+
} // namespace
} // namespace container_internal
ABSL_NAMESPACE_END