116 lines
2.5 KiB
C++
116 lines
2.5 KiB
C++
#ifndef SCOPEGUARD_H
|
|
#define SCOPEGUARD_H
|
|
|
|
// Taken from "Declarative Control Flow" (CppCon 2015)
|
|
// adjusted to work with Visual C++ 2013
|
|
|
|
#include <exception>
|
|
#include <utility>
|
|
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
|
#define noexcept
|
|
#endif
|
|
#include "UncaughtExceptions.h"
|
|
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
|
#undef noexcept
|
|
#endif
|
|
|
|
#define CONCATENATE_IMPL(s1, s2) s1 ## s2
|
|
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
|
|
#ifdef __COUNTER__
|
|
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __COUNTER__)
|
|
#else
|
|
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__)
|
|
#endif
|
|
|
|
namespace detail {
|
|
enum class ScopeGuardOnExit
|
|
{
|
|
};
|
|
|
|
enum class ScopeGuardOnFail
|
|
{
|
|
};
|
|
|
|
enum class ScopeGuardOnSuccess
|
|
{
|
|
};
|
|
|
|
template<typename Fun> class ScopeGuard
|
|
{
|
|
public:
|
|
ScopeGuard(Fun&& fn)
|
|
: fn(std::move(fn))
|
|
{
|
|
}
|
|
~ScopeGuard()
|
|
{
|
|
fn();
|
|
}
|
|
|
|
private:
|
|
Fun fn;
|
|
};
|
|
|
|
class UncaughtExceptionCounter
|
|
{
|
|
int exceptionCount_;
|
|
|
|
public:
|
|
UncaughtExceptionCounter()
|
|
: exceptionCount_(folly::uncaught_exceptions())
|
|
{
|
|
}
|
|
|
|
bool newUncaughtException()
|
|
{
|
|
return folly::uncaught_exceptions() > exceptionCount_;
|
|
}
|
|
};
|
|
|
|
template<typename FunctionType, bool executeOnException> class ScopeGuardForNewException
|
|
{
|
|
FunctionType function_;
|
|
UncaughtExceptionCounter ec_;
|
|
|
|
public:
|
|
explicit ScopeGuardForNewException(const FunctionType& fn)
|
|
: function_(fn)
|
|
{
|
|
}
|
|
|
|
explicit ScopeGuardForNewException(FunctionType&& fn)
|
|
: function_(std::move(fn))
|
|
{
|
|
}
|
|
|
|
~ScopeGuardForNewException()
|
|
{
|
|
if (executeOnException == ec_.newUncaughtException())
|
|
{
|
|
function_();
|
|
}
|
|
}
|
|
};
|
|
|
|
template<typename Fun> ScopeGuard<Fun> operator+(ScopeGuardOnExit, Fun&& fn)
|
|
{
|
|
return ScopeGuard<Fun>(std::forward<Fun>(fn));
|
|
}
|
|
|
|
template<typename Fun> ScopeGuardForNewException<typename std::decay_t<Fun>, true> operator+(detail::ScopeGuardOnFail, Fun&& fn)
|
|
{
|
|
return ScopeGuardForNewException<typename std::decay_t<Fun>, true>(std::forward<Fun>(fn));
|
|
}
|
|
|
|
template<typename Fun> ScopeGuardForNewException<typename std::decay_t<Fun>, false> operator+(detail::ScopeGuardOnSuccess, Fun&& fn)
|
|
{
|
|
return ScopeGuardForNewException<typename std::decay_t<Fun>, false>(std::forward<Fun>(fn));
|
|
}
|
|
}
|
|
|
|
#define SCOPE_FAIL auto ANONYMOUS_VARIABLE(SCOPE_FAIL_STATE) = ::detail::ScopeGuardOnFail() +[&]()
|
|
#define SCOPE_SUCCESS auto ANONYMOUS_VARIABLE(SCOPE_FAIL_STATE) = ::detail::ScopeGuardOnSuccess() +[&]()
|
|
#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) = ::detail::ScopeGuardOnExit() +[&]()
|
|
|
|
#endif
|