diff options
| author | Liam <byteslice@airmail.cc> | 2022-10-04 20:05:08 -0400 | 
|---|---|---|
| committer | Liam <byteslice@airmail.cc> | 2022-10-08 12:41:27 -0400 | 
| commit | 47a2efee73b1ac8670cf47d5c0ab3f7e4a0b526b (patch) | |
| tree | 50352327fd75d9fc6b52db568d3747c7bbed6a4f | |
| parent | 155213484b9a785c93e16a28285999256587691a (diff) | |
kernel: add expanded result macros
| -rw-r--r-- | src/core/hle/result.h | 120 | 
1 files changed, 114 insertions, 6 deletions
| diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 47a1b829b..e20e0bfee 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -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) | 
