ScopeGuard.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. * Copyright 2011-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <cstddef>
  18. #include <cstdlib>
  19. #include <functional>
  20. #include <new>
  21. #include <type_traits>
  22. #include <utility>
  23. #include <folly/Portability.h>
  24. #include <folly/Preprocessor.h>
  25. #include <folly/Utility.h>
  26. #include <folly/lang/UncaughtExceptions.h>
  27. namespace folly {
  28. namespace detail {
  29. class ScopeGuardImplBase {
  30. public:
  31. void dismiss() noexcept {
  32. dismissed_ = true;
  33. }
  34. protected:
  35. ScopeGuardImplBase() noexcept : dismissed_(false) {}
  36. static void warnAboutToCrash() noexcept;
  37. static ScopeGuardImplBase makeEmptyScopeGuard() noexcept {
  38. return ScopeGuardImplBase{};
  39. }
  40. template <typename T>
  41. static const T& asConst(const T& t) noexcept {
  42. return t;
  43. }
  44. bool dismissed_;
  45. };
  46. template <typename FunctionType, bool InvokeNoexcept>
  47. class ScopeGuardImpl : public ScopeGuardImplBase {
  48. public:
  49. explicit ScopeGuardImpl(FunctionType& fn) noexcept(
  50. std::is_nothrow_copy_constructible<FunctionType>::value)
  51. : ScopeGuardImpl(
  52. asConst(fn),
  53. makeFailsafe(
  54. std::is_nothrow_copy_constructible<FunctionType>{},
  55. &fn)) {}
  56. explicit ScopeGuardImpl(const FunctionType& fn) noexcept(
  57. std::is_nothrow_copy_constructible<FunctionType>::value)
  58. : ScopeGuardImpl(
  59. fn,
  60. makeFailsafe(
  61. std::is_nothrow_copy_constructible<FunctionType>{},
  62. &fn)) {}
  63. explicit ScopeGuardImpl(FunctionType&& fn) noexcept(
  64. std::is_nothrow_move_constructible<FunctionType>::value)
  65. : ScopeGuardImpl(
  66. std::move_if_noexcept(fn),
  67. makeFailsafe(
  68. std::is_nothrow_move_constructible<FunctionType>{},
  69. &fn)) {}
  70. ScopeGuardImpl(ScopeGuardImpl&& other) noexcept(
  71. std::is_nothrow_move_constructible<FunctionType>::value)
  72. : function_(std::move_if_noexcept(other.function_)) {
  73. // If the above line attempts a copy and the copy throws, other is
  74. // left owning the cleanup action and will execute it (or not) depending
  75. // on the value of other.dismissed_. The following lines only execute
  76. // if the move/copy succeeded, in which case *this assumes ownership of
  77. // the cleanup action and dismisses other.
  78. dismissed_ = exchange(other.dismissed_, true);
  79. }
  80. ~ScopeGuardImpl() noexcept(InvokeNoexcept) {
  81. if (!dismissed_) {
  82. execute();
  83. }
  84. }
  85. private:
  86. static ScopeGuardImplBase makeFailsafe(std::true_type, const void*) noexcept {
  87. return makeEmptyScopeGuard();
  88. }
  89. template <typename Fn>
  90. static auto makeFailsafe(std::false_type, Fn* fn) noexcept
  91. -> ScopeGuardImpl<decltype(std::ref(*fn)), InvokeNoexcept> {
  92. return ScopeGuardImpl<decltype(std::ref(*fn)), InvokeNoexcept>{
  93. std::ref(*fn)};
  94. }
  95. template <typename Fn>
  96. explicit ScopeGuardImpl(Fn&& fn, ScopeGuardImplBase&& failsafe)
  97. : ScopeGuardImplBase{}, function_(std::forward<Fn>(fn)) {
  98. failsafe.dismiss();
  99. }
  100. void* operator new(std::size_t) = delete;
  101. void execute() noexcept(InvokeNoexcept) {
  102. if (InvokeNoexcept) {
  103. try {
  104. function_();
  105. } catch (...) {
  106. warnAboutToCrash();
  107. std::terminate();
  108. }
  109. } else {
  110. function_();
  111. }
  112. }
  113. FunctionType function_;
  114. };
  115. template <typename F, bool INE>
  116. using ScopeGuardImplDecay = ScopeGuardImpl<typename std::decay<F>::type, INE>;
  117. } // namespace detail
  118. /**
  119. * ScopeGuard is a general implementation of the "Initialization is
  120. * Resource Acquisition" idiom. Basically, it guarantees that a function
  121. * is executed upon leaving the currrent scope unless otherwise told.
  122. *
  123. * The makeGuard() function is used to create a new ScopeGuard object.
  124. * It can be instantiated with a lambda function, a std::function<void()>,
  125. * a functor, or a void(*)() function pointer.
  126. *
  127. *
  128. * Usage example: Add a friend to memory if and only if it is also added
  129. * to the db.
  130. *
  131. * void User::addFriend(User& newFriend) {
  132. * // add the friend to memory
  133. * friends_.push_back(&newFriend);
  134. *
  135. * // If the db insertion that follows fails, we should
  136. * // remove it from memory.
  137. * auto guard = makeGuard([&] { friends_.pop_back(); });
  138. *
  139. * // this will throw an exception upon error, which
  140. * // makes the ScopeGuard execute UserCont::pop_back()
  141. * // once the Guard's destructor is called.
  142. * db_->addFriend(GetName(), newFriend.GetName());
  143. *
  144. * // an exception was not thrown, so don't execute
  145. * // the Guard.
  146. * guard.dismiss();
  147. * }
  148. *
  149. * Examine ScopeGuardTest.cpp for some more sample usage.
  150. *
  151. * Stolen from:
  152. * Andrei's and Petru Marginean's CUJ article:
  153. * http://drdobbs.com/184403758
  154. * and the loki library:
  155. * http://loki-lib.sourceforge.net/index.php?n=Idioms.ScopeGuardPointer
  156. * and triendl.kj article:
  157. * http://www.codeproject.com/KB/cpp/scope_guard.aspx
  158. */
  159. template <typename F>
  160. detail::ScopeGuardImplDecay<F, true> makeGuard(F&& f) noexcept(
  161. noexcept(detail::ScopeGuardImplDecay<F, true>(static_cast<F&&>(f)))) {
  162. return detail::ScopeGuardImplDecay<F, true>(static_cast<F&&>(f));
  163. }
  164. namespace detail {
  165. #if defined(FOLLY_EXCEPTION_COUNT_USE_CXA_GET_GLOBALS) || \
  166. defined(FOLLY_EXCEPTION_COUNT_USE_GETPTD) || \
  167. defined(FOLLY_EXCEPTION_COUNT_USE_STD)
  168. /**
  169. * ScopeGuard used for executing a function when leaving the current scope
  170. * depending on the presence of a new uncaught exception.
  171. *
  172. * If the executeOnException template parameter is true, the function is
  173. * executed if a new uncaught exception is present at the end of the scope.
  174. * If the parameter is false, then the function is executed if no new uncaught
  175. * exceptions are present at the end of the scope.
  176. *
  177. * Used to implement SCOPE_FAIL and SCOPE_SUCCESS below.
  178. */
  179. template <typename FunctionType, bool ExecuteOnException>
  180. class ScopeGuardForNewException {
  181. public:
  182. explicit ScopeGuardForNewException(const FunctionType& fn) : guard_(fn) {}
  183. explicit ScopeGuardForNewException(FunctionType&& fn)
  184. : guard_(std::move(fn)) {}
  185. ScopeGuardForNewException(ScopeGuardForNewException&& other) = default;
  186. ~ScopeGuardForNewException() noexcept(ExecuteOnException) {
  187. if (ExecuteOnException != (exceptionCounter_ < uncaught_exceptions())) {
  188. guard_.dismiss();
  189. }
  190. }
  191. private:
  192. void* operator new(std::size_t) = delete;
  193. void operator delete(void*) = delete;
  194. ScopeGuardImpl<FunctionType, ExecuteOnException> guard_;
  195. int exceptionCounter_{uncaught_exceptions()};
  196. };
  197. /**
  198. * Internal use for the macro SCOPE_FAIL below
  199. */
  200. enum class ScopeGuardOnFail {};
  201. template <typename FunctionType>
  202. ScopeGuardForNewException<typename std::decay<FunctionType>::type, true>
  203. operator+(detail::ScopeGuardOnFail, FunctionType&& fn) {
  204. return ScopeGuardForNewException<
  205. typename std::decay<FunctionType>::type,
  206. true>(std::forward<FunctionType>(fn));
  207. }
  208. /**
  209. * Internal use for the macro SCOPE_SUCCESS below
  210. */
  211. enum class ScopeGuardOnSuccess {};
  212. template <typename FunctionType>
  213. ScopeGuardForNewException<typename std::decay<FunctionType>::type, false>
  214. operator+(ScopeGuardOnSuccess, FunctionType&& fn) {
  215. return ScopeGuardForNewException<
  216. typename std::decay<FunctionType>::type,
  217. false>(std::forward<FunctionType>(fn));
  218. }
  219. #endif // native uncaught_exception() supported
  220. /**
  221. * Internal use for the macro SCOPE_EXIT below
  222. */
  223. enum class ScopeGuardOnExit {};
  224. template <typename FunctionType>
  225. ScopeGuardImpl<typename std::decay<FunctionType>::type, true> operator+(
  226. detail::ScopeGuardOnExit,
  227. FunctionType&& fn) {
  228. return ScopeGuardImpl<typename std::decay<FunctionType>::type, true>(
  229. std::forward<FunctionType>(fn));
  230. }
  231. } // namespace detail
  232. } // namespace folly
  233. #define SCOPE_EXIT \
  234. auto FB_ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) = \
  235. ::folly::detail::ScopeGuardOnExit() + [&]() noexcept
  236. #if defined(FOLLY_EXCEPTION_COUNT_USE_CXA_GET_GLOBALS) || \
  237. defined(FOLLY_EXCEPTION_COUNT_USE_GETPTD) || \
  238. defined(FOLLY_EXCEPTION_COUNT_USE_STD)
  239. #define SCOPE_FAIL \
  240. auto FB_ANONYMOUS_VARIABLE(SCOPE_FAIL_STATE) = \
  241. ::folly::detail::ScopeGuardOnFail() + [&]() noexcept
  242. #define SCOPE_SUCCESS \
  243. auto FB_ANONYMOUS_VARIABLE(SCOPE_SUCCESS_STATE) = \
  244. ::folly::detail::ScopeGuardOnSuccess() + [&]()
  245. #endif // native uncaught_exception() supported