scope_exit: Add SCOPE_SUCCESS and SCOPE_EXIT
This commit is contained in:
parent
bafb39ebc5
commit
64761dbc72
4 changed files with 89 additions and 34 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
16
src/common/macro_util.h
Normal file
16
src/common/macro_util.h
Normal file
|
@ -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
|
|
@ -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 <exception>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace detail {
|
||||
template <typename Func>
|
||||
struct ScopeExitHelper {
|
||||
explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {}
|
||||
~ScopeExitHelper() { func(); }
|
||||
#include "common/macro_util.h"
|
||||
|
||||
Func func;
|
||||
};
|
||||
namespace Dynarmic::detail {
|
||||
|
||||
template <typename Func>
|
||||
ScopeExitHelper<Func> ScopeExit(Func&& func) { return ScopeExitHelper<Func>(std::move(func)); }
|
||||
struct ScopeExitTag {};
|
||||
struct ScopeFailTag {};
|
||||
struct ScopeSuccessTag {};
|
||||
|
||||
template <typename Function>
|
||||
class ScopeExit final {
|
||||
public:
|
||||
explicit ScopeExit(Function&& fn) : function(std::move(fn)) {}
|
||||
~ScopeExit() noexcept {
|
||||
function();
|
||||
}
|
||||
private:
|
||||
Function function;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
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 <typename Function>
|
||||
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 <typename Function>
|
||||
auto operator->*(ScopeExitTag, Function&& function) {
|
||||
return ScopeExit<std::decay_t<Function>>{std::forward<Function>(function)};
|
||||
}
|
||||
|
||||
#define CONCAT2(x, y) DO_CONCAT2(x, y)
|
||||
#define DO_CONCAT2(x, y) x ## y
|
||||
template <typename Function>
|
||||
auto operator->*(ScopeFailTag, Function&& function) {
|
||||
return ScopeFail<std::decay_t<Function>>{std::forward<Function>(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 <typename Function>
|
||||
auto operator->*(ScopeSuccessTag, Function&& function) {
|
||||
return ScopeSuccess<std::decay_t<Function>>{std::forward<Function>(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{} ->* [&]()
|
||||
|
|
Loading…
Reference in a new issue