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() {
|
void Jit::Run() {
|
||||||
ASSERT(!is_executing);
|
ASSERT(!is_executing);
|
||||||
is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT({ this->is_executing = false; });
|
SCOPE_EXIT { this->is_executing = false; };
|
||||||
|
|
||||||
impl->jit_state.halt_requested = false;
|
impl->jit_state.halt_requested = false;
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ public:
|
||||||
void Run() {
|
void Run() {
|
||||||
ASSERT(!is_executing);
|
ASSERT(!is_executing);
|
||||||
is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT({ this->is_executing = false; });
|
SCOPE_EXIT { this->is_executing = false; };
|
||||||
jit_state.halt_requested = false;
|
jit_state.halt_requested = false;
|
||||||
|
|
||||||
// TODO: Check code alignment
|
// 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
|
/* This file is part of the dynarmic project.
|
||||||
// Licensed under GPLv2 or any later version
|
* Copyright (c) 2018 MerryMage
|
||||||
// Refer to the license.txt file included.
|
* 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
|
#pragma once
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace detail {
|
#include "common/macro_util.h"
|
||||||
template <typename Func>
|
|
||||||
struct ScopeExitHelper {
|
|
||||||
explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {}
|
|
||||||
~ScopeExitHelper() { func(); }
|
|
||||||
|
|
||||||
Func func;
|
namespace Dynarmic::detail {
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Func>
|
struct ScopeExitTag {};
|
||||||
ScopeExitHelper<Func> ScopeExit(Func&& func) { return ScopeExitHelper<Func>(std::move(func)); }
|
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)
|
template <typename Function>
|
||||||
#define DO_CONCAT2(x, y) x ## y
|
auto operator->*(ScopeFailTag, Function&& function) {
|
||||||
|
return ScopeFail<std::decay_t<Function>>{std::forward<Function>(function)};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
template <typename Function>
|
||||||
* This macro allows you to conveniently specify a block of code that will run on scope exit. Handy
|
auto operator->*(ScopeSuccessTag, Function&& function) {
|
||||||
* for doing ad-hoc clean-up tasks in a function with multiple returns.
|
return ScopeSuccess<std::decay_t<Function>>{std::forward<Function>(function)};
|
||||||
*
|
}
|
||||||
* Example usage:
|
|
||||||
* \code
|
} // namespace Dynarmic::detail
|
||||||
* const int saved_val = g_foo;
|
|
||||||
* g_foo = 55;
|
#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(_SCOPE_EXIT_) = ::Dynarmic::detail::ScopeExitTag{} ->* [&]() noexcept
|
||||||
* SCOPE_EXIT({ g_foo = saved_val; });
|
#define SCOPE_FAIL auto ANONYMOUS_VARIABLE(_SCOPE_FAIL_) = ::Dynarmic::detail::ScopeFailTag{} ->* [&]() noexcept
|
||||||
*
|
#define SCOPE_SUCCESS auto ANONYMOUS_VARIABLE(_SCOPE_FAIL_) = ::Dynarmic::detail::ScopeSuccessTag{} ->* [&]()
|
||||||
* if (Bar()) {
|
|
||||||
* return 0;
|
|
||||||
* } else {
|
|
||||||
* return 20;
|
|
||||||
* }
|
|
||||||
* \endcode
|
|
||||||
*/
|
|
||||||
#define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body)
|
|
||||||
|
|
Loading…
Reference in a new issue