dynarmic/include/mcl/scope_exit.hpp
Merry 7eb1d05f63 Squashed 'externals/mcl/' content from commit a86a53843
git-subtree-dir: externals/mcl
git-subtree-split: a86a53843f82e4d6ca2f2e1437824495acad2712
2022-04-19 16:27:52 +01:00

85 lines
2.2 KiB
C++

// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <exception>
#include <type_traits>
#include <utility>
#include <mcl/macro/anonymous_variable.hpp>
namespace mcl::detail {
struct scope_exit_tag {};
struct scope_fail_tag {};
struct scope_success_tag {};
template<typename Function>
class scope_exit final {
public:
explicit scope_exit(Function&& fn)
: function(std::move(fn)) {}
~scope_exit() noexcept {
function();
}
private:
Function function;
};
template<typename Function>
class scope_fail final {
public:
explicit scope_fail(Function&& fn)
: function(std::move(fn)), exception_count(std::uncaught_exceptions()) {}
~scope_fail() noexcept {
if (std::uncaught_exceptions() > exception_count) {
function();
}
}
private:
Function function;
int exception_count;
};
template<typename Function>
class scope_success final {
public:
explicit scope_success(Function&& fn)
: function(std::move(fn)), exception_count(std::uncaught_exceptions()) {}
~scope_success() {
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->*(scope_exit_tag, Function&& function) {
return scope_exit<std::decay_t<Function>>{std::forward<Function>(function)};
}
template<typename Function>
auto operator->*(scope_fail_tag, Function&& function) {
return scope_fail<std::decay_t<Function>>{std::forward<Function>(function)};
}
template<typename Function>
auto operator->*(scope_success_tag, Function&& function) {
return scope_success<std::decay_t<Function>>{std::forward<Function>(function)};
}
} // namespace mcl::detail
#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(MCL_SCOPE_EXIT_VAR_) = ::mcl::detail::scope_exit_tag{}->*[&]() noexcept
#define SCOPE_FAIL auto ANONYMOUS_VARIABLE(MCL_SCOPE_FAIL_VAR_) = ::mcl::detail::scope_fail_tag{}->*[&]() noexcept
#define SCOPE_SUCCESS auto ANONYMOUS_VARIABLE(MCL_SCOPE_FAIL_VAR_) = ::mcl::detail::scope_success_tag{}->*[&]()