From 22dc7911f9a4721f6dec0cc41a36fd204aa0e4f8 Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Tue, 3 Oct 2023 10:01:17 -0700 Subject: Refactor swisstable copy/move assignment to fix issues with allocator propagation and improve performance. Correctness: - We use swap to implement copy assignment and move assignment, which means that allocator propagation in copy/move assignment depends on `propagate_on_container_swap` in addition to `propagate_on_container_copy_assignment`/`propagate_on_container_move_assignment`. - In swap, if `propagate_on_container_swap` is `false` and `get_allocator() != other.get_allocator()`, the behavior is undefined (https://en.cppreference.com/w/cpp/container/unordered_set/swap) - we should assert that this UB case isn't happening. For this reason, we also delete the NoPropagateOn_Swap test case in raw_hash_set_allocator_test. Performance: - Don't rely on swap so we don't have to do unnecessary copying into the moved-from sets. - Don't use temp sets in move assignment. - Default the move constructor of CommonFields. - Avoid using exchange in raw_hash_set move constructor. - In `raw_hash_set(raw_hash_set&& that, const allocator_type& a)` with unequal allocators and in move assignment with non-propagating unequal allocators, move set keys instead of copying them. PiperOrigin-RevId: 570419290 Change-Id: I499e54f17d9cb0b0836601f5c06187d1f269a5b8 --- absl/container/internal/raw_hash_set_test.cc | 32 +++++++++++++++++++--------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'absl/container/internal/raw_hash_set_test.cc') diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index 4ee61220..61eb6d95 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -410,14 +410,14 @@ struct StringTable }; struct IntTable - : raw_hash_set, + : raw_hash_set, std::equal_to, std::allocator> { using Base = typename IntTable::raw_hash_set; using Base::Base; }; struct Uint8Table - : raw_hash_set, + : raw_hash_set, std::equal_to, std::allocator> { using Base = typename Uint8Table::raw_hash_set; using Base::Base; @@ -436,14 +436,14 @@ struct CustomAlloc : std::allocator { }; struct CustomAllocIntTable - : raw_hash_set, + : raw_hash_set, std::equal_to, CustomAlloc> { using Base = typename CustomAllocIntTable::raw_hash_set; using Base::Base; }; struct MinimumAlignmentUint8Table - : raw_hash_set, + : raw_hash_set, std::equal_to, MinimumAlignmentAlloc> { using Base = typename MinimumAlignmentUint8Table::raw_hash_set; using Base::Base; @@ -1602,7 +1602,7 @@ TEST(Table, CopyConstructWithAlloc) { } struct ExplicitAllocIntTable - : raw_hash_set, + : raw_hash_set, std::equal_to, Alloc> { ExplicitAllocIntTable() = default; }; @@ -1680,6 +1680,14 @@ TEST(Table, MoveAssign) { EXPECT_THAT(*u.find("a"), Pair("a", "b")); } +TEST(Table, MoveSelfAssign) { + StringTable t; + t.emplace("a", "b"); + EXPECT_EQ(1, t.size()); + t = std::move(*&t); + // As long as we don't crash, it's fine. +} + TEST(Table, Equality) { StringTable t; std::vector> v = {{"a", "b"}, @@ -1858,11 +1866,9 @@ TEST(Table, HeterogeneousLookupOverloads) { EXPECT_FALSE((VerifyResultOf())); EXPECT_FALSE((VerifyResultOf())); - using TransparentTable = raw_hash_set< - StringPolicy, - absl::container_internal::hash_default_hash, - absl::container_internal::hash_default_eq, - std::allocator>; + using TransparentTable = + raw_hash_set, + hash_default_eq, std::allocator>; EXPECT_TRUE((VerifyResultOf())); EXPECT_TRUE((VerifyResultOf())); @@ -2464,6 +2470,12 @@ TEST(Iterator, InvalidComparisonDifferentTables) { "Invalid iterator comparison.*non-end"); } +template +using RawHashSetAlloc = raw_hash_set, + std::equal_to, Alloc>; + +TEST(Table, AllocatorPropagation) { TestAllocPropagation(); } + } // namespace } // namespace container_internal ABSL_NAMESPACE_END -- cgit v1.2.3