From 64761dbc72a97ddda50eb7a4353c9bf486e30b76 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 28 Jan 2018 17:57:02 +0000 Subject: [PATCH] scope_exit: Add SCOPE_SUCCESS and SCOPE_EXIT --- src/backend_x64/a32_interface.cpp | 2 +- src/backend_x64/a64_interface.cpp | 2 +- src/common/macro_util.h | 16 +++++ src/common/scope_exit.h | 103 ++++++++++++++++++++---------- 4 files changed, 89 insertions(+), 34 deletions(-) create mode 100644 src/common/macro_util.h diff --git a/src/backend_x64/a32_interface.cpp b/src/backend_x64/a32_interface.cpp index 48d63457..73f7b36e 100644 --- a/src/backend_x64/a32_interface.cpp +++ b/src/backend_x64/a32_interface.cpp @@ -153,7 +153,7 @@ Jit::~Jit() {} void Jit::Run() { ASSERT(!is_executing); is_executing = true; - SCOPE_EXIT({ this->is_executing = false; }); + SCOPE_EXIT { this->is_executing = false; }; impl->jit_state.halt_requested = false; diff --git a/src/backend_x64/a64_interface.cpp b/src/backend_x64/a64_interface.cpp index e80930e3..fbace6e9 100644 --- a/src/backend_x64/a64_interface.cpp +++ b/src/backend_x64/a64_interface.cpp @@ -47,7 +47,7 @@ public: void Run() { ASSERT(!is_executing); is_executing = true; - SCOPE_EXIT({ this->is_executing = false; }); + SCOPE_EXIT { this->is_executing = false; }; jit_state.halt_requested = false; // TODO: Check code alignment diff --git a/src/common/macro_util.h b/src/common/macro_util.h new file mode 100644 index 00000000..a36f1033 --- /dev/null +++ b/src/common/macro_util.h @@ -0,0 +1,16 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#define CONCATENATE_TOKENS(x, y) CONCATENATE_TOKENS_IMPL(x, y) +#define CONCATENATE_TOKENS_IMPL(x, y) x ## y + +#ifdef __COUNTER__ +#define ANONYMOUS_VARIABLE(str) CONCATENATE_TOKENS(str, __COUNTER__) +#else +#define ANONYMOUS_VARIABLE(str) CONCATENATE_TOKENS(str, __LINE__) +#endif diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h index 45974a68..0fd770f1 100644 --- a/src/common/scope_exit.h +++ b/src/common/scope_exit.h @@ -1,42 +1,81 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ #pragma once +#include +#include #include -namespace detail { - template - struct ScopeExitHelper { - explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {} - ~ScopeExitHelper() { func(); } +#include "common/macro_util.h" - Func func; - }; +namespace Dynarmic::detail { - template - ScopeExitHelper ScopeExit(Func&& func) { return ScopeExitHelper(std::move(func)); } +struct ScopeExitTag {}; +struct ScopeFailTag {}; +struct ScopeSuccessTag {}; + +template +class ScopeExit final { +public: + explicit ScopeExit(Function&& fn) : function(std::move(fn)) {} + ~ScopeExit() noexcept { + function(); + } +private: + Function function; +}; + +template +class ScopeFail final { +public: + explicit ScopeFail(Function&& fn) : function(std::move(fn)), exception_count(std::uncaught_exceptions()) {} + ~ScopeFail() noexcept { + if (std::uncaught_exceptions() > exception_count) { + function(); + } + } +private: + Function function; + int exception_count; +}; + +template +class ScopeSuccess final { +public: + explicit ScopeSuccess(Function&& fn) : function(std::move(fn)), exception_count(std::uncaught_exceptions()) {} + ~ScopeSuccess() { + if (std::uncaught_exceptions() <= exception_count) { + function(); + } + } +private: + Function function; + int exception_count; +}; + +// We use ->* here as it has the highest precedence of the operators we can use. + +template +auto operator->*(ScopeExitTag, Function&& function) { + return ScopeExit>{std::forward(function)}; } -#define CONCAT2(x, y) DO_CONCAT2(x, y) -#define DO_CONCAT2(x, y) x ## y +template +auto operator->*(ScopeFailTag, Function&& function) { + return ScopeFail>{std::forward(function)}; +} -/** - * This macro allows you to conveniently specify a block of code that will run on scope exit. Handy - * for doing ad-hoc clean-up tasks in a function with multiple returns. - * - * Example usage: - * \code - * const int saved_val = g_foo; - * g_foo = 55; - * SCOPE_EXIT({ g_foo = saved_val; }); - * - * if (Bar()) { - * return 0; - * } else { - * return 20; - * } - * \endcode - */ -#define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body) +template +auto operator->*(ScopeSuccessTag, Function&& function) { + return ScopeSuccess>{std::forward(function)}; +} + +} // namespace Dynarmic::detail + +#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(_SCOPE_EXIT_) = ::Dynarmic::detail::ScopeExitTag{} ->* [&]() noexcept +#define SCOPE_FAIL auto ANONYMOUS_VARIABLE(_SCOPE_FAIL_) = ::Dynarmic::detail::ScopeFailTag{} ->* [&]() noexcept +#define SCOPE_SUCCESS auto ANONYMOUS_VARIABLE(_SCOPE_FAIL_) = ::Dynarmic::detail::ScopeSuccessTag{} ->* [&]()