diff options
Diffstat (limited to 'zen/scope_guard.h')
-rw-r--r-- | zen/scope_guard.h | 115 |
1 files changed, 76 insertions, 39 deletions
diff --git a/zen/scope_guard.h b/zen/scope_guard.h index b5564c9b..791764de 100644 --- a/zen/scope_guard.h +++ b/zen/scope_guard.h @@ -4,79 +4,116 @@ // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** -#ifndef ZEN_SCOPEGUARD_8971632487321434 -#define ZEN_SCOPEGUARD_8971632487321434 +#ifndef SCOPE_GUARD_H_8971632487321434 +#define SCOPE_GUARD_H_8971632487321434 #include <cassert> +#include <exception> #include <type_traits> //std::decay -//best of Zen, Loki and C++11 +//best of Zen, Loki and C++17 + + +#ifdef ZEN_WIN +inline int getUncaughtExceptionCount() { return std::uncaught_exceptions(); } + +#elif defined ZEN_LINUX || defined ZEN_MAC +//std::uncaught_exceptions() currently unsupported on GCC and Clang => clean up ASAP +#ifdef ZEN_LINUX + static_assert(__GNUC__ < 5 || (__GNUC__ == 5 && (__GNUC_MINOR__ < 2 || (__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ <= 1))), "check std::uncaught_exceptions support"); +#else + static_assert(__clang_major__ < 7 || (__clang_major__ == 7 && __clang_minor__ <= 0), "check std::uncaught_exceptions support"); +#endif + +namespace __cxxabiv1 +{ +struct __cxa_eh_globals; +extern "C" __cxa_eh_globals* __cxa_get_globals() noexcept; +} + +inline int getUncaughtExceptionCount() +{ + return *(reinterpret_cast<unsigned int*>(static_cast<char*>(static_cast<void*>(__cxxabiv1::__cxa_get_globals())) + sizeof(void*))); +} +#endif + namespace zen { //Scope Guard /* - zen::ScopeGuard lockAio = zen::makeGuard([&] { ::CloseHandle(hDir); }); + auto guardAio = zen::makeGuard<ScopeGuardRunMode::ON_EXIT>([&] { ::CloseHandle(hDir); }); ... - lockAio.dismiss(); -*/ + guardAio.dismiss(); -//Scope Exit -/* +Scope Exit: ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir)); + ZEN_ON_SCOPE_FAIL(UndoPreviousWork()); + ZEN_ON_SCOPE_SUCCESS(NotifySuccess()); */ -class ScopeGuardBase +enum class ScopeGuardRunMode { -public: - void dismiss() { dismissed_ = true; } - -protected: - ScopeGuardBase() {} - ScopeGuardBase(ScopeGuardBase&& other) : dismissed_(other.dismissed_) { other.dismiss(); } //take over responsibility - ~ScopeGuardBase() {} //[!] protected non-virtual base class destructor - - bool isDismissed() const { return dismissed_; } - -private: - ScopeGuardBase (const ScopeGuardBase&) = delete; - ScopeGuardBase& operator=(const ScopeGuardBase&) = delete; - - bool dismissed_ = false; + ON_EXIT, + ON_SUCCESS, + ON_FAIL }; -template <typename F> -class ScopeGuardImpl : public ScopeGuardBase +template <ScopeGuardRunMode runMode, typename F> +class ScopeGuard { public: - explicit ScopeGuardImpl(const F& fun) : fun_(fun) {} - explicit ScopeGuardImpl( F&& fun) : fun_(std::move(fun)) {} - ScopeGuardImpl(ScopeGuardImpl&& other) : ScopeGuardBase(std::move(other)), fun_(std::move(other.fun_)) {} + explicit ScopeGuard(const F& fun) : fun_(fun) {} + explicit ScopeGuard( F&& fun) : fun_(std::move(fun)) {} + + ScopeGuard(ScopeGuard&& other) : fun_(std::move(other.fun_)), + exeptionCount(other.exeptionCount), + dismissed(other.dismissed) { other.dismissed = true; } - ~ScopeGuardImpl() + ~ScopeGuard() noexcept(runMode != ScopeGuardRunMode::ON_SUCCESS) { - if (!this->isDismissed()) - try +#ifdef _MSC_VER + #pragma warning(suppress: 4127) //"conditional expression is constant" +#endif + if (!dismissed) + { + if (runMode != ScopeGuardRunMode::ON_EXIT) { - fun_(); + const bool failed = getUncaughtExceptionCount() > exeptionCount; + if ((runMode == ScopeGuardRunMode::ON_FAIL) != failed) + return; } - catch (...) { assert(false); } + + if (runMode == ScopeGuardRunMode::ON_SUCCESS) + fun_(); //throw X + else + try { fun_(); } + catch (...) { assert(false); } //consistency: don't expect exceptions for ON_EXIT even if "!failed"! + } } + void dismiss() { dismissed = true; } + private: + ScopeGuard (const ScopeGuard&) = delete; + ScopeGuard& operator=(const ScopeGuard&) = delete; + F fun_; + const int exeptionCount = getUncaughtExceptionCount(); + bool dismissed = false; }; -typedef ScopeGuardBase&& ScopeGuard; -template <class F> inline -ScopeGuardImpl<typename std::decay<F>::type> makeGuard(F&& fun) { return ScopeGuardImpl<typename std::decay<F>::type>(std::forward<F>(fun)); } +template <ScopeGuardRunMode runMode, class F> inline +auto makeGuard(F&& fun) { return ScopeGuard<runMode, std::decay_t<F>>(std::forward<F>(fun)); } } #define ZEN_CONCAT_SUB(X, Y) X ## Y #define ZEN_CONCAT(X, Y) ZEN_CONCAT_SUB(X, Y) -#define ZEN_ON_SCOPE_EXIT(X) auto ZEN_CONCAT(dummy, __LINE__) = zen::makeGuard([&]{ X; }); (void)ZEN_CONCAT(dummy, __LINE__); +#define ZEN_ON_SCOPE_EXIT(X) auto ZEN_CONCAT(dummy, __LINE__) = zen::makeGuard<zen::ScopeGuardRunMode::ON_EXIT >([&]{ X; }); (void)ZEN_CONCAT(dummy, __LINE__); +#define ZEN_ON_SCOPE_FAIL(X) auto ZEN_CONCAT(dummy, __LINE__) = zen::makeGuard<zen::ScopeGuardRunMode::ON_FAIL >([&]{ X; }); (void)ZEN_CONCAT(dummy, __LINE__); +#define ZEN_ON_SCOPE_SUCCESS(X) auto ZEN_CONCAT(dummy, __LINE__) = zen::makeGuard<zen::ScopeGuardRunMode::ON_SUCCESS>([&]{ X; }); (void)ZEN_CONCAT(dummy, __LINE__); -#endif //ZEN_SCOPEGUARD_8971632487321434 +#endif //SCOPE_GUARD_H_8971632487321434 |