diff options
| author | 2022-10-12 17:11:07 -0700 | |
|---|---|---|
| committer | 2022-10-12 17:11:07 -0700 | |
| commit | 64c2ccb0cbd41bfdeaddfd33c1da18446c6879fb (patch) | |
| tree | 8291538cd7e917169699609a0539cf62bf9c0c70 | |
| parent | Merge pull request #9027 from yuzu-emu/revert-8987-another-name-for-reinforce... (diff) | |
| parent | kernel: add expanded result macros (diff) | |
| download | yuzu-64c2ccb0cbd41bfdeaddfd33c1da18446c6879fb.tar.gz yuzu-64c2ccb0cbd41bfdeaddfd33c1da18446c6879fb.tar.xz yuzu-64c2ccb0cbd41bfdeaddfd33c1da18446c6879fb.zip | |
Merge pull request #9034 from liamwhite/result-macros
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 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "common/bit_field.h" | 7 | #include "common/bit_field.h" |
| 8 | #include "common/common_funcs.h" | ||
| 8 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 9 | #include "common/expected.h" | 10 | #include "common/expected.h" |
| 10 | 11 | ||
| @@ -130,6 +131,10 @@ union Result { | |||
| 130 | [[nodiscard]] constexpr bool IsError() const { | 131 | [[nodiscard]] constexpr bool IsError() const { |
| 131 | return !IsSuccess(); | 132 | return !IsSuccess(); |
| 132 | } | 133 | } |
| 134 | |||
| 135 | [[nodiscard]] constexpr bool IsFailure() const { | ||
| 136 | return !IsSuccess(); | ||
| 137 | } | ||
| 133 | }; | 138 | }; |
| 134 | static_assert(std::is_trivial_v<Result>); | 139 | static_assert(std::is_trivial_v<Result>); |
| 135 | 140 | ||
| @@ -349,10 +354,110 @@ private: | |||
| 349 | } \ | 354 | } \ |
| 350 | } while (false) | 355 | } while (false) |
| 351 | 356 | ||
| 352 | #define R_SUCCEEDED(res) (res.IsSuccess()) | 357 | #define R_SUCCEEDED(res) (static_cast<Result>(res).IsSuccess()) |
| 358 | #define R_FAILED(res) (static_cast<Result>(res).IsFailure()) | ||
| 353 | 359 | ||
| 354 | /// Evaluates a boolean expression, and succeeds if that expression is true. | 360 | namespace ResultImpl { |
| 355 | #define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess) | 361 | template <auto EvaluateResult, class F> |
| 362 | class ScopedResultGuard { | ||
| 363 | YUZU_NON_COPYABLE(ScopedResultGuard); | ||
| 364 | YUZU_NON_MOVEABLE(ScopedResultGuard); | ||
| 365 | |||
| 366 | private: | ||
| 367 | Result& m_ref; | ||
| 368 | F m_f; | ||
| 369 | |||
| 370 | public: | ||
| 371 | constexpr ScopedResultGuard(Result& ref, F f) : m_ref(ref), m_f(std::move(f)) {} | ||
| 372 | constexpr ~ScopedResultGuard() { | ||
| 373 | if (EvaluateResult(m_ref)) { | ||
| 374 | m_f(); | ||
| 375 | } | ||
| 376 | } | ||
| 377 | }; | ||
| 378 | |||
| 379 | template <auto EvaluateResult> | ||
| 380 | class ResultReferenceForScopedResultGuard { | ||
| 381 | private: | ||
| 382 | Result& m_ref; | ||
| 383 | |||
| 384 | public: | ||
| 385 | constexpr ResultReferenceForScopedResultGuard(Result& r) : m_ref(r) {} | ||
| 386 | constexpr operator Result&() const { | ||
| 387 | return m_ref; | ||
| 388 | } | ||
| 389 | }; | ||
| 390 | |||
| 391 | template <auto EvaluateResult, typename F> | ||
| 392 | constexpr ScopedResultGuard<EvaluateResult, F> operator+( | ||
| 393 | ResultReferenceForScopedResultGuard<EvaluateResult> ref, F&& f) { | ||
| 394 | return ScopedResultGuard<EvaluateResult, F>(static_cast<Result&>(ref), std::forward<F>(f)); | ||
| 395 | } | ||
| 396 | |||
| 397 | constexpr bool EvaluateResultSuccess(const Result& r) { | ||
| 398 | return R_SUCCEEDED(r); | ||
| 399 | } | ||
| 400 | constexpr bool EvaluateResultFailure(const Result& r) { | ||
| 401 | return R_FAILED(r); | ||
| 402 | } | ||
| 403 | |||
| 404 | template <typename T> | ||
| 405 | constexpr void UpdateCurrentResultReference(T result_reference, Result result) { | ||
| 406 | ASSERT(false); | ||
| 407 | } | ||
| 408 | |||
| 409 | template <> | ||
| 410 | constexpr void UpdateCurrentResultReference<Result&>(Result& result_reference, Result result) { | ||
| 411 | result_reference = result; | ||
| 412 | } | ||
| 413 | |||
| 414 | template <> | ||
| 415 | constexpr void UpdateCurrentResultReference<Result>(Result result_reference, Result result) {} | ||
| 416 | } // namespace ResultImpl | ||
| 417 | |||
| 418 | #define DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(COUNTER_VALUE) \ | ||
| 419 | [[maybe_unused]] constexpr bool HasPrevRef_##COUNTER_VALUE = \ | ||
| 420 | std::same_as<decltype(__TmpCurrentResultReference), Result&>; \ | ||
| 421 | [[maybe_unused]] auto& PrevRef_##COUNTER_VALUE = __TmpCurrentResultReference; \ | ||
| 422 | [[maybe_unused]] Result __tmp_result_##COUNTER_VALUE = ResultSuccess; \ | ||
| 423 | Result& __TmpCurrentResultReference = \ | ||
| 424 | HasPrevRef_##COUNTER_VALUE ? PrevRef_##COUNTER_VALUE : __tmp_result_##COUNTER_VALUE | ||
| 425 | |||
| 426 | #define ON_RESULT_RETURN_IMPL(...) \ | ||
| 427 | static_assert(std::same_as<decltype(__TmpCurrentResultReference), Result&>); \ | ||
| 428 | auto RESULT_GUARD_STATE_##__COUNTER__ = \ | ||
| 429 | ResultImpl::ResultReferenceForScopedResultGuard<__VA_ARGS__>( \ | ||
| 430 | __TmpCurrentResultReference) + \ | ||
| 431 | [&]() | ||
| 432 | |||
| 433 | #define ON_RESULT_FAILURE_2 ON_RESULT_RETURN_IMPL(ResultImpl::EvaluateResultFailure) | ||
| 434 | |||
| 435 | #define ON_RESULT_FAILURE \ | ||
| 436 | DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \ | ||
| 437 | ON_RESULT_FAILURE_2 | ||
| 438 | |||
| 439 | #define ON_RESULT_SUCCESS_2 ON_RESULT_RETURN_IMPL(ResultImpl::EvaluateResultSuccess) | ||
| 440 | |||
| 441 | #define ON_RESULT_SUCCESS \ | ||
| 442 | DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \ | ||
| 443 | ON_RESULT_SUCCESS_2 | ||
| 444 | |||
| 445 | constexpr inline Result __TmpCurrentResultReference = ResultSuccess; | ||
| 446 | |||
| 447 | /// Returns a result. | ||
| 448 | #define R_RETURN(res_expr) \ | ||
| 449 | { \ | ||
| 450 | const Result _tmp_r_throw_rc = (res_expr); \ | ||
| 451 | ResultImpl::UpdateCurrentResultReference<decltype(__TmpCurrentResultReference)>( \ | ||
| 452 | __TmpCurrentResultReference, _tmp_r_throw_rc); \ | ||
| 453 | return _tmp_r_throw_rc; \ | ||
| 454 | } | ||
| 455 | |||
| 456 | /// Returns ResultSuccess() | ||
| 457 | #define R_SUCCEED() R_RETURN(ResultSuccess) | ||
| 458 | |||
| 459 | /// Throws a result. | ||
| 460 | #define R_THROW(res_expr) R_RETURN(res_expr) | ||
| 356 | 461 | ||
| 357 | /// Evaluates a boolean expression, and returns a result unless that expression is true. | 462 | /// Evaluates a boolean expression, and returns a result unless that expression is true. |
| 358 | #define R_UNLESS(expr, res) \ | 463 | #define R_UNLESS(expr, res) \ |
| @@ -361,7 +466,7 @@ private: | |||
| 361 | if (res.IsError()) { \ | 466 | if (res.IsError()) { \ |
| 362 | LOG_ERROR(Kernel, "Failed with result: {}", res.raw); \ | 467 | LOG_ERROR(Kernel, "Failed with result: {}", res.raw); \ |
| 363 | } \ | 468 | } \ |
| 364 | return res; \ | 469 | R_THROW(res); \ |
| 365 | } \ | 470 | } \ |
| 366 | } | 471 | } |
| 367 | 472 | ||
| @@ -369,7 +474,10 @@ private: | |||
| 369 | #define R_TRY(res_expr) \ | 474 | #define R_TRY(res_expr) \ |
| 370 | { \ | 475 | { \ |
| 371 | const auto _tmp_r_try_rc = (res_expr); \ | 476 | const auto _tmp_r_try_rc = (res_expr); \ |
| 372 | if (_tmp_r_try_rc.IsError()) { \ | 477 | if (R_FAILED(_tmp_r_try_rc)) { \ |
| 373 | return _tmp_r_try_rc; \ | 478 | R_THROW(_tmp_r_try_rc); \ |
| 374 | } \ | 479 | } \ |
| 375 | } | 480 | } |
| 481 | |||
| 482 | /// Evaluates a boolean expression, and succeeds if that expression is true. | ||
| 483 | #define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess) | ||