summaryrefslogtreecommitdiff
path: root/zen/scope_guard.h
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2016-03-16 21:31:24 +0100
committerDaniel Wilhelm <daniel@wili.li>2016-03-16 21:31:24 +0100
commit89621addb4a7c87d2e3f3e7462e3c690cf71de71 (patch)
tree008b5dea7624ee1eeb57ff82c45fdf1afcab3b08 /zen/scope_guard.h
parent7.5 (diff)
downloadFreeFileSync-89621addb4a7c87d2e3f3e7462e3c690cf71de71.tar.gz
FreeFileSync-89621addb4a7c87d2e3f3e7462e3c690cf71de71.tar.bz2
FreeFileSync-89621addb4a7c87d2e3f3e7462e3c690cf71de71.zip
7.6
Diffstat (limited to 'zen/scope_guard.h')
-rw-r--r--zen/scope_guard.h115
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
bgstack15