Permalink
Switch branches/tags
v2018.09.24.00 v2018.09.17.00 v2018.09.10.01 v2018.09.10.00 v2018.09.03.01 v2018.09.03.00 v2018.08.27.00 v2018.08.20.00 v2018.08.13.00 v2018.08.09.00 v2018.08.06.00 v2018.07.30.00 v2018.07.23.00 v2018.07.16.00 v2018.07.09.00 v2018.07.02.00 v2018.06.25.00 v2018.06.18.00 v2018.06.11.00 v2018.06.04.00 v2018.05.28.00 v2018.05.21.00 v2018.05.14.00 v2018.05.07.00 v2018.04.30.00 v2018.04.23.00 v2018.04.16.00 v2018.04.09.00 v2018.04.02.00 v2018.03.26.00 v2018.03.19.00 v2018.03.12.00 v2018.03.05.00 v2018.02.26.00 v2018.02.19.00 v2018.02.12.00 v2018.02.05.00 v2018.01.29.00 v2018.01.22.00 v2018.01.15.00 v2018.01.08.00 v2018.01.01.00 v2017.12.25.00 v2017.12.18.00 v2017.12.11.00 v2017.12.04.00 v2017.11.27.00 v2017.11.20.00 v2017.11.13.00 v2017.11.06.00 v2017.10.30.00 v2017.10.23.00 v2017.10.16.00 v2017.10.09.00 v2017.10.02.00 v2017.09.25.00 v2017.09.18.00 v2017.09.11.00 v2017.09.04.00 v2017.08.28.00 v2017.08.21.00 v2017.08.14.00 v2017.08.07.00 v2017.07.31.00 v2017.07.24.00 v2017.07.17.01 v2017.07.17.00 v2017.07.10.00 v2017.07.03.00 v2017.06.26.01 v2017.06.26.00 v2017.06.19.00 v2017.06.12.00 v2017.06.05.00 v2017.05.29.00 v2017.05.22.00 v2017.05.15.00 v2017.05.08.00 v2017.05.01.00 v2017.04.24.00 v2017.04.17.00 v2017.04.10.00 v2017.04.03.00 v2017.03.27.00 v2017.03.20.00 v2017.03.13.00 v2017.03.06.00 v2016.12.19.00 v2016.12.12.00 v2016.12.05.00 v2016.11.28.00 v2016.11.21.00 v2016.11.14.00 v2016.11.07.00 v2016.10.31.00 v2016.10.24.00 v2016.10.17.00 v2016.10.10.00 v2016.10.03.00 v2016.09.26.00
Nothing to show
Find file Copy path
297 lines (250 sloc) 8.86 KB
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cstddef>
#include <cstdlib>
#include <functional>
#include <new>
#include <type_traits>
#include <utility>
#include <folly/Portability.h>
#include <folly/Preprocessor.h>
#include <folly/lang/UncaughtExceptions.h>
namespace folly {
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) {}
static ScopeGuardImplBase makeEmptyScopeGuard() noexcept {
return ScopeGuardImplBase{};
}
template <typename T>
static const T& asConst(const T& t) noexcept {
return t;
}
bool dismissed_;
private:
static void warnAboutToCrash() noexcept;
};
template <typename FunctionType>
class ScopeGuardImpl : public ScopeGuardImplBase {
public:
explicit ScopeGuardImpl(FunctionType& fn) noexcept(
std::is_nothrow_copy_constructible<FunctionType>::value)
: ScopeGuardImpl(
asConst(fn),
makeFailsafe(
std::is_nothrow_copy_constructible<FunctionType>{},
&fn)) {}
explicit ScopeGuardImpl(const FunctionType& fn) noexcept(
std::is_nothrow_copy_constructible<FunctionType>::value)
: ScopeGuardImpl(
fn,
makeFailsafe(
std::is_nothrow_copy_constructible<FunctionType>{},
&fn)) {}
explicit ScopeGuardImpl(FunctionType&& fn) noexcept(
std::is_nothrow_move_constructible<FunctionType>::value)
: ScopeGuardImpl(
std::move_if_noexcept(fn),
makeFailsafe(
std::is_nothrow_move_constructible<FunctionType>{},
&fn)) {}
ScopeGuardImpl(ScopeGuardImpl&& other) noexcept(
std::is_nothrow_move_constructible<FunctionType>::value)
: function_(std::move_if_noexcept(other.function_)) {
// If the above line attempts a copy and the copy throws, other is
// left owning the cleanup action and will execute it (or not) depending
// on the value of other.dismissed_. The following lines only execute
// if the move/copy succeeded, in which case *this assumes ownership of
// the cleanup action and dismisses other.
dismissed_ = other.dismissed_;
other.dismissed_ = true;
}
~ScopeGuardImpl() noexcept {
if (!dismissed_) {
execute();
}
}
private:
static ScopeGuardImplBase makeFailsafe(std::true_type, const void*) noexcept {
return makeEmptyScopeGuard();
}
template <typename Fn>
static auto makeFailsafe(std::false_type, Fn* fn) noexcept
-> ScopeGuardImpl<decltype(std::ref(*fn))> {
return ScopeGuardImpl<decltype(std::ref(*fn))>{std::ref(*fn)};
}
template <typename Fn>
explicit ScopeGuardImpl(Fn&& fn, ScopeGuardImplBase&& failsafe)
: ScopeGuardImplBase{}, function_(std::forward<Fn>(fn)) {
failsafe.dismiss();
}
void* operator new(std::size_t) = delete;
void execute() noexcept {
runAndWarnAboutToCrashOnException(function_);
}
FunctionType function_;
};
template <typename F>
using ScopeGuardImplDecay = ScopeGuardImpl<typename std::decay<F>::type>;
} // namespace detail
/**
* 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
*/
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_STD)
/**
* ScopeGuard used for executing a function when leaving the current scope
* depending on the presence of a new uncaught exception.
*
* If the executeOnException template parameter is true, the function is
* executed if a new uncaught exception is present at the end of the 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_SUCCESS below.
*/
template <typename FunctionType, bool ExecuteOnException>
class ScopeGuardForNewException {
public:
explicit ScopeGuardForNewException(const FunctionType& fn) : function_(fn) {}
explicit ScopeGuardForNewException(FunctionType&& fn)
: function_(std::move(fn)) {}
ScopeGuardForNewException(ScopeGuardForNewException&& other) = default;
~ScopeGuardForNewException() noexcept(ExecuteOnException) {
if (ExecuteOnException == (exceptionCounter_ < uncaught_exceptions())) {
if (ExecuteOnException) {
ScopeGuardImplBase::runAndWarnAboutToCrashOnException(function_);
} else {
function_();
}
}
}
private:
ScopeGuardForNewException(const ScopeGuardForNewException& other) = delete;
void* operator new(std::size_t) = delete;
FunctionType function_;
int exceptionCounter_{uncaught_exceptions()};
};
/**
* Internal use for the macro SCOPE_FAIL below
*/
enum class ScopeGuardOnFail {};
template <typename FunctionType>
ScopeGuardForNewException<typename std::decay<FunctionType>::type, true>
operator+(detail::ScopeGuardOnFail, FunctionType&& fn) {
return ScopeGuardForNewException<
typename std::decay<FunctionType>::type,
true>(std::forward<FunctionType>(fn));
}
/**
* Internal use for the macro SCOPE_SUCCESS below
*/
enum class ScopeGuardOnSuccess {};
template <typename FunctionType>
ScopeGuardForNewException<typename std::decay<FunctionType>::type, false>
operator+(ScopeGuardOnSuccess, FunctionType&& fn) {
return ScopeGuardForNewException<
typename std::decay<FunctionType>::type,
false>(std::forward<FunctionType>(fn));
}
#endif // native uncaught_exception() supported
/**
* Internal use for the macro SCOPE_EXIT below
*/
enum class ScopeGuardOnExit {};
template <typename FunctionType>
ScopeGuardImpl<typename std::decay<FunctionType>::type> operator+(
detail::ScopeGuardOnExit,
FunctionType&& fn) {
return ScopeGuardImpl<typename std::decay<FunctionType>::type>(
std::forward<FunctionType>(fn));
}
} // namespace detail
} // 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_STD)
#define SCOPE_FAIL \
auto FB_ANONYMOUS_VARIABLE(SCOPE_FAIL_STATE) = \
::folly::detail::ScopeGuardOnFail() + [&]() noexcept
#define SCOPE_SUCCESS \
auto FB_ANONYMOUS_VARIABLE(SCOPE_SUCCESS_STATE) = \
::folly::detail::ScopeGuardOnSuccess() + [&]()
#endif // native uncaught_exception() supported