Export of internal Abseil changes

--
8c77b14bdee3f4cafb8ba520d4d050b15a949fd4 by Derek Mauro <dmauro@google.com>:

Fix absl::Cleanup usage example

PiperOrigin-RevId: 354702001

--
10365da7a0aacaa0c4774a4b618a76dff328611b by CJ Johnson <johnsoncj@google.com>:

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
pull/898/head
Abseil Team 4 years ago committed by Derek Mauro
parent a9a4956020
commit 184d2f8364
  1. 42
      absl/cleanup/cleanup.h
  2. 117
      absl/cleanup/cleanup_test.cc
  3. 2
      absl/cleanup/internal/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<Callback> 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 <typename Callback>
Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>;
#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<cleanup_internal::Tag, Callback> 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 <typename Callback>
Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>;
#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
ABSL_NAMESPACE_END
} // namespace absl

@ -27,8 +27,8 @@ namespace {
using Tag = absl::cleanup_internal::Tag;
template <typename Type1, typename Type2>
void AssertSameType() {
static_assert(std::is_same<Type1, Type2>::value, "");
constexpr bool IsSame() {
return (std::is_same<Type1, Type2>::value);
}
struct IdentityFactory {
@ -88,27 +88,31 @@ template <typename>
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<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>();
static_assert(
IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
"");
}
{
auto cleanup = absl::MakeCleanup(&FunctionPointerFunction);
auto cleanup = absl::MakeCleanup(&FnPtrFunction);
AssertSameType<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>();
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
"");
}
{
auto cleanup = absl::MakeCleanup(FunctionPointerFunction);
auto cleanup = absl::MakeCleanup(FnPtrFunction);
AssertSameType<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>();
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
"");
}
}
@ -118,19 +122,23 @@ TYPED_TEST(CleanupTest, CTADProducesCorrectType) {
auto callback = TypeParam::AsCallback([] {});
absl::Cleanup cleanup = std::move(callback);
AssertSameType<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>();
static_assert(
IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
"");
}
{
absl::Cleanup cleanup = &FunctionPointerFunction;
absl::Cleanup cleanup = &FnPtrFunction;
AssertSameType<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>();
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
"");
}
{
absl::Cleanup cleanup = FunctionPointerFunction;
absl::Cleanup cleanup = FnPtrFunction;
AssertSameType<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>();
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
"");
}
}
@ -140,7 +148,8 @@ TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) {
auto factory_cleanup = absl::MakeCleanup(callback);
absl::Cleanup deduction_cleanup = callback;
AssertSameType<decltype(factory_cleanup), decltype(deduction_cleanup)>();
static_assert(
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
}
{
@ -148,7 +157,8 @@ TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) {
absl::MakeCleanup(FunctorClassFactory::AsCallback([] {}));
absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {});
AssertSameType<decltype(factory_cleanup), decltype(deduction_cleanup)>();
static_assert(
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
}
{
@ -156,21 +166,24 @@ TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) {
absl::MakeCleanup(StdFunctionFactory::AsCallback([] {}));
absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {});
AssertSameType<decltype(factory_cleanup), decltype(deduction_cleanup)>();
static_assert(
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
}
{
auto factory_cleanup = absl::MakeCleanup(&FunctionPointerFunction);
absl::Cleanup deduction_cleanup = &FunctionPointerFunction;
auto factory_cleanup = absl::MakeCleanup(&FnPtrFunction);
absl::Cleanup deduction_cleanup = &FnPtrFunction;
AssertSameType<decltype(factory_cleanup), decltype(deduction_cleanup)>();
static_assert(
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
}
{
auto factory_cleanup = absl::MakeCleanup(FunctionPointerFunction);
absl::Cleanup deduction_cleanup = FunctionPointerFunction;
auto factory_cleanup = absl::MakeCleanup(FnPtrFunction);
absl::Cleanup deduction_cleanup = FnPtrFunction;
AssertSameType<decltype(factory_cleanup), decltype(deduction_cleanup)>();
static_assert(
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
}
}
#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

@ -43,6 +43,8 @@ constexpr bool ReturnsVoid() {
template <typename Callback>
class Storage {
public:
Storage() = delete;
explicit Storage(Callback callback)
: engaged_(true), callback_(std::move(callback)) {}

Loading…
Cancel
Save