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(-) 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