dynarmic/include/mcl/scope_exit.hpp

95 lines
2.2 KiB
C++
Raw Normal View History

// 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{}->*[&]()