Improve performance of enumerate() with optimization disabled
[folly.git] / folly / ScopeGuard.h
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 <functional>
21 #include <new>
22 #include <type_traits>
23 #include <utility>
24
25 #include <folly/Portability.h>
26 #include <folly/Preprocessor.h>
27 #include <folly/UncaughtExceptions.h>
28
29 namespace folly {
30
31 /**
32  * ScopeGuard is a general implementation of the "Initialization is
33  * Resource Acquisition" idiom.  Basically, it guarantees that a function
34  * is executed upon leaving the currrent scope unless otherwise told.
35  *
36  * The makeGuard() function is used to create a new ScopeGuard object.
37  * It can be instantiated with a lambda function, a std::function<void()>,
38  * a functor, or a void(*)() function pointer.
39  *
40  *
41  * Usage example: Add a friend to memory if and only if it is also added
42  * to the db.
43  *
44  * void User::addFriend(User& newFriend) {
45  *   // add the friend to memory
46  *   friends_.push_back(&newFriend);
47  *
48  *   // If the db insertion that follows fails, we should
49  *   // remove it from memory.
50  *   auto guard = makeGuard([&] { friends_.pop_back(); });
51  *
52  *   // this will throw an exception upon error, which
53  *   // makes the ScopeGuard execute UserCont::pop_back()
54  *   // once the Guard's destructor is called.
55  *   db_->addFriend(GetName(), newFriend.GetName());
56  *
57  *   // an exception was not thrown, so don't execute
58  *   // the Guard.
59  *   guard.dismiss();
60  * }
61  *
62  * Examine ScopeGuardTest.cpp for some more sample usage.
63  *
64  * Stolen from:
65  *   Andrei's and Petru Marginean's CUJ article:
66  *     http://drdobbs.com/184403758
67  *   and the loki library:
68  *     http://loki-lib.sourceforge.net/index.php?n=Idioms.ScopeGuardPointer
69  *   and triendl.kj article:
70  *     http://www.codeproject.com/KB/cpp/scope_guard.aspx
71  */
72 class ScopeGuardImplBase {
73  public:
74   void dismiss() noexcept {
75     dismissed_ = true;
76   }
77
78   template <typename T>
79   FOLLY_ALWAYS_INLINE static void runAndWarnAboutToCrashOnException(
80       T& function) noexcept {
81     try {
82       function();
83     } catch (...) {
84       warnAboutToCrash();
85       std::terminate();
86     }
87   }
88
89  protected:
90   ScopeGuardImplBase() noexcept : dismissed_(false) {}
91
92   static ScopeGuardImplBase makeEmptyScopeGuard() noexcept {
93     return ScopeGuardImplBase{};
94   }
95
96   template <typename T>
97   static const T& asConst(const T& t) noexcept {
98     return t;
99   }
100
101   bool dismissed_;
102
103  private:
104   static void warnAboutToCrash() noexcept;
105 };
106
107 template <typename FunctionType>
108 class ScopeGuardImpl : public ScopeGuardImplBase {
109  public:
110   explicit ScopeGuardImpl(FunctionType& fn) noexcept(
111       std::is_nothrow_copy_constructible<FunctionType>::value)
112       : ScopeGuardImpl(
113             asConst(fn),
114             makeFailsafe(std::is_nothrow_copy_constructible<FunctionType>{},
115                          &fn)) {}
116
117   explicit ScopeGuardImpl(const FunctionType& fn) noexcept(
118       std::is_nothrow_copy_constructible<FunctionType>::value)
119       : ScopeGuardImpl(
120             fn,
121             makeFailsafe(std::is_nothrow_copy_constructible<FunctionType>{},
122                          &fn)) {}
123
124   explicit ScopeGuardImpl(FunctionType&& fn) noexcept(
125       std::is_nothrow_move_constructible<FunctionType>::value)
126       : ScopeGuardImpl(
127             std::move_if_noexcept(fn),
128             makeFailsafe(std::is_nothrow_move_constructible<FunctionType>{},
129                          &fn)) {}
130
131   ScopeGuardImpl(ScopeGuardImpl&& other) noexcept(
132       std::is_nothrow_move_constructible<FunctionType>::value)
133       : function_(std::move_if_noexcept(other.function_)) {
134     // If the above line attempts a copy and the copy throws, other is
135     // left owning the cleanup action and will execute it (or not) depending
136     // on the value of other.dismissed_. The following lines only execute
137     // if the move/copy succeeded, in which case *this assumes ownership of
138     // the cleanup action and dismisses other.
139     dismissed_ = other.dismissed_;
140     other.dismissed_ = true;
141   }
142
143   ~ScopeGuardImpl() noexcept {
144     if (!dismissed_) {
145       execute();
146     }
147   }
148
149  private:
150   static ScopeGuardImplBase makeFailsafe(std::true_type, const void*) noexcept {
151     return makeEmptyScopeGuard();
152   }
153
154   template <typename Fn>
155   static auto makeFailsafe(std::false_type, Fn* fn) noexcept
156       -> ScopeGuardImpl<decltype(std::ref(*fn))> {
157     return ScopeGuardImpl<decltype(std::ref(*fn))>{std::ref(*fn)};
158   }
159
160   template <typename Fn>
161   explicit ScopeGuardImpl(Fn&& fn, ScopeGuardImplBase&& failsafe)
162       : ScopeGuardImplBase{}, function_(std::forward<Fn>(fn)) {
163     failsafe.dismiss();
164   }
165
166   void* operator new(std::size_t) = delete;
167
168   void execute() noexcept {
169     runAndWarnAboutToCrashOnException(function_);
170   }
171
172   FunctionType function_;
173 };
174
175 template <typename FunctionType>
176 ScopeGuardImpl<typename std::decay<FunctionType>::type>
177 makeGuard(FunctionType&& fn) noexcept(
178     std::is_nothrow_constructible<typename std::decay<FunctionType>::type,
179                                   FunctionType>::value) {
180   return ScopeGuardImpl<typename std::decay<FunctionType>::type>(
181       std::forward<FunctionType>(fn));
182 }
183
184 /**
185  * This is largely unneeded if you just use auto for your guards.
186  */
187 typedef ScopeGuardImplBase&& ScopeGuard;
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
195 /**
196  * ScopeGuard used for executing a function when leaving the current scope
197  * depending on the presence of a new uncaught exception.
198  *
199  * If the executeOnException template parameter is true, the function is
200  * executed if a new uncaught exception is present at the end of the scope.
201  * If the parameter is false, then the function is executed if no new uncaught
202  * exceptions are present at the end of the scope.
203  *
204  * Used to implement SCOPE_FAIL and SCOPE_SUCCESS below.
205  */
206 template <typename FunctionType, bool ExecuteOnException>
207 class ScopeGuardForNewException {
208  public:
209   explicit ScopeGuardForNewException(const FunctionType& fn) : function_(fn) {}
210
211   explicit ScopeGuardForNewException(FunctionType&& fn)
212       : function_(std::move(fn)) {}
213
214   ScopeGuardForNewException(ScopeGuardForNewException&& other) = default;
215
216   ~ScopeGuardForNewException() noexcept(ExecuteOnException) {
217     if (ExecuteOnException == (exceptionCounter_ < uncaught_exceptions())) {
218       if (ExecuteOnException) {
219         ScopeGuardImplBase::runAndWarnAboutToCrashOnException(function_);
220       } else {
221         function_();
222       }
223     }
224   }
225
226  private:
227   ScopeGuardForNewException(const ScopeGuardForNewException& other) = delete;
228
229   void* operator new(std::size_t) = delete;
230
231   FunctionType function_;
232   int exceptionCounter_{uncaught_exceptions()};
233 };
234
235 /**
236  * Internal use for the macro SCOPE_FAIL below
237  */
238 enum class ScopeGuardOnFail {};
239
240 template <typename FunctionType>
241 ScopeGuardForNewException<typename std::decay<FunctionType>::type, true>
242 operator+(detail::ScopeGuardOnFail, FunctionType&& fn) {
243   return
244       ScopeGuardForNewException<typename std::decay<FunctionType>::type, true>(
245       std::forward<FunctionType>(fn));
246 }
247
248 /**
249  * Internal use for the macro SCOPE_SUCCESS below
250  */
251 enum class ScopeGuardOnSuccess {};
252
253 template <typename FunctionType>
254 ScopeGuardForNewException<typename std::decay<FunctionType>::type, false>
255 operator+(ScopeGuardOnSuccess, FunctionType&& fn) {
256   return
257       ScopeGuardForNewException<typename std::decay<FunctionType>::type, false>(
258       std::forward<FunctionType>(fn));
259 }
260
261 #endif // native uncaught_exception() supported
262
263 /**
264  * Internal use for the macro SCOPE_EXIT below
265  */
266 enum class ScopeGuardOnExit {};
267
268 template <typename FunctionType>
269 ScopeGuardImpl<typename std::decay<FunctionType>::type>
270 operator+(detail::ScopeGuardOnExit, FunctionType&& fn) {
271   return ScopeGuardImpl<typename std::decay<FunctionType>::type>(
272       std::forward<FunctionType>(fn));
273 }
274 } // namespace detail
275
276 } // namespace folly
277
278 #define SCOPE_EXIT \
279   auto FB_ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
280   = ::folly::detail::ScopeGuardOnExit() + [&]() noexcept
281
282 #if defined(FOLLY_EXCEPTION_COUNT_USE_CXA_GET_GLOBALS) || \
283     defined(FOLLY_EXCEPTION_COUNT_USE_GETPTD) ||          \
284     defined(FOLLY_EXCEPTION_COUNT_USE_STD)
285 #define SCOPE_FAIL \
286   auto FB_ANONYMOUS_VARIABLE(SCOPE_FAIL_STATE) \
287   = ::folly::detail::ScopeGuardOnFail() + [&]() noexcept
288
289 #define SCOPE_SUCCESS \
290   auto FB_ANONYMOUS_VARIABLE(SCOPE_SUCCESS_STATE) \
291   = ::folly::detail::ScopeGuardOnSuccess() + [&]()
292 #endif // native uncaught_exception() supported