Merge pull request #9034 from liamwhite/result-macros

kernel: add expanded result macros
This commit is contained in:
bunnei 2022-10-12 17:11:07 -07:00 committed by GitHub
commit 64c2ccb0cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 114 additions and 6 deletions

View File

@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/expected.h"
@ -130,6 +131,10 @@ union Result {
[[nodiscard]] constexpr bool IsError() const {
return !IsSuccess();
}
[[nodiscard]] constexpr bool IsFailure() const {
return !IsSuccess();
}
};
static_assert(std::is_trivial_v<Result>);
@ -349,10 +354,110 @@ private:
} \
} while (false)
#define R_SUCCEEDED(res) (res.IsSuccess())
#define R_SUCCEEDED(res) (static_cast<Result>(res).IsSuccess())
#define R_FAILED(res) (static_cast<Result>(res).IsFailure())
/// Evaluates a boolean expression, and succeeds if that expression is true.
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess)
namespace ResultImpl {
template <auto EvaluateResult, class F>
class ScopedResultGuard {
YUZU_NON_COPYABLE(ScopedResultGuard);
YUZU_NON_MOVEABLE(ScopedResultGuard);
private:
Result& m_ref;
F m_f;
public:
constexpr ScopedResultGuard(Result& ref, F f) : m_ref(ref), m_f(std::move(f)) {}
constexpr ~ScopedResultGuard() {
if (EvaluateResult(m_ref)) {
m_f();
}
}
};
template <auto EvaluateResult>
class ResultReferenceForScopedResultGuard {
private:
Result& m_ref;
public:
constexpr ResultReferenceForScopedResultGuard(Result& r) : m_ref(r) {}
constexpr operator Result&() const {
return m_ref;
}
};
template <auto EvaluateResult, typename F>
constexpr ScopedResultGuard<EvaluateResult, F> operator+(
ResultReferenceForScopedResultGuard<EvaluateResult> ref, F&& f) {
return ScopedResultGuard<EvaluateResult, F>(static_cast<Result&>(ref), std::forward<F>(f));
}
constexpr bool EvaluateResultSuccess(const Result& r) {
return R_SUCCEEDED(r);
}
constexpr bool EvaluateResultFailure(const Result& r) {
return R_FAILED(r);
}
template <typename T>
constexpr void UpdateCurrentResultReference(T result_reference, Result result) {
ASSERT(false);
}
template <>
constexpr void UpdateCurrentResultReference<Result&>(Result& result_reference, Result result) {
result_reference = result;
}
template <>
constexpr void UpdateCurrentResultReference<Result>(Result result_reference, Result result) {}
} // namespace ResultImpl
#define DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(COUNTER_VALUE) \
[[maybe_unused]] constexpr bool HasPrevRef_##COUNTER_VALUE = \
std::same_as<decltype(__TmpCurrentResultReference), Result&>; \
[[maybe_unused]] auto& PrevRef_##COUNTER_VALUE = __TmpCurrentResultReference; \
[[maybe_unused]] Result __tmp_result_##COUNTER_VALUE = ResultSuccess; \
Result& __TmpCurrentResultReference = \
HasPrevRef_##COUNTER_VALUE ? PrevRef_##COUNTER_VALUE : __tmp_result_##COUNTER_VALUE
#define ON_RESULT_RETURN_IMPL(...) \
static_assert(std::same_as<decltype(__TmpCurrentResultReference), Result&>); \
auto RESULT_GUARD_STATE_##__COUNTER__ = \
ResultImpl::ResultReferenceForScopedResultGuard<__VA_ARGS__>( \
__TmpCurrentResultReference) + \
[&]()
#define ON_RESULT_FAILURE_2 ON_RESULT_RETURN_IMPL(ResultImpl::EvaluateResultFailure)
#define ON_RESULT_FAILURE \
DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \
ON_RESULT_FAILURE_2
#define ON_RESULT_SUCCESS_2 ON_RESULT_RETURN_IMPL(ResultImpl::EvaluateResultSuccess)
#define ON_RESULT_SUCCESS \
DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \
ON_RESULT_SUCCESS_2
constexpr inline Result __TmpCurrentResultReference = ResultSuccess;
/// Returns a result.
#define R_RETURN(res_expr) \
{ \
const Result _tmp_r_throw_rc = (res_expr); \
ResultImpl::UpdateCurrentResultReference<decltype(__TmpCurrentResultReference)>( \
__TmpCurrentResultReference, _tmp_r_throw_rc); \
return _tmp_r_throw_rc; \
}
/// Returns ResultSuccess()
#define R_SUCCEED() R_RETURN(ResultSuccess)
/// Throws a result.
#define R_THROW(res_expr) R_RETURN(res_expr)
/// Evaluates a boolean expression, and returns a result unless that expression is true.
#define R_UNLESS(expr, res) \
@ -361,7 +466,7 @@ private:
if (res.IsError()) { \
LOG_ERROR(Kernel, "Failed with result: {}", res.raw); \
} \
return res; \
R_THROW(res); \
} \
}
@ -369,7 +474,10 @@ private:
#define R_TRY(res_expr) \
{ \
const auto _tmp_r_try_rc = (res_expr); \
if (_tmp_r_try_rc.IsError()) { \
return _tmp_r_try_rc; \
if (R_FAILED(_tmp_r_try_rc)) { \
R_THROW(_tmp_r_try_rc); \
} \
}
/// Evaluates a boolean expression, and succeeds if that expression is true.
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess)