diff --git a/CMakeLists.txt b/CMakeLists.txt index 5426675d0db2ab81f1345a55f4d7a99019237f8a..257a75068ee8e240a993c2bd213f919dc577373b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -840,6 +840,7 @@ if (BUILD_TESTS) SOURCES ProducerConsumerQueueTest.cpp TEST random_test SOURCES RandomTest.cpp TEST range_test SOURCES RangeTest.cpp + TEST replaceable_test SOURCES ReplaceableTest.cpp TEST scope_guard_test SOURCES ScopeGuardTest.cpp # Heavily dependent on drand and srand48 #TEST shared_mutex_test SOURCES SharedMutexTest.cpp diff --git a/folly/Replaceable.h b/folly/Replaceable.h index abb79c9141b5a259a7c57e9ce8ddfae415680ca8..cbecb54f37da9157b08e20ebcc2f59b6e33a86ab 100644 --- a/folly/Replaceable.h +++ b/folly/Replaceable.h @@ -595,11 +595,8 @@ class alignas(T) Replaceable /** * `swap` just calls `swap(T&, T&)`. - * - * Should be `noexcept(std::is_nothrow_swappable<T>::value)` but we don't - * depend on C++17 features. */ - void swap(Replaceable& other) { + void swap(Replaceable& other) noexcept(IsNothrowSwappable<Replaceable>{}) { using std::swap; swap(*(*this), *other); } diff --git a/folly/test/ReplaceableTest.cpp b/folly/test/ReplaceableTest.cpp index af3c4bdcda4c3d861ce0a1acfd49897bead23d2a..f3aca572274982a68e8233c406c7b973e11b4f67 100644 --- a/folly/test/ReplaceableTest.cpp +++ b/folly/test/ReplaceableTest.cpp @@ -44,7 +44,9 @@ struct HasRef final { ++i1; } }; - +void swap(HasRef& lhs, HasRef& rhs) noexcept(false) { + std::swap(lhs.i1, rhs.i1); +} struct OddA; struct OddB { OddB() = delete; @@ -70,6 +72,11 @@ struct OddA { struct Indestructible { ~Indestructible() = delete; }; + +struct HasInt { + explicit HasInt(int v) : value{v} {} + int value{}; +}; } // namespace template <typename T> @@ -289,3 +296,41 @@ TEST(ReplaceableTest, Conversions) { Replaceable<OddA> rOddA{std::move(rOddB)}; Replaceable<OddB> rOddB2{rOddA}; } + +TEST(ReplaceableTest, swapMemberFunctionIsNoexcept) { + int v1{1}; + int v2{2}; + auto r1 = Replaceable<HasInt>{v1}; + auto r2 = Replaceable<HasInt>{v2}; + EXPECT_TRUE(noexcept(r1.swap(r2))); + r1.swap(r2); + EXPECT_EQ(v2, r1->value); + EXPECT_EQ(v1, r2->value); +} + +TEST(ReplaceableTest, swapMemberFunctionIsNotNoexcept) { + int v1{1}; + int v2{2}; + auto r1 = Replaceable<HasRef>{v1}; + auto r2 = Replaceable<HasRef>{v2}; + EXPECT_FALSE(noexcept(r1.swap(r2))); + r1.swap(r2); + EXPECT_EQ(v1, r1->i1); + EXPECT_EQ(v2, r2->i1); +} + +namespace adl_test { +struct UserDefinedSwap { + bool calledSwap{}; +}; +void swap(UserDefinedSwap& lhs, UserDefinedSwap&) noexcept(false) { + lhs.calledSwap = true; +} +} // namespace adl_test + +TEST(ReplaceableTest, swapMemberFunctionDelegatesToUserSwap) { + auto r1 = Replaceable<adl_test::UserDefinedSwap>{}; + auto r2 = Replaceable<adl_test::UserDefinedSwap>{}; + r1.swap(r2); + EXPECT_TRUE(r1->calledSwap); +}