/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2011-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#ifndef FOLLY_SCOPEGUARD_H_
-#define FOLLY_SCOPEGUARD_H_
+#pragma once
#include <cstddef>
#include <functional>
#include <type_traits>
#include <utility>
+#include <folly/Portability.h>
#include <folly/Preprocessor.h>
-#include <folly/detail/UncaughtExceptionCounter.h>
+#include <folly/UncaughtExceptions.h>
namespace folly {
-/**
- * ScopeGuard is a general implementation of the "Initialization is
- * Resource Acquisition" idiom. Basically, it guarantees that a function
- * is executed upon leaving the currrent scope unless otherwise told.
- *
- * The makeGuard() function is used to create a new ScopeGuard object.
- * It can be instantiated with a lambda function, a std::function<void()>,
- * a functor, or a void(*)() function pointer.
- *
- *
- * Usage example: Add a friend to memory iff it is also added to the db.
- *
- * void User::addFriend(User& newFriend) {
- * // add the friend to memory
- * friends_.push_back(&newFriend);
- *
- * // If the db insertion that follows fails, we should
- * // remove it from memory.
- * // (You could also declare this as "auto guard = makeGuard(...)")
- * ScopeGuard guard = makeGuard([&] { friends_.pop_back(); });
- *
- * // this will throw an exception upon error, which
- * // makes the ScopeGuard execute UserCont::pop_back()
- * // once the Guard's destructor is called.
- * db_->addFriend(GetName(), newFriend.GetName());
- *
- * // an exception was not thrown, so don't execute
- * // the Guard.
- * guard.dismiss();
- * }
- *
- * Examine ScopeGuardTest.cpp for some more sample usage.
- *
- * Stolen from:
- * Andrei's and Petru Marginean's CUJ article:
- * http://drdobbs.com/184403758
- * and the loki library:
- * http://loki-lib.sourceforge.net/index.php?n=Idioms.ScopeGuardPointer
- * and triendl.kj article:
- * http://www.codeproject.com/KB/cpp/scope_guard.aspx
- */
+namespace detail {
+
class ScopeGuardImplBase {
public:
void dismiss() noexcept {
dismissed_ = true;
}
+ template <typename T>
+ FOLLY_ALWAYS_INLINE static void runAndWarnAboutToCrashOnException(
+ T& function) noexcept {
+ try {
+ function();
+ } catch (...) {
+ warnAboutToCrash();
+ std::terminate();
+ }
+ }
+
protected:
ScopeGuardImplBase() noexcept : dismissed_(false) {}
}
bool dismissed_;
+
+ private:
+ static void warnAboutToCrash() noexcept;
};
template <typename FunctionType>
void* operator new(std::size_t) = delete;
- void execute() noexcept { function_(); }
+ void execute() noexcept {
+ runAndWarnAboutToCrashOnException(function_);
+ }
FunctionType function_;
};
-template <typename FunctionType>
-ScopeGuardImpl<typename std::decay<FunctionType>::type>
-makeGuard(FunctionType&& fn) noexcept(
- std::is_nothrow_constructible<typename std::decay<FunctionType>::type,
- FunctionType>::value) {
- return ScopeGuardImpl<typename std::decay<FunctionType>::type>(
- std::forward<FunctionType>(fn));
-}
+template <typename F>
+using ScopeGuardImplDecay = ScopeGuardImpl<typename std::decay<F>::type>;
+
+} // namespace detail
/**
- * This is largely unneeded if you just use auto for your guards.
+ * ScopeGuard is a general implementation of the "Initialization is
+ * Resource Acquisition" idiom. Basically, it guarantees that a function
+ * is executed upon leaving the currrent scope unless otherwise told.
+ *
+ * The makeGuard() function is used to create a new ScopeGuard object.
+ * It can be instantiated with a lambda function, a std::function<void()>,
+ * a functor, or a void(*)() function pointer.
+ *
+ *
+ * Usage example: Add a friend to memory if and only if it is also added
+ * to the db.
+ *
+ * void User::addFriend(User& newFriend) {
+ * // add the friend to memory
+ * friends_.push_back(&newFriend);
+ *
+ * // If the db insertion that follows fails, we should
+ * // remove it from memory.
+ * auto guard = makeGuard([&] { friends_.pop_back(); });
+ *
+ * // this will throw an exception upon error, which
+ * // makes the ScopeGuard execute UserCont::pop_back()
+ * // once the Guard's destructor is called.
+ * db_->addFriend(GetName(), newFriend.GetName());
+ *
+ * // an exception was not thrown, so don't execute
+ * // the Guard.
+ * guard.dismiss();
+ * }
+ *
+ * Examine ScopeGuardTest.cpp for some more sample usage.
+ *
+ * Stolen from:
+ * Andrei's and Petru Marginean's CUJ article:
+ * http://drdobbs.com/184403758
+ * and the loki library:
+ * http://loki-lib.sourceforge.net/index.php?n=Idioms.ScopeGuardPointer
+ * and triendl.kj article:
+ * http://www.codeproject.com/KB/cpp/scope_guard.aspx
*/
-typedef ScopeGuardImplBase&& ScopeGuard;
+template <typename F>
+detail::ScopeGuardImplDecay<F> makeGuard(F&& f) noexcept(
+ noexcept(detail::ScopeGuardImplDecay<F>(static_cast<F&&>(f)))) {
+ return detail::ScopeGuardImplDecay<F>(static_cast<F&&>(f));
+}
namespace detail {
#if defined(FOLLY_EXCEPTION_COUNT_USE_CXA_GET_GLOBALS) || \
- defined(FOLLY_EXCEPTION_COUNT_USE_GETPTD)
+ defined(FOLLY_EXCEPTION_COUNT_USE_GETPTD) || \
+ defined(FOLLY_EXCEPTION_COUNT_USE_STD)
/**
* ScopeGuard used for executing a function when leaving the current scope
* If the parameter is false, then the function is executed if no new uncaught
* exceptions are present at the end of the scope.
*
- * Used to implement SCOPE_FAIL and SCOPE_SUCCES below.
+ * Used to implement SCOPE_FAIL and SCOPE_SUCCESS below.
*/
-template <typename FunctionType, bool executeOnException>
+template <typename FunctionType, bool ExecuteOnException>
class ScopeGuardForNewException {
public:
- explicit ScopeGuardForNewException(const FunctionType& fn)
- : function_(fn) {
- }
+ explicit ScopeGuardForNewException(const FunctionType& fn) : function_(fn) {}
explicit ScopeGuardForNewException(FunctionType&& fn)
- : function_(std::move(fn)) {
- }
+ : function_(std::move(fn)) {}
- ScopeGuardForNewException(ScopeGuardForNewException&& other)
- : function_(std::move(other.function_))
- , exceptionCounter_(std::move(other.exceptionCounter_)) {
- }
+ ScopeGuardForNewException(ScopeGuardForNewException&& other) = default;
- ~ScopeGuardForNewException() noexcept(executeOnException) {
- if (executeOnException == exceptionCounter_.isNewUncaughtException()) {
- function_();
+ ~ScopeGuardForNewException() noexcept(ExecuteOnException) {
+ if (ExecuteOnException == (exceptionCounter_ < uncaught_exceptions())) {
+ if (ExecuteOnException) {
+ ScopeGuardImplBase::runAndWarnAboutToCrashOnException(function_);
+ } else {
+ function_();
+ }
}
}
void* operator new(std::size_t) = delete;
FunctionType function_;
- UncaughtExceptionCounter exceptionCounter_;
+ int exceptionCounter_{uncaught_exceptions()};
};
/**
}
} // namespace detail
-} // folly
+} // namespace folly
#define SCOPE_EXIT \
auto FB_ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
= ::folly::detail::ScopeGuardOnExit() + [&]() noexcept
#if defined(FOLLY_EXCEPTION_COUNT_USE_CXA_GET_GLOBALS) || \
- defined(FOLLY_EXCEPTION_COUNT_USE_GETPTD)
+ defined(FOLLY_EXCEPTION_COUNT_USE_GETPTD) || \
+ defined(FOLLY_EXCEPTION_COUNT_USE_STD)
#define SCOPE_FAIL \
auto FB_ANONYMOUS_VARIABLE(SCOPE_FAIL_STATE) \
= ::folly::detail::ScopeGuardOnFail() + [&]() noexcept
auto FB_ANONYMOUS_VARIABLE(SCOPE_SUCCESS_STATE) \
= ::folly::detail::ScopeGuardOnSuccess() + [&]()
#endif // native uncaught_exception() supported
-
-#endif // FOLLY_SCOPEGUARD_H_