kernel: add expanded result macros

This commit is contained in:
Liam 2022-10-04 20:05:08 -04:00
parent 155213484b
commit 47a2efee73
1 changed files with 114 additions and 6 deletions

View File

@ -5,6 +5,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/expected.h" #include "common/expected.h"
@ -130,6 +131,10 @@ union Result {
[[nodiscard]] constexpr bool IsError() const { [[nodiscard]] constexpr bool IsError() const {
return !IsSuccess(); return !IsSuccess();
} }
[[nodiscard]] constexpr bool IsFailure() const {
return !IsSuccess();
}
}; };
static_assert(std::is_trivial_v<Result>); static_assert(std::is_trivial_v<Result>);
@ -349,10 +354,110 @@ private:
} \ } \
} while (false) } 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. namespace ResultImpl {
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess) 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. /// Evaluates a boolean expression, and returns a result unless that expression is true.
#define R_UNLESS(expr, res) \ #define R_UNLESS(expr, res) \
@ -361,7 +466,7 @@ private:
if (res.IsError()) { \ if (res.IsError()) { \
LOG_ERROR(Kernel, "Failed with result: {}", res.raw); \ LOG_ERROR(Kernel, "Failed with result: {}", res.raw); \
} \ } \
return res; \ R_THROW(res); \
} \ } \
} }
@ -369,7 +474,10 @@ private:
#define R_TRY(res_expr) \ #define R_TRY(res_expr) \
{ \ { \
const auto _tmp_r_try_rc = (res_expr); \ const auto _tmp_r_try_rc = (res_expr); \
if (_tmp_r_try_rc.IsError()) { \ if (R_FAILED(_tmp_r_try_rc)) { \
return _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)