You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

cleanup.h 4.9 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. #ifndef ABSL_CLEANUP_CLEANUP_H_
  68. #define ABSL_CLEANUP_CLEANUP_H_
  69. #include <utility>
  70. #include "absl/base/config.h"
  71. #include "absl/base/macros.h"
  72. #include "absl/cleanup/internal/cleanup.h"
  73. namespace absl
  74. {
  75. ABSL_NAMESPACE_BEGIN
  76. template<typename Arg, typename Callback = void()>
  77. class ABSL_MUST_USE_RESULT Cleanup final
  78. {
  79. static_assert(cleanup_internal::WasDeduced<Arg>(), "Explicit template parameters are not supported.");
  80. static_assert(cleanup_internal::ReturnsVoid<Callback>(), "Callbacks that return values are not supported.");
  81. public:
  82. Cleanup(Callback callback) :
  83. storage_(std::move(callback))
  84. {
  85. } // NOLINT
  86. Cleanup(Cleanup&& other) = default;
  87. void Cancel() &&
  88. {
  89. ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
  90. storage_.DestroyCallback();
  91. }
  92. void Invoke() &&
  93. {
  94. ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
  95. storage_.InvokeCallback();
  96. storage_.DestroyCallback();
  97. }
  98. ~Cleanup()
  99. {
  100. if (storage_.IsCallbackEngaged())
  101. {
  102. storage_.InvokeCallback();
  103. storage_.DestroyCallback();
  104. }
  105. }
  106. private:
  107. cleanup_internal::Storage<Callback> storage_;
  108. };
  109. // `absl::Cleanup c = /* callback */;`
  110. //
  111. // C++17 type deduction API for creating an instance of `absl::Cleanup`
  112. #if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
  113. template<typename Callback>
  114. Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>;
  115. #endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
  116. // `auto c = absl::MakeCleanup(/* callback */);`
  117. //
  118. // C++11 type deduction API for creating an instance of `absl::Cleanup`
  119. template<typename... Args, typename Callback>
  120. absl::Cleanup<cleanup_internal::Tag, Callback> MakeCleanup(Callback callback)
  121. {
  122. static_assert(cleanup_internal::WasDeduced<cleanup_internal::Tag, Args...>(), "Explicit template parameters are not supported.");
  123. static_assert(cleanup_internal::ReturnsVoid<Callback>(), "Callbacks that return values are not supported.");
  124. return {std::move(callback)};
  125. }
  126. ABSL_NAMESPACE_END
  127. } // namespace absl
  128. #endif // ABSL_CLEANUP_CLEANUP_H_