From a9a49560208484f1f99efdde889da6147e8722fe Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 29 Jan 2021 12:09:30 -0800 Subject: Export of internal Abseil changes -- c68f1886f5e8fd90eb0c2d2e68feaf00a7cdacda by CJ Johnson : Introduce absl::Cleanup to the OSS repo PiperOrigin-RevId: 354583156 -- 17030cf388e10f7eb959e3e566326d1072ce392e by Abseil Team : Internal change only PiperOrigin-RevId: 354574953 -- e979d7236d4f3252e79ddda6739b67a9a326bf6d by CJ Johnson : Internal change PiperOrigin-RevId: 354545297 -- 7ea02b3783f7f49ef97d86a8f6580a19cc57df14 by Abseil Team : Pre-allocate memory for vectors where the size is known. PiperOrigin-RevId: 354344576 -- 9246c7cb11f1d6444f79ebe25acc69a8a9b870e0 by Matt Kulukundis : Add support for Elbrus 2000 (e2k) Import of https://github.com/abseil/abseil-cpp/pull/889 PiperOrigin-RevId: 354344013 -- 0fc93d359cc1fb307552e917b37b7b2e7eed822f by Abseil Team : Integrate CordRepRing logic into cord (but do not enable it) PiperOrigin-RevId: 354312238 -- eda05622f7da71466723acb33403f783529df24b by Abseil Team : Protect ignore diagnostic with "__has_warning". PiperOrigin-RevId: 354112334 -- 47716c5d8fb10efa4fdd801d28bac414c6f8ec32 by Abseil Team : Rearrange InlinedVector copy constructor and destructor to treat a few special cases inline and then tail-call a non-inlined routine for the rest. In particular, we optimize for empty vectors in both cases. Added a couple of benchmarks that copy either an InlVec or an InlVec>. Speed difference: ``` BM_CopyTrivial/0 0.92ns +- 0% 0.47ns +- 0% -48.91% (p=0.000 n=11+12) BM_CopyTrivial/1 0.92ns +- 0% 1.15ns +- 0% +25.00% (p=0.000 n=10+9) BM_CopyTrivial/8 8.57ns +- 0% 10.72ns +- 1% +25.16% (p=0.000 n=10+12) BM_CopyNonTrivial/0 3.21ns +- 0% 0.70ns +- 0% -78.23% (p=0.000 n=12+10) BM_CopyNonTrivial/1 5.88ns +- 1% 5.51ns +- 0% -6.28% (p=0.000 n=10+8) BM_CopyNonTrivial/8 21.5ns +- 1% 15.2ns +- 2% -29.23% (p=0.000 n=12+12) ``` Note: the slowdowns are a few cycles which is expected given the procedure call added in that case. We decided this is a good tradeoff given the code size reductions and the more significant speedups for empty vectors. Size difference (as measured by nm): ``` BM_CopyTrivial from 1048 bytes to 326 bytes. BM_CopyNonTrivial from 749 bytes to 470 bytes. ``` Code size for a large binary drops by ~500KB (from 349415719 to 348906015 348906191). All of the benchmarks that showed a significant difference: Ones that improve with this CL: ``` BM_CopyNonTrivial/0 3.21ns +- 0% 0.70ns +- 0% -78.23% (p=0.000 n=12+10) BM_InlinedVectorFillString/0 0.93ns +- 0% 0.24ns +- 0% -74.19% (p=0.000 n=12+10) BM_InlinedVectorAssignments/1 10.5ns +- 0% 4.1ns +- 0% -60.64% (p=0.000 n=11+10) BM_InlinedVectorAssignments/2 10.7ns +- 0% 4.4ns +- 0% -59.08% (p=0.000 n=11+11) BM_CopyTrivial/0 0.92ns +- 0% 0.47ns +- 0% -48.91% (p=0.000 n=11+12) BM_CopyNonTrivial/8 21.5ns +- 1% 15.2ns +- 2% -29.23% (p=0.000 n=12+12) BM_StdVectorEmpty 0.47ns +- 1% 0.35ns +- 0% -24.73% (p=0.000 n=12+12) BM_StdVectorSize 0.46ns +- 2% 0.35ns +- 0% -24.32% (p=0.000 n=12+12) BM_SwapElements/0 3.44ns +- 0% 2.76ns +- 1% -19.83% (p=0.000 n=11+11) BM_InlinedVectorFillRange/256 20.7ns +- 1% 17.8ns +- 0% -14.08% (p=0.000 n=12+9) BM_CopyNonTrivial/1 5.88ns +- 1% 5.51ns +- 0% -6.28% (p=0.000 n=10+8) BM_SwapElements/1 4.19ns +- 0% 3.95ns +- 1% -5.63% (p=0.000 n=11+12) BM_SwapElements/1 4.18ns +- 0% 3.99ns +- 0% -4.70% (p=0.000 n=9+11) BM_SwapElements/0 2.41ns +- 0% 2.31ns +- 0% -4.45% (p=0.000 n=12+12) BM_InlinedVectorFillRange/64 8.25ns +- 0% 8.04ns +- 0% -2.51% (p=0.000 n=12+11) BM_SwapElements/1 82.4ns +- 0% 81.5ns +- 0% -1.06% (p=0.000 n=12+12) ``` Ones that get worse with this CL: ``` BM_CopyTrivial/1 0.92ns +- 0% 1.15ns +- 0% +25.00% (p=0.000 n=10+9) BM_CopyTrivial/8 8.57ns +- 0% 10.72ns +- 1% +25.16% (p=0.000 n=10+12) BM_SwapElements/512 1.48ns +- 1% 1.66ns +- 1% +11.88% (p=0.000 n=12+12) BM_InlinedVectorFillString/1 11.5ns +- 0% 12.8ns +- 1% +11.62% (p=0.000 n=12+11) BM_SwapElements/64 1.48ns +- 2% 1.66ns +- 1% +11.66% (p=0.000 n=12+11) BM_SwapElements/1k 1.48ns +- 1% 1.65ns +- 2% +11.32% (p=0.000 n=12+12) BM_SwapElements/512 1.48ns +- 2% 1.58ns +- 4% +6.62% (p=0.000 n=11+12) BM_SwapElements/1k 1.49ns +- 2% 1.58ns +- 3% +6.05% (p=0.000 n=12+12) BM_SwapElements/64 1.48ns +- 2% 1.57ns +- 4% +6.04% (p=0.000 n=11+12) BM_InlinedVectorFillRange/1 4.81ns +- 0% 5.05ns +- 0% +4.83% (p=0.000 n=11+11) BM_InlinedVectorFillString/8 79.4ns +- 1% 83.1ns +- 1% +4.64% (p=0.000 n=10+12) BM_StdVectorFillString/1 16.3ns +- 0% 16.6ns +- 0% +2.13% (p=0.000 n=11+8) ``` PiperOrigin-RevId: 353906786 -- 8e26518b3cec9c598e5e9573c46c3bd1b03a67ef by Abseil Team : Internal change PiperOrigin-RevId: 353737330 -- f206ae0983e58c9904ed8b8f05f9caf564a446be by Matt Kulukundis : Import of CCTZ from GitHub. PiperOrigin-RevId: 353682256 GitOrigin-RevId: c68f1886f5e8fd90eb0c2d2e68feaf00a7cdacda Change-Id: I5790c1036c4f543c701d1039848fabf7ae881ad8 --- absl/cleanup/cleanup_test.cc | 240 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 absl/cleanup/cleanup_test.cc (limited to 'absl/cleanup/cleanup_test.cc') diff --git a/absl/cleanup/cleanup_test.cc b/absl/cleanup/cleanup_test.cc new file mode 100644 index 00000000..34e3bfad --- /dev/null +++ b/absl/cleanup/cleanup_test.cc @@ -0,0 +1,240 @@ +// Copyright 2021 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/cleanup/cleanup.h" + +#include +#include +#include + +#include "gtest/gtest.h" +#include "absl/base/config.h" +#include "absl/utility/utility.h" + +namespace { + +using Tag = absl::cleanup_internal::Tag; + +template +void AssertSameType() { + static_assert(std::is_same::value, ""); +} + +struct IdentityFactory { + template + static Callback AsCallback(Callback callback) { + return Callback(std::move(callback)); + } +}; + +// `FunctorClass` is a type used for testing `absl::Cleanup`. It is intended to +// represent users that make their own move-only callback types outside of +// `std::function` and lambda literals. +class FunctorClass { + using Callback = std::function; + + public: + explicit FunctorClass(Callback callback) : callback_(std::move(callback)) {} + + FunctorClass(FunctorClass&& other) + : callback_(absl::exchange(other.callback_, Callback())) {} + + FunctorClass(const FunctorClass&) = delete; + + FunctorClass& operator=(const FunctorClass&) = delete; + + FunctorClass& operator=(FunctorClass&&) = delete; + + void operator()() const& = delete; + + void operator()() && { + ASSERT_TRUE(callback_); + callback_(); + callback_ = nullptr; + } + + private: + Callback callback_; +}; + +struct FunctorClassFactory { + template + static FunctorClass AsCallback(Callback callback) { + return FunctorClass(std::move(callback)); + } +}; + +struct StdFunctionFactory { + template + static std::function AsCallback(Callback callback) { + return std::function(std::move(callback)); + } +}; + +using CleanupTestParams = + ::testing::Types; +template +struct CleanupTest : public ::testing::Test {}; +TYPED_TEST_SUITE(CleanupTest, CleanupTestParams); + +bool function_pointer_called = false; +void FunctionPointerFunction() { function_pointer_called = true; } + +TYPED_TEST(CleanupTest, FactoryProducesCorrectType) { + { + auto callback = TypeParam::AsCallback([] {}); + auto cleanup = absl::MakeCleanup(std::move(callback)); + + AssertSameType, decltype(cleanup)>(); + } + + { + auto cleanup = absl::MakeCleanup(&FunctionPointerFunction); + + AssertSameType, decltype(cleanup)>(); + } + + { + auto cleanup = absl::MakeCleanup(FunctionPointerFunction); + + AssertSameType, decltype(cleanup)>(); + } +} + +#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) +TYPED_TEST(CleanupTest, CTADProducesCorrectType) { + { + auto callback = TypeParam::AsCallback([] {}); + absl::Cleanup cleanup = std::move(callback); + + AssertSameType, decltype(cleanup)>(); + } + + { + absl::Cleanup cleanup = &FunctionPointerFunction; + + AssertSameType, decltype(cleanup)>(); + } + + { + absl::Cleanup cleanup = FunctionPointerFunction; + + AssertSameType, decltype(cleanup)>(); + } +} + +TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) { + { + auto callback = IdentityFactory::AsCallback([] {}); + auto factory_cleanup = absl::MakeCleanup(callback); + absl::Cleanup deduction_cleanup = callback; + + AssertSameType(); + } + + { + auto factory_cleanup = + absl::MakeCleanup(FunctorClassFactory::AsCallback([] {})); + absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {}); + + AssertSameType(); + } + + { + auto factory_cleanup = + absl::MakeCleanup(StdFunctionFactory::AsCallback([] {})); + absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {}); + + AssertSameType(); + } + + { + auto factory_cleanup = absl::MakeCleanup(&FunctionPointerFunction); + absl::Cleanup deduction_cleanup = &FunctionPointerFunction; + + AssertSameType(); + } + + { + auto factory_cleanup = absl::MakeCleanup(FunctionPointerFunction); + absl::Cleanup deduction_cleanup = FunctionPointerFunction; + + AssertSameType(); + } +} +#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) + +TYPED_TEST(CleanupTest, BasicUsage) { + bool called = false; + + { + EXPECT_FALSE(called); + + auto cleanup = + absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); + + EXPECT_FALSE(called); + } + + EXPECT_TRUE(called); +} + +TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) { + function_pointer_called = false; + + { + EXPECT_FALSE(function_pointer_called); + + auto cleanup = + absl::MakeCleanup(TypeParam::AsCallback(&FunctionPointerFunction)); + + EXPECT_FALSE(function_pointer_called); + } + + EXPECT_TRUE(function_pointer_called); +} + +TYPED_TEST(CleanupTest, Cancel) { + bool called = false; + + { + EXPECT_FALSE(called); + + auto cleanup = + absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); + std::move(cleanup).Cancel(); + + EXPECT_FALSE(called); + } + + EXPECT_FALSE(called); +} + +TYPED_TEST(CleanupTest, Invoke) { + bool called = false; + + { + EXPECT_FALSE(called); + + auto cleanup = + absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); + std::move(cleanup).Invoke(); + + EXPECT_TRUE(called); + } + + EXPECT_TRUE(called); +} + +} // namespace -- cgit v1.2.3 From 184d2f8364bcb05e413ec4c72cad0cf86e712d1c Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Sat, 30 Jan 2021 06:20:07 -0800 Subject: Export of internal Abseil changes -- 8c77b14bdee3f4cafb8ba520d4d050b15a949fd4 by Derek Mauro : Fix absl::Cleanup usage example PiperOrigin-RevId: 354702001 -- 10365da7a0aacaa0c4774a4b618a76dff328611b by CJ Johnson : Swap the order of the C++11 and C++17 interfaces for absl::Cleanup to mirror the order used in the comment example PiperOrigin-RevId: 354675180 GitOrigin-RevId: 8c77b14bdee3f4cafb8ba520d4d050b15a949fd4 Change-Id: Ia2054b725ed737ff9e557cb3d973de7c34bc51b0 --- absl/cleanup/cleanup.h | 42 +++++++-------- absl/cleanup/cleanup_test.cc | 117 ++++++++++++++++++++++++---------------- absl/cleanup/internal/cleanup.h | 2 + 3 files changed, 95 insertions(+), 66 deletions(-) (limited to 'absl/cleanup/cleanup_test.cc') diff --git a/absl/cleanup/cleanup.h b/absl/cleanup/cleanup.h index eba04b33..f606b3f4 100644 --- a/absl/cleanup/cleanup.h +++ b/absl/cleanup/cleanup.h @@ -24,36 +24,36 @@ // ``` // void CopyGoodData(const char* input_path, const char* output_path) { // FILE* in_file = fopen(input_path, "r"); -// FILE* out_file = fopen(output_path, "w"); -// if (in_file == nullptr || out_file == nullptr) return; +// if (in_file == nullptr) return; // // // C++17 style using class template argument deduction -// absl::Cleanup in_closer = [&in_file] { fclose(in_file); }; +// absl::Cleanup in_closer = [in_file] { fclose(in_file); }; // -// // C++11 style using the factory function -// auto out_closer = absl::MakeCleanup([&out_file] { fclose(out_file); }); +// FILE* out_file = fopen(output_path, "w"); +// if (out_file == nullptr) return; // `in_closer` will run // -// // `fclose` will be called on all exit paths by the cleanup instances +// // C++11 style using the factory function +// auto out_closer = absl::MakeCleanup([out_file] { fclose(out_file); }); // // Data data; // while (ReadData(in_file, &data)) { // if (data.IsBad()) { // LOG(ERROR) << "Found bad data."; -// return; // `in_closer` and `out_closer` will call their callbacks +// return; // `in_closer` and `out_closer` will run // } // SaveData(out_file, &data); // } -// return; // `in_closer` and `out_closer` will call their callbacks +// +// // `in_closer` and `out_closer` will run // } // ``` // -// `std::move(cleanup).Invoke()` will execute the callback early, before -// destruction, and prevent the callback from executing in the destructor. +// Methods: // -// Alternatively, `std::move(cleanup).Cancel()` will prevent the callback from -// ever executing at all. +// `std::move(cleanup).Cancel()` will prevent the callback from executing. // -// Once a cleanup object has been `std::move(...)`-ed, it may not be used again. +// `std::move(cleanup).Invoke()` will execute the callback early, before +// destruction, and prevent the callback from executing in the destructor. #ifndef ABSL_CLEANUP_CLEANUP_H_ #define ABSL_CLEANUP_CLEANUP_H_ @@ -101,6 +101,14 @@ class ABSL_MUST_USE_RESULT Cleanup { cleanup_internal::Storage storage_; }; +// `absl::Cleanup c = /* callback */;` +// +// C++17 type deduction API for creating an instance of `absl::Cleanup`. +#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) +template +Cleanup(Callback callback) -> Cleanup; +#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) + // `auto c = absl::MakeCleanup(/* callback */);` // // C++11 type deduction API for creating an instance of `absl::Cleanup`. @@ -115,14 +123,6 @@ absl::Cleanup MakeCleanup(Callback callback) { return {std::move(callback)}; } -// `absl::Cleanup c = /* callback */;` -// -// C++17 type deduction API for creating an instance of `absl::Cleanup`. -#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) -template -Cleanup(Callback callback) -> Cleanup; -#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) - ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/cleanup/cleanup_test.cc b/absl/cleanup/cleanup_test.cc index 34e3bfad..792595d6 100644 --- a/absl/cleanup/cleanup_test.cc +++ b/absl/cleanup/cleanup_test.cc @@ -27,8 +27,8 @@ namespace { using Tag = absl::cleanup_internal::Tag; template -void AssertSameType() { - static_assert(std::is_same::value, ""); +constexpr bool IsSame() { + return (std::is_same::value); } struct IdentityFactory { @@ -88,27 +88,31 @@ template struct CleanupTest : public ::testing::Test {}; TYPED_TEST_SUITE(CleanupTest, CleanupTestParams); -bool function_pointer_called = false; -void FunctionPointerFunction() { function_pointer_called = true; } +bool fn_ptr_called = false; +void FnPtrFunction() { fn_ptr_called = true; } TYPED_TEST(CleanupTest, FactoryProducesCorrectType) { { auto callback = TypeParam::AsCallback([] {}); auto cleanup = absl::MakeCleanup(std::move(callback)); - AssertSameType, decltype(cleanup)>(); + static_assert( + IsSame, decltype(cleanup)>(), + ""); } { - auto cleanup = absl::MakeCleanup(&FunctionPointerFunction); + auto cleanup = absl::MakeCleanup(&FnPtrFunction); - AssertSameType, decltype(cleanup)>(); + static_assert(IsSame, decltype(cleanup)>(), + ""); } { - auto cleanup = absl::MakeCleanup(FunctionPointerFunction); + auto cleanup = absl::MakeCleanup(FnPtrFunction); - AssertSameType, decltype(cleanup)>(); + static_assert(IsSame, decltype(cleanup)>(), + ""); } } @@ -118,19 +122,23 @@ TYPED_TEST(CleanupTest, CTADProducesCorrectType) { auto callback = TypeParam::AsCallback([] {}); absl::Cleanup cleanup = std::move(callback); - AssertSameType, decltype(cleanup)>(); + static_assert( + IsSame, decltype(cleanup)>(), + ""); } { - absl::Cleanup cleanup = &FunctionPointerFunction; + absl::Cleanup cleanup = &FnPtrFunction; - AssertSameType, decltype(cleanup)>(); + static_assert(IsSame, decltype(cleanup)>(), + ""); } { - absl::Cleanup cleanup = FunctionPointerFunction; + absl::Cleanup cleanup = FnPtrFunction; - AssertSameType, decltype(cleanup)>(); + static_assert(IsSame, decltype(cleanup)>(), + ""); } } @@ -140,7 +148,8 @@ TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) { auto factory_cleanup = absl::MakeCleanup(callback); absl::Cleanup deduction_cleanup = callback; - AssertSameType(); + static_assert( + IsSame(), ""); } { @@ -148,7 +157,8 @@ TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) { absl::MakeCleanup(FunctorClassFactory::AsCallback([] {})); absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {}); - AssertSameType(); + static_assert( + IsSame(), ""); } { @@ -156,21 +166,24 @@ TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) { absl::MakeCleanup(StdFunctionFactory::AsCallback([] {})); absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {}); - AssertSameType(); + static_assert( + IsSame(), ""); } { - auto factory_cleanup = absl::MakeCleanup(&FunctionPointerFunction); - absl::Cleanup deduction_cleanup = &FunctionPointerFunction; + auto factory_cleanup = absl::MakeCleanup(&FnPtrFunction); + absl::Cleanup deduction_cleanup = &FnPtrFunction; - AssertSameType(); + static_assert( + IsSame(), ""); } { - auto factory_cleanup = absl::MakeCleanup(FunctionPointerFunction); - absl::Cleanup deduction_cleanup = FunctionPointerFunction; + auto factory_cleanup = absl::MakeCleanup(FnPtrFunction); + absl::Cleanup deduction_cleanup = FnPtrFunction; - AssertSameType(); + static_assert( + IsSame(), ""); } } #endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) @@ -179,62 +192,76 @@ TYPED_TEST(CleanupTest, BasicUsage) { bool called = false; { - EXPECT_FALSE(called); - auto cleanup = absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); - - EXPECT_FALSE(called); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback } - EXPECT_TRUE(called); + EXPECT_TRUE(called); // Destructor should invoke the callback } TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) { - function_pointer_called = false; + fn_ptr_called = false; { - EXPECT_FALSE(function_pointer_called); - - auto cleanup = - absl::MakeCleanup(TypeParam::AsCallback(&FunctionPointerFunction)); - - EXPECT_FALSE(function_pointer_called); + auto cleanup = absl::MakeCleanup(TypeParam::AsCallback(&FnPtrFunction)); + EXPECT_FALSE(fn_ptr_called); // Constructor shouldn't invoke the callback } - EXPECT_TRUE(function_pointer_called); + EXPECT_TRUE(fn_ptr_called); // Destructor should invoke the callback } TYPED_TEST(CleanupTest, Cancel) { bool called = false; { - EXPECT_FALSE(called); - auto cleanup = absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); - std::move(cleanup).Cancel(); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback - EXPECT_FALSE(called); + std::move(cleanup).Cancel(); + EXPECT_FALSE(called); // Cancel shouldn't invoke the callback } - EXPECT_FALSE(called); + EXPECT_FALSE(called); // Destructor shouldn't invoke the callback } TYPED_TEST(CleanupTest, Invoke) { bool called = false; { - EXPECT_FALSE(called); - auto cleanup = absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback + std::move(cleanup).Invoke(); + EXPECT_TRUE(called); // Invoke should invoke the callback + + called = false; // Reset tracker before destructor runs + } + + EXPECT_FALSE(called); // Destructor shouldn't invoke the callback +} + +TYPED_TEST(CleanupTest, Move) { + bool called = false; + + { + auto moved_from_cleanup = + absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback + + { + auto moved_to_cleanup = std::move(moved_from_cleanup); + EXPECT_FALSE(called); // Move shouldn't invoke the callback + } + + EXPECT_TRUE(called); // Destructor should invoke the callback - EXPECT_TRUE(called); + called = false; // Reset tracker before destructor runs } - EXPECT_TRUE(called); + EXPECT_FALSE(called); // Destructor shouldn't invoke the callback } } // namespace diff --git a/absl/cleanup/internal/cleanup.h b/absl/cleanup/internal/cleanup.h index a126ff30..8fbca5bd 100644 --- a/absl/cleanup/internal/cleanup.h +++ b/absl/cleanup/internal/cleanup.h @@ -43,6 +43,8 @@ constexpr bool ReturnsVoid() { template class Storage { public: + Storage() = delete; + explicit Storage(Callback callback) : engaged_(true), callback_(std::move(callback)) {} -- cgit v1.2.3