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