Commit 87229af6 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Reimplement SCOPE_SUCCESS and SCOPE_FAIL on top of ScopeGuard

Summary:
[Folly] Reimplement `SCOPE_SUCCESS` and `SCOPE_FAIL` on top of `ScopeGuardImpl`.

Allows the underlying type to be safely move-constructed, in case the compiler does not do RVO copy elision in pre-C++17 builds.

Fixes #940.

Reviewed By: ericniebler

Differential Revision: D10120199

fbshipit-source-id: 889b867041338d6b76a0af5f04076b16e3120f63
parent 96c11880
...@@ -37,20 +37,10 @@ class ScopeGuardImplBase { ...@@ -37,20 +37,10 @@ class ScopeGuardImplBase {
dismissed_ = true; dismissed_ = true;
} }
template <typename T>
FOLLY_ALWAYS_INLINE static void runAndWarnAboutToCrashOnException(
T& function) noexcept {
try {
function();
} catch (...) {
warnAboutToCrash();
std::terminate();
}
}
protected: protected:
ScopeGuardImplBase() noexcept : dismissed_(false) {} ScopeGuardImplBase() noexcept : dismissed_(false) {}
static void warnAboutToCrash() noexcept;
static ScopeGuardImplBase makeEmptyScopeGuard() noexcept { static ScopeGuardImplBase makeEmptyScopeGuard() noexcept {
return ScopeGuardImplBase{}; return ScopeGuardImplBase{};
} }
...@@ -61,12 +51,9 @@ class ScopeGuardImplBase { ...@@ -61,12 +51,9 @@ class ScopeGuardImplBase {
} }
bool dismissed_; bool dismissed_;
private:
static void warnAboutToCrash() noexcept;
}; };
template <typename FunctionType> template <typename FunctionType, bool InvokeNoexcept>
class ScopeGuardImpl : public ScopeGuardImplBase { class ScopeGuardImpl : public ScopeGuardImplBase {
public: public:
explicit ScopeGuardImpl(FunctionType& fn) noexcept( explicit ScopeGuardImpl(FunctionType& fn) noexcept(
...@@ -105,7 +92,7 @@ class ScopeGuardImpl : public ScopeGuardImplBase { ...@@ -105,7 +92,7 @@ class ScopeGuardImpl : public ScopeGuardImplBase {
other.dismissed_ = true; other.dismissed_ = true;
} }
~ScopeGuardImpl() noexcept { ~ScopeGuardImpl() noexcept(InvokeNoexcept) {
if (!dismissed_) { if (!dismissed_) {
execute(); execute();
} }
...@@ -118,8 +105,9 @@ class ScopeGuardImpl : public ScopeGuardImplBase { ...@@ -118,8 +105,9 @@ class ScopeGuardImpl : public ScopeGuardImplBase {
template <typename Fn> template <typename Fn>
static auto makeFailsafe(std::false_type, Fn* fn) noexcept static auto makeFailsafe(std::false_type, Fn* fn) noexcept
-> ScopeGuardImpl<decltype(std::ref(*fn))> { -> ScopeGuardImpl<decltype(std::ref(*fn)), InvokeNoexcept> {
return ScopeGuardImpl<decltype(std::ref(*fn))>{std::ref(*fn)}; return ScopeGuardImpl<decltype(std::ref(*fn)), InvokeNoexcept>{
std::ref(*fn)};
} }
template <typename Fn> template <typename Fn>
...@@ -130,15 +118,24 @@ class ScopeGuardImpl : public ScopeGuardImplBase { ...@@ -130,15 +118,24 @@ class ScopeGuardImpl : public ScopeGuardImplBase {
void* operator new(std::size_t) = delete; void* operator new(std::size_t) = delete;
void execute() noexcept { void execute() noexcept(InvokeNoexcept) {
runAndWarnAboutToCrashOnException(function_); if (InvokeNoexcept) {
try {
function_();
} catch (...) {
warnAboutToCrash();
std::terminate();
}
} else {
function_();
}
} }
FunctionType function_; FunctionType function_;
}; };
template <typename F> template <typename F, bool INE>
using ScopeGuardImplDecay = ScopeGuardImpl<typename std::decay<F>::type>; using ScopeGuardImplDecay = ScopeGuardImpl<typename std::decay<F>::type, INE>;
} // namespace detail } // namespace detail
...@@ -184,9 +181,9 @@ using ScopeGuardImplDecay = ScopeGuardImpl<typename std::decay<F>::type>; ...@@ -184,9 +181,9 @@ using ScopeGuardImplDecay = ScopeGuardImpl<typename std::decay<F>::type>;
* http://www.codeproject.com/KB/cpp/scope_guard.aspx * http://www.codeproject.com/KB/cpp/scope_guard.aspx
*/ */
template <typename F> template <typename F>
detail::ScopeGuardImplDecay<F> makeGuard(F&& f) noexcept( detail::ScopeGuardImplDecay<F, true> makeGuard(F&& f) noexcept(
noexcept(detail::ScopeGuardImplDecay<F>(static_cast<F&&>(f)))) { noexcept(detail::ScopeGuardImplDecay<F, true>(static_cast<F&&>(f)))) {
return detail::ScopeGuardImplDecay<F>(static_cast<F&&>(f)); return detail::ScopeGuardImplDecay<F, true>(static_cast<F&&>(f));
} }
namespace detail { namespace detail {
...@@ -209,30 +206,24 @@ namespace detail { ...@@ -209,30 +206,24 @@ namespace detail {
template <typename FunctionType, bool ExecuteOnException> template <typename FunctionType, bool ExecuteOnException>
class ScopeGuardForNewException { class ScopeGuardForNewException {
public: public:
explicit ScopeGuardForNewException(const FunctionType& fn) : function_(fn) {} explicit ScopeGuardForNewException(const FunctionType& fn) : guard_(fn) {}
explicit ScopeGuardForNewException(FunctionType&& fn) explicit ScopeGuardForNewException(FunctionType&& fn)
: function_(std::move(fn)) {} : guard_(std::move(fn)) {}
ScopeGuardForNewException(ScopeGuardForNewException&& other) = default; ScopeGuardForNewException(ScopeGuardForNewException&& other) = default;
~ScopeGuardForNewException() noexcept(ExecuteOnException) { ~ScopeGuardForNewException() noexcept(ExecuteOnException) {
if (ExecuteOnException == (exceptionCounter_ < uncaught_exceptions())) { if (ExecuteOnException != (exceptionCounter_ < uncaught_exceptions())) {
if (ExecuteOnException) { guard_.dismiss();
ScopeGuardImplBase::runAndWarnAboutToCrashOnException(function_);
} else {
function_();
}
} }
} }
private: private:
ScopeGuardForNewException(const ScopeGuardForNewException& other) = delete;
void* operator new(std::size_t) = delete; void* operator new(std::size_t) = delete;
void operator delete(void*) = delete; void operator delete(void*) = delete;
FunctionType function_; ScopeGuardImpl<FunctionType, ExecuteOnException> guard_;
int exceptionCounter_{uncaught_exceptions()}; int exceptionCounter_{uncaught_exceptions()};
}; };
...@@ -270,10 +261,10 @@ operator+(ScopeGuardOnSuccess, FunctionType&& fn) { ...@@ -270,10 +261,10 @@ operator+(ScopeGuardOnSuccess, FunctionType&& fn) {
enum class ScopeGuardOnExit {}; enum class ScopeGuardOnExit {};
template <typename FunctionType> template <typename FunctionType>
ScopeGuardImpl<typename std::decay<FunctionType>::type> operator+( ScopeGuardImpl<typename std::decay<FunctionType>::type, true> operator+(
detail::ScopeGuardOnExit, detail::ScopeGuardOnExit,
FunctionType&& fn) { FunctionType&& fn) {
return ScopeGuardImpl<typename std::decay<FunctionType>::type>( return ScopeGuardImpl<typename std::decay<FunctionType>::type, true>(
std::forward<FunctionType>(fn)); std::forward<FunctionType>(fn));
} }
} // namespace detail } // namespace detail
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment