diff options
author | Abseil Team <absl-team@google.com> | 2023-11-20 14:57:43 -0800 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-11-20 14:58:49 -0800 |
commit | db5c79932e16e97e8b2f9ecd0e74f99f0e74e0d7 (patch) | |
tree | f97c66bd57931a32ba1cb4c7a222f7003d9f359d | |
parent | f393335cb7410fc3a88f41dc5dd878c020213e0b (diff) |
Make `FlatHashMapPolicy` return `std::true_type` for relocatable objects.
This reduces produced binary size and can trigger even more optimizations in the future.
PiperOrigin-RevId: 584136517
Change-Id: I3854833799f88f28b755ec53132925f0c3d468ab
-rw-r--r-- | absl/container/BUILD.bazel | 2 | ||||
-rw-r--r-- | absl/container/CMakeLists.txt | 2 | ||||
-rw-r--r-- | absl/container/flat_hash_map.h | 4 | ||||
-rw-r--r-- | absl/container/flat_hash_map_test.cc | 38 | ||||
-rw-r--r-- | absl/container/internal/container_memory.h | 22 | ||||
-rw-r--r-- | absl/container/internal/container_memory_test.cc | 32 |
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 |