proxygen
ScopeGuard.h
Go to the documentation of this file.
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 
17 #pragma once
18 
19 #include <cstddef>
20 #include <cstdlib>
21 #include <functional>
22 #include <new>
23 #include <type_traits>
24 #include <utility>
25 
26 #include <folly/Portability.h>
27 #include <folly/Preprocessor.h>
28 #include <folly/Utility.h>
30 
31 namespace folly {
32 
33 namespace detail {
34 
36  public:
37  void dismiss() noexcept {
38  dismissed_ = true;
39  }
40 
41  protected:
43 
44  static void warnAboutToCrash() noexcept;
46  return ScopeGuardImplBase{};
47  }
48 
49  template <typename T>
50  static const T& asConst(const T& t) noexcept {
51  return t;
52  }
53 
54  bool dismissed_;
55 };
56 
57 template <typename FunctionType, bool InvokeNoexcept>
59  public:
60  explicit ScopeGuardImpl(FunctionType& fn) noexcept(
63  asConst(fn),
64  makeFailsafe(
65  std::is_nothrow_copy_constructible<FunctionType>{},
66  &fn)) {}
67 
68  explicit ScopeGuardImpl(const FunctionType& fn) noexcept(
71  fn,
72  makeFailsafe(
73  std::is_nothrow_copy_constructible<FunctionType>{},
74  &fn)) {}
75 
76  explicit ScopeGuardImpl(FunctionType&& fn) noexcept(
77  std::is_nothrow_move_constructible<FunctionType>::value)
79  std::move_if_noexcept(fn),
80  makeFailsafe(
81  std::is_nothrow_move_constructible<FunctionType>{},
82  &fn)) {}
83 
85  std::is_nothrow_move_constructible<FunctionType>::value)
86  : function_(std::move_if_noexcept(other.function_)) {
87  // If the above line attempts a copy and the copy throws, other is
88  // left owning the cleanup action and will execute it (or not) depending
89  // on the value of other.dismissed_. The following lines only execute
90  // if the move/copy succeeded, in which case *this assumes ownership of
91  // the cleanup action and dismisses other.
92  dismissed_ = exchange(other.dismissed_, true);
93  }
94 
95  ~ScopeGuardImpl() noexcept(InvokeNoexcept) {
96  if (!dismissed_) {
97  execute();
98  }
99  }
100 
101  private:
103  return makeEmptyScopeGuard();
104  }
105 
106  template <typename Fn>
107  static auto makeFailsafe(std::false_type, Fn* fn) noexcept
110  std::ref(*fn)};
111  }
112 
113  template <typename Fn>
114  explicit ScopeGuardImpl(Fn&& fn, ScopeGuardImplBase&& failsafe)
115  : ScopeGuardImplBase{}, function_(std::forward<Fn>(fn)) {
116  failsafe.dismiss();
117  }
118 
119  void* operator new(std::size_t) = delete;
120 
121  void execute() noexcept(InvokeNoexcept) {
122  if (InvokeNoexcept) {
123  try {
124  function_();
125  } catch (...) {
127  std::terminate();
128  }
129  } else {
130  function_();
131  }
132  }
133 
134  FunctionType function_;
135 };
136 
137 template <typename F, bool INE>
139 
140 } // namespace detail
141 
183 template <typename F>
185  noexcept(detail::ScopeGuardImplDecay<F, true>(static_cast<F&&>(f)))) {
186  return detail::ScopeGuardImplDecay<F, true>(static_cast<F&&>(f));
187 }
188 
189 namespace detail {
190 
191 #if defined(FOLLY_EXCEPTION_COUNT_USE_CXA_GET_GLOBALS) || \
192  defined(FOLLY_EXCEPTION_COUNT_USE_GETPTD) || \
193  defined(FOLLY_EXCEPTION_COUNT_USE_STD)
194 
206 template <typename FunctionType, bool ExecuteOnException>
207 class ScopeGuardForNewException {
208  public:
209  explicit ScopeGuardForNewException(const FunctionType& fn) : guard_(fn) {}
210 
211  explicit ScopeGuardForNewException(FunctionType&& fn)
212  : guard_(std::move(fn)) {}
213 
214  ScopeGuardForNewException(ScopeGuardForNewException&& other) = default;
215 
216  ~ScopeGuardForNewException() noexcept(ExecuteOnException) {
217  if (ExecuteOnException != (exceptionCounter_ < uncaught_exceptions())) {
218  guard_.dismiss();
219  }
220  }
221 
222  private:
223  void* operator new(std::size_t) = delete;
224  void operator delete(void*) = delete;
225 
227  int exceptionCounter_{uncaught_exceptions()};
228 };
229 
233 enum class ScopeGuardOnFail {};
234 
235 template <typename FunctionType>
237 operator+(detail::ScopeGuardOnFail, FunctionType&& fn) {
238  return ScopeGuardForNewException<
240  true>(std::forward<FunctionType>(fn));
241 }
242 
246 enum class ScopeGuardOnSuccess {};
247 
248 template <typename FunctionType>
250 operator+(ScopeGuardOnSuccess, FunctionType&& fn) {
251  return ScopeGuardForNewException<
253  false>(std::forward<FunctionType>(fn));
254 }
255 
256 #endif // native uncaught_exception() supported
257 
261 enum class ScopeGuardOnExit {};
262 
263 template <typename FunctionType>
266  FunctionType&& fn) {
268  std::forward<FunctionType>(fn));
269 }
270 } // namespace detail
271 
272 } // namespace folly
273 
274 #define SCOPE_EXIT \
275  auto FB_ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) = \
276  ::folly::detail::ScopeGuardOnExit() + [&]() noexcept
277 
278 #if defined(FOLLY_EXCEPTION_COUNT_USE_CXA_GET_GLOBALS) || \
279  defined(FOLLY_EXCEPTION_COUNT_USE_GETPTD) || \
280  defined(FOLLY_EXCEPTION_COUNT_USE_STD)
281 #define SCOPE_FAIL \
282  auto FB_ANONYMOUS_VARIABLE(SCOPE_FAIL_STATE) = \
283  ::folly::detail::ScopeGuardOnFail() + [&]() noexcept
284 
285 #define SCOPE_SUCCESS \
286  auto FB_ANONYMOUS_VARIABLE(SCOPE_SUCCESS_STATE) = \
287  ::folly::detail::ScopeGuardOnSuccess() + [&]()
288 #endif // native uncaught_exception() supported
auto f
ScopeGuardImpl(ScopeGuardImpl &&other) noexcept(std::is_nothrow_move_constructible< FunctionType >::value)
Definition: ScopeGuard.h:84
#define FOLLY_NODISCARD
Definition: Portability.h:64
PskType type
static void warnAboutToCrash() noexcept
Definition: ScopeGuard.cpp:21
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
static ScopeGuardImplBase makeEmptyScopeGuard() noexcept
Definition: ScopeGuard.h:45
STL namespace.
ScopeGuardImpl(Fn &&fn, ScopeGuardImplBase &&failsafe)
Definition: ScopeGuard.h:114
folly::std T
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
bool_constant< true > true_type
Definition: gtest-port.h:2210
ScopeGuardImpl< typename std::decay< FunctionType >::type, true > operator+(detail::ScopeGuardOnExit, FunctionType &&fn)
Definition: ScopeGuard.h:264
int uncaught_exceptions() noexcept
static ScopeGuardImplBase makeFailsafe(std::true_type, const void *) noexcept
Definition: ScopeGuard.h:102
~ScopeGuardImpl() noexcept(InvokeNoexcept)
Definition: ScopeGuard.h:95
void execute() noexcept(InvokeNoexcept)
Definition: ScopeGuard.h:121
static const T & asConst(const T &t) noexcept
Definition: ScopeGuard.h:50
static const char *const value
Definition: Conv.cpp:50
static auto makeFailsafe(std::false_type, Fn *fn) noexcept-> ScopeGuardImpl< decltype(std::ref(*fn)), InvokeNoexcept >
Definition: ScopeGuard.h:107
ScopeGuardImpl(FunctionType &fn) noexcept(std::is_nothrow_copy_constructible< FunctionType >::value)
Definition: ScopeGuard.h:60
FOLLY_NODISCARD detail::ScopeGuardImplDecay< F, true > makeGuard(F &&f) noexcept(noexcept(detail::ScopeGuardImplDecay< F, true >(static_cast< F && >(f))))
Definition: ScopeGuard.h:184
T exchange(T &obj, U &&new_value)
Definition: Utility.h:120
ScopeGuardImpl(const FunctionType &fn) noexcept(std::is_nothrow_copy_constructible< FunctionType >::value)
Definition: ScopeGuard.h:68
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
bool_constant< false > false_type
Definition: gtest-port.h:2209
ScopeGuardImpl(FunctionType &&fn) noexcept(std::is_nothrow_move_constructible< FunctionType >::value)
Definition: ScopeGuard.h:76