1*9356374aSAndroid Build Coastguard Worker // Copyright 2021 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker //
15*9356374aSAndroid Build Coastguard Worker // -----------------------------------------------------------------------------
16*9356374aSAndroid Build Coastguard Worker // File: cleanup.h
17*9356374aSAndroid Build Coastguard Worker // -----------------------------------------------------------------------------
18*9356374aSAndroid Build Coastguard Worker //
19*9356374aSAndroid Build Coastguard Worker // `absl::Cleanup` implements the scope guard idiom, invoking the contained
20*9356374aSAndroid Build Coastguard Worker // callback's `operator()() &&` on scope exit.
21*9356374aSAndroid Build Coastguard Worker //
22*9356374aSAndroid Build Coastguard Worker // Example:
23*9356374aSAndroid Build Coastguard Worker //
24*9356374aSAndroid Build Coastguard Worker // ```
25*9356374aSAndroid Build Coastguard Worker // absl::Status CopyGoodData(const char* source_path, const char* sink_path) {
26*9356374aSAndroid Build Coastguard Worker // FILE* source_file = fopen(source_path, "r");
27*9356374aSAndroid Build Coastguard Worker // if (source_file == nullptr) {
28*9356374aSAndroid Build Coastguard Worker // return absl::NotFoundError("No source file"); // No cleanups execute
29*9356374aSAndroid Build Coastguard Worker // }
30*9356374aSAndroid Build Coastguard Worker //
31*9356374aSAndroid Build Coastguard Worker // // C++17 style cleanup using class template argument deduction
32*9356374aSAndroid Build Coastguard Worker // absl::Cleanup source_closer = [source_file] { fclose(source_file); };
33*9356374aSAndroid Build Coastguard Worker //
34*9356374aSAndroid Build Coastguard Worker // FILE* sink_file = fopen(sink_path, "w");
35*9356374aSAndroid Build Coastguard Worker // if (sink_file == nullptr) {
36*9356374aSAndroid Build Coastguard Worker // return absl::NotFoundError("No sink file"); // First cleanup executes
37*9356374aSAndroid Build Coastguard Worker // }
38*9356374aSAndroid Build Coastguard Worker //
39*9356374aSAndroid Build Coastguard Worker // // C++11 style cleanup using the factory function
40*9356374aSAndroid Build Coastguard Worker // auto sink_closer = absl::MakeCleanup([sink_file] { fclose(sink_file); });
41*9356374aSAndroid Build Coastguard Worker //
42*9356374aSAndroid Build Coastguard Worker // Data data;
43*9356374aSAndroid Build Coastguard Worker // while (ReadData(source_file, &data)) {
44*9356374aSAndroid Build Coastguard Worker // if (!data.IsGood()) {
45*9356374aSAndroid Build Coastguard Worker // absl::Status result = absl::FailedPreconditionError("Read bad data");
46*9356374aSAndroid Build Coastguard Worker // return result; // Both cleanups execute
47*9356374aSAndroid Build Coastguard Worker // }
48*9356374aSAndroid Build Coastguard Worker // SaveData(sink_file, &data);
49*9356374aSAndroid Build Coastguard Worker // }
50*9356374aSAndroid Build Coastguard Worker //
51*9356374aSAndroid Build Coastguard Worker // return absl::OkStatus(); // Both cleanups execute
52*9356374aSAndroid Build Coastguard Worker // }
53*9356374aSAndroid Build Coastguard Worker // ```
54*9356374aSAndroid Build Coastguard Worker //
55*9356374aSAndroid Build Coastguard Worker // Methods:
56*9356374aSAndroid Build Coastguard Worker //
57*9356374aSAndroid Build Coastguard Worker // `std::move(cleanup).Cancel()` will prevent the callback from executing.
58*9356374aSAndroid Build Coastguard Worker //
59*9356374aSAndroid Build Coastguard Worker // `std::move(cleanup).Invoke()` will execute the callback early, before
60*9356374aSAndroid Build Coastguard Worker // destruction, and prevent the callback from executing in the destructor.
61*9356374aSAndroid Build Coastguard Worker //
62*9356374aSAndroid Build Coastguard Worker // Usage:
63*9356374aSAndroid Build Coastguard Worker //
64*9356374aSAndroid Build Coastguard Worker // `absl::Cleanup` is not an interface type. It is only intended to be used
65*9356374aSAndroid Build Coastguard Worker // within the body of a function. It is not a value type and instead models a
66*9356374aSAndroid Build Coastguard Worker // control flow construct. Check out `defer` in Golang for something similar.
67*9356374aSAndroid Build Coastguard Worker
68*9356374aSAndroid Build Coastguard Worker #ifndef ABSL_CLEANUP_CLEANUP_H_
69*9356374aSAndroid Build Coastguard Worker #define ABSL_CLEANUP_CLEANUP_H_
70*9356374aSAndroid Build Coastguard Worker
71*9356374aSAndroid Build Coastguard Worker #include <utility>
72*9356374aSAndroid Build Coastguard Worker
73*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h"
74*9356374aSAndroid Build Coastguard Worker #include "absl/base/macros.h"
75*9356374aSAndroid Build Coastguard Worker #include "absl/cleanup/internal/cleanup.h"
76*9356374aSAndroid Build Coastguard Worker
77*9356374aSAndroid Build Coastguard Worker namespace absl {
78*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
79*9356374aSAndroid Build Coastguard Worker
80*9356374aSAndroid Build Coastguard Worker template <typename Arg, typename Callback = void()>
81*9356374aSAndroid Build Coastguard Worker class ABSL_MUST_USE_RESULT Cleanup final {
82*9356374aSAndroid Build Coastguard Worker static_assert(cleanup_internal::WasDeduced<Arg>(),
83*9356374aSAndroid Build Coastguard Worker "Explicit template parameters are not supported.");
84*9356374aSAndroid Build Coastguard Worker
85*9356374aSAndroid Build Coastguard Worker static_assert(cleanup_internal::ReturnsVoid<Callback>(),
86*9356374aSAndroid Build Coastguard Worker "Callbacks that return values are not supported.");
87*9356374aSAndroid Build Coastguard Worker
88*9356374aSAndroid Build Coastguard Worker public:
Cleanup(Callback callback)89*9356374aSAndroid Build Coastguard Worker Cleanup(Callback callback) : storage_(std::move(callback)) {} // NOLINT
90*9356374aSAndroid Build Coastguard Worker
91*9356374aSAndroid Build Coastguard Worker Cleanup(Cleanup&& other) = default;
92*9356374aSAndroid Build Coastguard Worker
Cancel()93*9356374aSAndroid Build Coastguard Worker void Cancel() && {
94*9356374aSAndroid Build Coastguard Worker ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
95*9356374aSAndroid Build Coastguard Worker storage_.DestroyCallback();
96*9356374aSAndroid Build Coastguard Worker }
97*9356374aSAndroid Build Coastguard Worker
Invoke()98*9356374aSAndroid Build Coastguard Worker void Invoke() && {
99*9356374aSAndroid Build Coastguard Worker ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
100*9356374aSAndroid Build Coastguard Worker storage_.InvokeCallback();
101*9356374aSAndroid Build Coastguard Worker storage_.DestroyCallback();
102*9356374aSAndroid Build Coastguard Worker }
103*9356374aSAndroid Build Coastguard Worker
~Cleanup()104*9356374aSAndroid Build Coastguard Worker ~Cleanup() {
105*9356374aSAndroid Build Coastguard Worker if (storage_.IsCallbackEngaged()) {
106*9356374aSAndroid Build Coastguard Worker storage_.InvokeCallback();
107*9356374aSAndroid Build Coastguard Worker storage_.DestroyCallback();
108*9356374aSAndroid Build Coastguard Worker }
109*9356374aSAndroid Build Coastguard Worker }
110*9356374aSAndroid Build Coastguard Worker
111*9356374aSAndroid Build Coastguard Worker private:
112*9356374aSAndroid Build Coastguard Worker cleanup_internal::Storage<Callback> storage_;
113*9356374aSAndroid Build Coastguard Worker };
114*9356374aSAndroid Build Coastguard Worker
115*9356374aSAndroid Build Coastguard Worker // `absl::Cleanup c = /* callback */;`
116*9356374aSAndroid Build Coastguard Worker //
117*9356374aSAndroid Build Coastguard Worker // C++17 type deduction API for creating an instance of `absl::Cleanup`
118*9356374aSAndroid Build Coastguard Worker #if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
119*9356374aSAndroid Build Coastguard Worker template <typename Callback>
120*9356374aSAndroid Build Coastguard Worker Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>;
121*9356374aSAndroid Build Coastguard Worker #endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
122*9356374aSAndroid Build Coastguard Worker
123*9356374aSAndroid Build Coastguard Worker // `auto c = absl::MakeCleanup(/* callback */);`
124*9356374aSAndroid Build Coastguard Worker //
125*9356374aSAndroid Build Coastguard Worker // C++11 type deduction API for creating an instance of `absl::Cleanup`
126*9356374aSAndroid Build Coastguard Worker template <typename... Args, typename Callback>
MakeCleanup(Callback callback)127*9356374aSAndroid Build Coastguard Worker absl::Cleanup<cleanup_internal::Tag, Callback> MakeCleanup(Callback callback) {
128*9356374aSAndroid Build Coastguard Worker static_assert(cleanup_internal::WasDeduced<cleanup_internal::Tag, Args...>(),
129*9356374aSAndroid Build Coastguard Worker "Explicit template parameters are not supported.");
130*9356374aSAndroid Build Coastguard Worker
131*9356374aSAndroid Build Coastguard Worker static_assert(cleanup_internal::ReturnsVoid<Callback>(),
132*9356374aSAndroid Build Coastguard Worker "Callbacks that return values are not supported.");
133*9356374aSAndroid Build Coastguard Worker
134*9356374aSAndroid Build Coastguard Worker return {std::move(callback)};
135*9356374aSAndroid Build Coastguard Worker }
136*9356374aSAndroid Build Coastguard Worker
137*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
138*9356374aSAndroid Build Coastguard Worker } // namespace absl
139*9356374aSAndroid Build Coastguard Worker
140*9356374aSAndroid Build Coastguard Worker #endif // ABSL_CLEANUP_CLEANUP_H_
141