Atmosphere/libraries/libvapours/include/vapours/results/results_common.hpp

550 lines
30 KiB
C++
Raw Normal View History

/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
2020-02-23 07:05:14 +00:00
#include <vapours/common.hpp>
#include <vapours/assert.hpp>
namespace ams {
const char *GetResultName(int module, int description);
namespace result::impl {
#if defined(AMS_AUTO_GENERATE_RESULT_NAMES)
struct DummyNameHolder {
static constexpr bool Exists = false;
static constexpr const char *Name = "unknown";
};
template<int Module>
struct ResultNameSpaceExistsImpl {
static constexpr bool Exists = false;
template<int Description>
using NameHolder = DummyNameHolder;
};
#endif
class ResultTraits {
public:
using BaseType = u32;
static_assert(std::is_same<BaseType, ::Result>::value, "std::is_same<BaseType, ::Result>::value");
static constexpr BaseType SuccessValue = BaseType();
static constexpr BaseType ModuleBits = 9;
static constexpr BaseType DescriptionBits = 13;
static constexpr BaseType ReservedBits = 10;
static_assert(ModuleBits + DescriptionBits + ReservedBits == sizeof(BaseType) * CHAR_BIT, "ModuleBits + DescriptionBits + ReservedBits == sizeof(BaseType) * CHAR_BIT");
2020-12-03 19:13:35 +00:00
private:
static constexpr ALWAYS_INLINE BaseType GetBitsValue(BaseType v, int ofs, int num) {
return (v >> ofs) & ~(~BaseType() << num);
}
public:
2020-02-23 07:05:14 +00:00
static constexpr ALWAYS_INLINE BaseType MakeValue(BaseType module, BaseType description) {
return (module) | (description << ModuleBits);
}
template<BaseType module, BaseType description>
struct MakeStaticValue : public std::integral_constant<BaseType, MakeValue(module, description)> {
static_assert(module < (1 << ModuleBits), "Invalid Module");
static_assert(description < (1 << DescriptionBits), "Invalid Description");
};
2020-02-23 07:05:14 +00:00
static constexpr ALWAYS_INLINE BaseType GetModuleFromValue(BaseType value) {
2020-12-03 19:13:35 +00:00
return GetBitsValue(value, 0, ModuleBits);
}
2020-02-23 07:05:14 +00:00
static constexpr ALWAYS_INLINE BaseType GetDescriptionFromValue(BaseType value) {
2020-12-03 19:13:35 +00:00
return GetBitsValue(value, ModuleBits, DescriptionBits);
}
static constexpr ALWAYS_INLINE BaseType GetReservedFromValue(BaseType value) {
return GetBitsValue(value, ModuleBits + DescriptionBits, ReservedBits);
}
static constexpr ALWAYS_INLINE BaseType MaskReservedFromValue(BaseType value) {
return value & ~(~(~BaseType() << ReservedBits) << (ModuleBits + DescriptionBits));
}
static constexpr ALWAYS_INLINE BaseType MergeValueWithReserved(BaseType value, BaseType reserved) {
return (value << 0) | (reserved << (ModuleBits + DescriptionBits));
}
};
/* Use CRTP for Results. */
template<typename Self>
class ResultBase {
public:
using BaseType = typename ResultTraits::BaseType;
static constexpr BaseType SuccessValue = ResultTraits::SuccessValue;
public:
2020-01-31 00:51:35 +00:00
constexpr ALWAYS_INLINE BaseType GetModule() const { return ResultTraits::GetModuleFromValue(static_cast<const Self *>(this)->GetValue()); }
constexpr ALWAYS_INLINE BaseType GetDescription() const { return ResultTraits::GetDescriptionFromValue(static_cast<const Self *>(this)->GetValue()); }
};
2020-12-03 19:13:35 +00:00
class ResultInternalAccessor;
}
class ResultSuccess;
class Result final : public result::impl::ResultBase<Result> {
2020-12-03 19:13:35 +00:00
friend class result::impl::ResultInternalAccessor;
public:
using Base = typename result::impl::ResultBase<Result>;
private:
2021-10-01 22:12:38 +00:00
typename Base::BaseType m_value;
private:
/* TODO: Maybe one-day, the result constructor. */
public:
Result() { /* ... */ }
/* TODO: It sure would be nice to make this private. */
2021-10-01 22:12:38 +00:00
constexpr ALWAYS_INLINE Result(typename Base::BaseType v) : m_value(v) { static_assert(std::is_same<typename Base::BaseType, ::Result>::value); }
2020-01-31 00:51:35 +00:00
constexpr ALWAYS_INLINE operator ResultSuccess() const;
2021-10-01 22:12:38 +00:00
static constexpr ALWAYS_INLINE bool CanAccept(Result) { return true; }
2021-10-01 22:12:38 +00:00
constexpr ALWAYS_INLINE bool IsSuccess() const { return m_value == Base::SuccessValue; }
2020-01-31 00:51:35 +00:00
constexpr ALWAYS_INLINE bool IsFailure() const { return !this->IsSuccess(); }
constexpr ALWAYS_INLINE typename Base::BaseType GetModule() const { return Base::GetModule(); }
constexpr ALWAYS_INLINE typename Base::BaseType GetDescription() const { return Base::GetDescription(); }
2021-10-01 22:12:38 +00:00
constexpr ALWAYS_INLINE typename Base::BaseType GetInnerValue() const { return ::ams::result::impl::ResultTraits::MaskReservedFromValue(m_value); }
constexpr ALWAYS_INLINE typename Base::BaseType GetValue() const { return m_value; }
};
static_assert(sizeof(Result) == sizeof(Result::Base::BaseType), "sizeof(Result) == sizeof(Result::Base::BaseType)");
static_assert(std::is_trivially_destructible<Result>::value, "std::is_trivially_destructible<Result>::value");
ALWAYS_INLINE const char *GetResultName(const Result &result) {
return GetResultName(result.GetModule(), result.GetDescription());
}
namespace result::impl {
2020-12-03 19:13:35 +00:00
class ResultInternalAccessor {
public:
2020-01-31 00:51:35 +00:00
static constexpr ALWAYS_INLINE Result MakeResult(ResultTraits::BaseType value) {
return Result(value);
}
2020-12-03 19:13:35 +00:00
static constexpr ALWAYS_INLINE ResultTraits::BaseType GetReserved(Result result) {
2021-10-01 22:12:38 +00:00
return ResultTraits::GetReservedFromValue(result.m_value);
2020-12-03 19:13:35 +00:00
}
static constexpr ALWAYS_INLINE Result MergeReserved(Result result, ResultTraits::BaseType reserved) {
2021-10-01 22:12:38 +00:00
return Result(ResultTraits::MergeValueWithReserved(ResultTraits::MaskReservedFromValue(result.m_value), reserved));
2020-12-03 19:13:35 +00:00
}
};
2020-01-31 00:51:35 +00:00
constexpr ALWAYS_INLINE Result MakeResult(ResultTraits::BaseType value) {
2020-12-03 19:13:35 +00:00
return ResultInternalAccessor::MakeResult(value);
}
}
class ResultSuccess final : public result::impl::ResultBase<ResultSuccess> {
public:
using Base = typename result::impl::ResultBase<ResultSuccess>;
public:
2021-10-01 22:12:38 +00:00
constexpr ALWAYS_INLINE operator Result() const { return result::impl::MakeResult(Base::SuccessValue); }
static constexpr ALWAYS_INLINE bool CanAccept(Result result) { return result.IsSuccess(); }
2020-01-31 00:51:35 +00:00
constexpr ALWAYS_INLINE bool IsSuccess() const { return true; }
constexpr ALWAYS_INLINE bool IsFailure() const { return !this->IsSuccess(); }
2020-01-31 00:51:35 +00:00
constexpr ALWAYS_INLINE typename Base::BaseType GetValue() const { return Base::SuccessValue; }
};
namespace result::impl {
2020-02-23 07:05:14 +00:00
NORETURN NOINLINE void OnResultAssertion(const char *file, int line, const char *func, const char *expr, Result result);
NORETURN NOINLINE void OnResultAssertion(Result result);
NORETURN NOINLINE void OnResultAbort(const char *file, int line, const char *func, const char *expr, Result result);
NORETURN NOINLINE void OnResultAbort(Result result);
}
2020-01-31 00:51:35 +00:00
constexpr ALWAYS_INLINE Result::operator ResultSuccess() const {
if (!ResultSuccess::CanAccept(*this)) {
2020-02-23 07:05:14 +00:00
result::impl::OnResultAbort(*this);
}
return ResultSuccess();
}
namespace result::impl {
template<ResultTraits::BaseType _Module, ResultTraits::BaseType _Description>
class ResultErrorBase : public ResultBase<ResultErrorBase<_Module, _Description>> {
public:
using Base = typename result::impl::ResultBase<ResultErrorBase<_Module, _Description>>;
static constexpr typename Base::BaseType Module = _Module;
static constexpr typename Base::BaseType Description = _Description;
static constexpr typename Base::BaseType Value = ResultTraits::MakeStaticValue<Module, Description>::value;
static_assert(Value != Base::SuccessValue, "Value != Base::SuccessValue");
public:
2021-10-01 22:12:38 +00:00
constexpr ALWAYS_INLINE operator Result() const { return MakeResult(Value); }
Minor header fixes to reduce parsing issues with Clang (#1700) * Work around Clang's incomplete C++20 support for omitting typename * vapours: fix Clang error about missing return in constexpr function * stratosphere: fix call to non-constexpr strlen in constexpr function strlen being constexpr is a non-compliant GCC extension; Clang explicitly rejects it: https://reviews.llvm.org/D23692 * stratosphere: add a bunch of missing override specifiers * stratosphere: work around Clang consteval bug Minimal example: https://godbolt.org/z/MoM64v93M The issue seems to be that Clang does not consider f(x) to be a constant expression if x comes from a template argument that isn't a non-type auto template argument (???) We can work around this by relaxing GetMessageHeaderForCheck (by using constexpr instead of consteval). This produces no functional changes because the result of GetMessageHeaderForCheck() is assigned to a constexpr variable, so the result is guaranteed to be computed at compile-time. * stratosphere: fix missing require clauses in definitions GCC not requiring the require clauses to be repeated for member definitions is actually a compiler bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96830 Clang rejects declarations with missing require clauses. * Fix ALWAYS_INLINE_LAMBDA and parameter list relative order While GCC doesn't seem to care about the position of the always_inline attribute relative to the parameter list, Clang is very picky and requires the attribute to appear after the parameter list (and before a trailing return type) * stratosphere: fix static constexpr member variable with incomplete type GCC accepts this for some reason (because of the lambda?) but Clang correctly rejects this.
2021-11-07 01:19:34 +00:00
constexpr ALWAYS_INLINE operator ResultSuccess() const {
OnResultAbort(Value);
__builtin_unreachable();
return ResultSuccess();
}
2020-01-31 00:51:35 +00:00
constexpr ALWAYS_INLINE bool IsSuccess() const { return false; }
constexpr ALWAYS_INLINE bool IsFailure() const { return !this->IsSuccess(); }
2020-01-31 00:51:35 +00:00
constexpr ALWAYS_INLINE typename Base::BaseType GetValue() const { return Value; }
};
template<ResultTraits::BaseType _Module, ResultTraits::BaseType DescStart, ResultTraits::BaseType DescEnd>
class ResultErrorRangeBase {
2021-10-01 22:12:38 +00:00
private:
/* NOTE: GCC does not optimize the module/description comparisons into one check (as of 10/1/2021) */
/* and so this optimizes result comparisons to get the same codegen as Nintendo does. */
static constexpr bool UseDirectValueComparison = true;
public:
static constexpr ResultTraits::BaseType Module = _Module;
static constexpr ResultTraits::BaseType DescriptionStart = DescStart;
static constexpr ResultTraits::BaseType DescriptionEnd = DescEnd;
static_assert(DescriptionStart <= DescriptionEnd, "DescriptionStart <= DescriptionEnd");
static constexpr typename ResultTraits::BaseType StartValue = ResultTraits::MakeStaticValue<Module, DescriptionStart>::value;
static constexpr typename ResultTraits::BaseType EndValue = ResultTraits::MakeStaticValue<Module, DescriptionEnd>::value;
public:
2021-10-01 22:12:38 +00:00
static constexpr ALWAYS_INLINE bool Includes(Result result) {
if constexpr (UseDirectValueComparison) {
const auto inner_value = result.GetInnerValue();
if constexpr (StartValue == EndValue) {
return inner_value == StartValue;
} else {
return StartValue <= inner_value && inner_value <= EndValue;
}
} else {
return result.GetModule() == Module && DescriptionStart <= result.GetDescription() && result.GetDescription() <= DescriptionEnd;
}
}
};
}
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_ARCH_ARM64) && defined(ATMOSPHERE_IS_STRATOSPHERE)
namespace diag::impl {
void FatalErrorByResultForNx(Result result) noexcept NORETURN;
}
#endif
}
/* Macros for defining new results. */
#if defined(AMS_AUTO_GENERATE_RESULT_NAMES)
#define R_DEFINE_NAMESPACE_RESULT_MODULE(nmspc, value) \
namespace nmspc { \
\
namespace result_impl { \
static constexpr inline ::ams::result::impl::ResultTraits::BaseType ResultModuleId = value; \
\
template<int Description> \
struct ResultNameHolderImpl { static constexpr bool Exists = false; }; \
} \
\
} \
\
namespace ams::result::impl { \
\
template<> struct ResultNameSpaceExistsImpl<value> { \
static constexpr bool Exists = true; \
\
template<int Description> \
using NameHolder = nmspc::result_impl::ResultNameHolderImpl<Description>; \
}; \
\
}
#else
#define R_DEFINE_NAMESPACE_RESULT_MODULE(nmspc, value) \
namespace nmspc { \
\
namespace result_impl { \
static constexpr inline ::ams::result::impl::ResultTraits::BaseType ResultModuleId = value; \
} \
\
}
#endif
#define R_CURRENT_NAMESPACE_RESULT_MODULE result_impl::ResultModuleId
#define R_NAMESPACE_MODULE_ID(nmspc) nmspc::R_CURRENT_NAMESPACE_RESULT_MODULE
#define R_MAKE_NAMESPACE_RESULT(nmspc, desc) static_cast<::ams::Result>(::ams::result::impl::ResultTraits::MakeValue(R_NAMESPACE_MODULE_ID(nmspc), desc))
#if defined(AMS_AUTO_GENERATE_RESULT_NAMES)
#define R_DEFINE_ERROR_RESULT_NAME_HOLDER_IMPL(name, desc_start, desc_end) \
template<> struct result_impl::ResultNameHolderImpl<desc_start> { static constexpr bool Exists = true; static constexpr const char *Name = #name; };
#else
#define R_DEFINE_ERROR_RESULT_NAME_HOLDER_IMPL(name, desc_start, desc_end)
#endif
#define R_DEFINE_ERROR_RESULT_CLASS_IMPL(name, desc_start, desc_end) \
class Result##name final : public ::ams::result::impl::ResultErrorBase<R_CURRENT_NAMESPACE_RESULT_MODULE, desc_start>, public ::ams::result::impl::ResultErrorRangeBase<R_CURRENT_NAMESPACE_RESULT_MODULE, desc_start, desc_end> {}
#define R_DEFINE_ERROR_RESULT_IMPL(name, desc_start, desc_end) \
R_DEFINE_ERROR_RESULT_NAME_HOLDER_IMPL(name, desc_start, desc_end) \
R_DEFINE_ERROR_RESULT_CLASS_IMPL(name, desc_start, desc_end)
#define R_DEFINE_ABSTRACT_ERROR_RESULT_IMPL(name, desc_start, desc_end) \
class Result##name final : public ::ams::result::impl::ResultErrorRangeBase<R_CURRENT_NAMESPACE_RESULT_MODULE, desc_start, desc_end> {}
#define R_DEFINE_ERROR_RESULT(name, desc) R_DEFINE_ERROR_RESULT_IMPL(name, desc, desc)
#define R_DEFINE_ERROR_RANGE(name, start, end) R_DEFINE_ERROR_RESULT_IMPL(name, start, end)
#define R_DEFINE_ABSTRACT_ERROR_RESULT(name, desc) R_DEFINE_ABSTRACT_ERROR_RESULT_IMPL(name, desc, desc)
#define R_DEFINE_ABSTRACT_ERROR_RANGE(name, start, end) R_DEFINE_ABSTRACT_ERROR_RESULT_IMPL(name, start, end)
#define R_DEFINE_ERROR_RESULT_NS(ns, name, desc) namespace ns { R_DEFINE_ERROR_RESULT_CLASS_IMPL(name, desc, desc); } R_DEFINE_ERROR_RESULT_NAME_HOLDER_IMPL(name, desc, desc)
#define R_DEFINE_ERROR_RANGE_NS(ns, name, start, end) namespace ns { R_DEFINE_ERROR_RESULT_CLASS_IMPL(name, start, end); } R_DEFINE_ERROR_RESULT_NAME_HOLDER_IMPL(name, start, end)
#define R_DEFINE_ABSTRACT_ERROR_RESULT_NS(ns, name, desc) namespace ns { R_DEFINE_ABSTRACT_ERROR_RESULT_IMPL(name, desc, desc); }
#define R_DEFINE_ABSTRACT_ERROR_RANGE_NS(ns, name, start, end) namespace ns { R_DEFINE_ABSTRACT_ERROR_RESULT_IMPL(name, start, end); }
/* Remove libnx macros, replace with our own. */
#ifndef R_SUCCEEDED
#error "R_SUCCEEDED not defined."
#endif
#undef R_SUCCEEDED
#ifndef R_FAILED
#error "R_FAILED not defined"
#endif
#undef R_FAILED
#define R_SUCCEEDED(res) (static_cast<::ams::Result>(res).IsSuccess())
#define R_FAILED(res) (static_cast<::ams::Result>(res).IsFailure())
/* NOTE: The following are experimental and cannot be safely used yet. */
/* =================================================================== */
constinit inline ::ams::Result __TmpCurrentResultReference = ::ams::ResultSuccess();
namespace ams::result::impl {
template<auto EvaluateResult, class F>
class ScopedResultGuard {
NON_COPYABLE(ScopedResultGuard);
NON_MOVEABLE(ScopedResultGuard);
private:
Result &m_ref;
F m_f;
public:
constexpr ALWAYS_INLINE ScopedResultGuard(Result &ref, F f) : m_ref(ref), m_f(std::move(f)) { }
constexpr ALWAYS_INLINE ~ScopedResultGuard() { if (EvaluateResult(m_ref)) { m_f(); } }
};
template<auto EvaluateResult>
class ResultReferenceForScopedResultGuard {
private:
Result &m_ref;
public:
constexpr ALWAYS_INLINE ResultReferenceForScopedResultGuard(Result &r) : m_ref(r) { /* ... */ }
constexpr ALWAYS_INLINE operator Result &() const { return m_ref; }
};
template<auto EvaluateResult, typename F>
constexpr ALWAYS_INLINE ScopedResultGuard<EvaluateResult, F> operator+(ResultReferenceForScopedResultGuard<EvaluateResult> ref, F&& f) {
return ScopedResultGuard<EvaluateResult, F>(static_cast<Result &>(ref), std::forward<F>(f));
}
constexpr ALWAYS_INLINE bool EvaluateResultSuccess(const ::ams::Result &r) { return R_SUCCEEDED(r); }
constexpr ALWAYS_INLINE bool EvaluateResultFailure(const ::ams::Result &r) { return R_FAILED(r); }
template<typename R>
constexpr ALWAYS_INLINE bool EvaluateResultIncludedImplForSuccessCompatibility(const ::ams::Result &r) {
if constexpr (std::same_as<R, ::ams::ResultSuccess>) {
return R_SUCCEEDED(r);
} else {
return R::Includes(r);
}
}
template<typename... Rs>
constexpr ALWAYS_INLINE bool EvaluateAnyResultIncludes(const ::ams::Result &r) { return (EvaluateResultIncludedImplForSuccessCompatibility<Rs>(r) || ...); }
template<typename... Rs>
constexpr ALWAYS_INLINE bool EvaluateResultNotIncluded(const ::ams::Result &r) { return !EvaluateAnyResultIncludes<Rs...>(r); }
}
#define AMS_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(); \
::ams::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 ANONYMOUS_VARIABLE(RESULT_GUARD_STATE_) = ::ams::result::impl::ResultReferenceForScopedResultGuard<__VA_ARGS__>(__TmpCurrentResultReference) + [&]() ALWAYS_INLINE_LAMBDA
#define ON_RESULT_FAILURE_2 ON_RESULT_RETURN_IMPL(::ams::result::impl::EvaluateResultFailure)
#define ON_RESULT_FAILURE \
AMS_DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \
ON_RESULT_FAILURE_2
#define ON_RESULT_SUCCESS_2 ON_RESULT_RETURN_IMPL(::ams::result::impl::EvaluateResultSuccess)
#define ON_RESULT_SUCCESS \
AMS_DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \
ON_RESULT_SUCCESS_2
#define ON_RESULT_INCLUDED_2(...) ON_RESULT_RETURN_IMPL(::ams::result::impl::EvaluateAnyResultIncludes<__VA_ARGS__>)
#define ON_RESULT_INCLUDED(...) \
AMS_DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \
ON_RESULT_INCLUDED_2(__VA_ARGS__)
#define ON_RESULT_NOT_INCLUDED_2(...) ON_RESULT_RETURN_IMPL(::ams::result::impl::EvaluateResultNotIncluded<__VA_ARGS__>)
#define ON_RESULT_NOT_INCLUDED(...) \
AMS_DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \
ON_RESULT_NOT_INCLUDED_2(__VA_ARGS__)
#define ON_RESULT_FAILURE_BESIDES(...) ON_RESULT_NOT_INCLUDED(::ams::ResultSuccess, ## __VA_ARGS__)
#define ON_RESULT_FAILURE_BESIDES_2(...) ON_RESULT_NOT_INCLUDED_2(::ams::ResultSuccess, ## __VA_ARGS__)
/* =================================================================== */
/// Returns a result.
#define R_RETURN(res_expr) \
{ \
const ::ams::Result _tmp_r_throw_rc = (res_expr); \
if constexpr (std::same_as<decltype(__TmpCurrentResultReference), ::ams::Result &>) { __TmpCurrentResultReference = _tmp_r_throw_rc; } \
return _tmp_r_throw_rc; \
}
/// Returns ResultSuccess()
#define R_SUCCEED() R_RETURN(::ams::ResultSuccess())
/// Throws a result.
#define R_THROW(res_expr) R_RETURN(res_expr)
/// Evaluates an expression that returns a result, and returns the result if it would fail.
#define R_TRY(res_expr) \
{ \
if (const auto _tmp_r_try_rc = (res_expr); R_FAILED(_tmp_r_try_rc)) { \
R_THROW(_tmp_r_try_rc); \
} \
}
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_IS_STRATOSPHERE) && !defined(AMS_ENABLE_DETAILED_ASSERTIONS) && !defined(AMS_BUILD_FOR_DEBUGGING) && !defined(AMS_BUILD_FOR_AUDITING)
#define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false)
#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false)
#elif defined(ATMOSPHERE_OS_HORIZON)
#define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) AMS_CALL_ASSERT_FAIL_IMPL(::ams::diag::AssertionType_Assert, "ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32, cond, val.GetModule(), val.GetDescription(), static_cast<::ams::Result>(val).GetInnerValue())
#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) AMS_CALL_ABORT_IMPL("ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32, cond, static_cast<::ams::Result>(val).GetModule(), static_cast<::ams::Result>(val).GetDescription(), static_cast<::ams::Result>(val).GetInnerValue())
2020-02-23 07:05:14 +00:00
#else
#define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) AMS_CALL_ASSERT_FAIL_IMPL(::ams::diag::AssertionType_Assert, "ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32 "\n Name: %s", cond, val.GetModule(), val.GetDescription(), static_cast<::ams::Result>(val).GetInnerValue(), ::ams::GetResultName(static_cast<::ams::Result>(val)))
#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) AMS_CALL_ABORT_IMPL("ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32 "\n Name: %s", cond, static_cast<::ams::Result>(val).GetModule(), static_cast<::ams::Result>(val).GetDescription(), static_cast<::ams::Result>(val).GetInnerValue(), ::ams::GetResultName(static_cast<::ams::Result>(val)))
2020-02-23 07:05:14 +00:00
#endif
/// Evaluates an expression that returns a result, and asserts the result if it would fail.
#ifdef AMS_ENABLE_ASSERTIONS
#define R_ASSERT(res_expr) \
{ \
if (const auto _tmp_r_assert_rc = (res_expr); AMS_UNLIKELY(R_FAILED(_tmp_r_assert_rc))) { \
AMS_CALL_ON_RESULT_ASSERTION_IMPL(#res_expr, _tmp_r_assert_rc); \
} \
}
2020-02-23 07:05:14 +00:00
#else
#define R_ASSERT(res_expr) AMS_UNUSED((res_expr));
#endif
/// Evaluates an expression that returns a result, and aborts if the result would fail.
#define R_ABORT_UNLESS(res_expr) \
{ \
if (const auto _tmp_r_abort_rc = (res_expr); AMS_UNLIKELY(R_FAILED(_tmp_r_abort_rc))) { \
AMS_CALL_ON_RESULT_ABORT_IMPL(#res_expr, _tmp_r_abort_rc); \
} \
}
/// Evaluates a boolean expression, and returns a result unless that expression is true.
#define R_UNLESS(expr, res) \
{ \
if (!(expr)) { \
R_THROW(res); \
} \
}
Implement the NCM sysmodule (closes #91) * Implement NCM * Modernize ncm_main * Remove unnecessary smExit * Give access to svcCallSecureMonitor * Stack size bump * Fix incorrect setup for NandUser's content storage entry * Fix a potential data abort when flushing the placeholder accessor cache * Fix HasFile and HasDirectory * Use r+b, not w+b * Misc fixes * errno begone * Fixed more stdio error handling * More main fixes * Various command improvements * Make dispatch tables great again * Fix logic inversion * Fixed content path generation * Bump heap size, fix CleanupAllPlaceHolder * Various fixes. Note: This contains debug stuff which will be removed later. I was getting tired of having to cherrypick tiny changes * Fixed placeholder/content deletion * Fixed incorrect content manager destruction * Prevent automatic placeholder creation on open * Fixed List implementation. Also lots of debug logging. * Removed debug code * Added a scope guard for WritePlaceHolder * Manually prevent placeholder/content appending * Revert "Removed debug code" This reverts commit d6ff261fcc8c1f26968e894b02c17a01a12ec98b. * Always cache placeholder file. Switch to ftell for preventing appending * Universally use EnsureEnabled * Abstract away file writing logic * Misc cleanup * Refactor placeholder cacheing * Remove debug code (again) * Revert "Remove debug code (again)" This reverts commit 168447d80e9640768fb1b43f04a385507c1bb5ab. * Misc changes * Fixed file modes * Fixed ContentId/PlaceHolderId alignment * Improved type safety * Fixed reinitialization * Fixed doubleup on path creation * Remove debug code * Fixed 1.0.0 booting * Correct amount of add on content * Correct main thread stack size * lr: Introducing registered data * Reorder stratosphere Makefile * Move results to libstrat * lr: Cleanup lr_redirection * lr: lr_manager tweaks * lr: Imrpoved path handling and adjust ResolveAddOnContentPath order * lr: Organise types * Add eof newlines * lr: Eliminate unnecessary vars * lr: Unnecessary vars 2 electric boogaloo * lr: Various helpers * lr: RegisteredLocationResolver helpers * ncm: Move ncm_types to libstrat * ncm: Misc cleanup * Implement NCM * Modernize ncm_main * Remove unnecessary smExit * Give access to svcCallSecureMonitor * Stack size bump * Fix incorrect setup for NandUser's content storage entry * Fix a potential data abort when flushing the placeholder accessor cache * Fix HasFile and HasDirectory * Use r+b, not w+b * Misc fixes * errno begone * Fixed more stdio error handling * More main fixes * Various command improvements * Make dispatch tables great again * Fix logic inversion * Fixed content path generation * Bump heap size, fix CleanupAllPlaceHolder * Various fixes. Note: This contains debug stuff which will be removed later. I was getting tired of having to cherrypick tiny changes * Fixed placeholder/content deletion * Fixed incorrect content manager destruction * Prevent automatic placeholder creation on open * Fixed List implementation. Also lots of debug logging. * Removed debug code * Added a scope guard for WritePlaceHolder * Manually prevent placeholder/content appending * Revert "Removed debug code" This reverts commit d6ff261fcc8c1f26968e894b02c17a01a12ec98b. * Always cache placeholder file. Switch to ftell for preventing appending * Universally use EnsureEnabled * Abstract away file writing logic * Misc cleanup * Refactor placeholder cacheing * Remove debug code (again) * Revert "Remove debug code (again)" This reverts commit 168447d80e9640768fb1b43f04a385507c1bb5ab. * Misc changes * Fixed file modes * Fixed ContentId/PlaceHolderId alignment * Improved type safety * Fixed reinitialization * Fixed doubleup on path creation * Remove debug code * Fixed 1.0.0 booting * Correct amount of add on content * Correct main thread stack size * lr: Introducing registered data * Reorder stratosphere Makefile * Move results to libstrat * lr: Cleanup lr_redirection * lr: lr_manager tweaks * lr: Imrpoved path handling and adjust ResolveAddOnContentPath order * lr: Organise types * Add eof newlines * lr: Eliminate unnecessary vars * lr: Unnecessary vars 2 electric boogaloo * lr: Various helpers * lr: RegisteredLocationResolver helpers * ncm: Move ncm_types to libstrat * ncm: Misc cleanup * Updated AddOnContentLocationResolver and RegisteredLocationResolver to 9.0.0 * Finished updating lr to 9.0.0 * Updated NCM to 9.0.0 * Fix libstrat includes * Fixed application launching * title_id_2 -> owner_tid * Updated to new-ipc * Change to using pure virtuals * Title Id -> Program Id * Fixed compilation against master * std::scoped_lock<> -> std::scoped_lock * Adopted R_UNLESS and R_CONVERT * Prefix namespace to Results * Adopt std::numeric_limits * Fixed incorrect error handling in ReadFile * Adopted AMS_ABORT_UNLESS * Adopt util::GenerateUuid() * Syntax improvements * ncm_types: Address review * Address more review comments * Updated copyrights * Address more feedback * More feedback addressed * More changes * Move dispatch tables out of interface files * Addressed remaining comments * lr: move into libstratosphere * ncm: Fix logic inversion * lr: Add comments * lr: Remove whitespace * ncm: Start addressing feedback * ncm: Cleanup InitializeContentManager * lr: support client-side usage * lr_service -> lr_api * ncm: Begin refactoring content manager * ncm: More content manager improvements * ncm: Content manager mount improvements * ldr: use lr bindings * lr bindings usage: minor fixes * ncm/lr: Pointer placement * ncm: placeholder accessor cleanup * ncm: minor fixes * ncm: refactor rights cache * ncm: content meta database cleanup * ncm: move content meta database impl out of interface file * ncm: Use const ContentMetaKey & * ncm: fix other non-const ContentMetaKey references * ncm: content meta database cleanup * ncm: content storage fixes for 2.0.0 * ncm: add missing end of file newlines * ncm: implement ContentMetaReader * ncm: client-side api * ncm: trim trailing spaces * ncm: FS_MAX_PATH-1 -> fs::EntryNameLengthMax * ncm: Use PathString and Path * fs: implement accessor wrappers for ncm * fs: implement user fs wrappers * fs: add MountSdCard * ncm: move to content manager impl * ncm: fix up main * kvdb: use fs:: * fs: Add wrappers needed for ncm * ncm: use fs bindings, other refactoring * ncm: minor fixes * fsa: fix ReadFile without size output * fs: add substorage, rom path tool * ncm: fix dangling fsdev usage * fs: fix bug in Commit * fs: fixed incorrect mode check * fs: implement Mount(System)Data * ncm: don't delete hos * results: add R_SUCCEED_IF * ams-except-ncm: use R_SUCCEED_IF * ncm: added comments * ncm: fix api definitions * ncm: use R_SUCCEED_IF * pm: think of the savings * ncm: employ kernel strats * ncm: Nintendo has 5 MiB of heap. Give ourselves 4 to be safe, pending analysis * ncm: refactor IDs, split types header into many headers * ams.mitm: use fs bindings instead of stdio * fs: SystemData uses SystemDataId * ncm: improve meta-db accuracy * ncm: inline getlatestkey * fs: improve UnsupportedOperation results * fs: modernize mount utils * ams: misc fixes for merge-errors * fs: improve unsupportedoperation results * git subrepo pull emummc subrepo: subdir: "emummc" merged: "d12dd546" upstream: origin: "https://github.com/m4xw/emuMMC" branch: "develop" commit: "d12dd546" git-subrepo: version: "0.4.1" origin: "???" commit: "???" * util: add boundedmap * ncm: minor style fixes * ncm: don't unmount if mounting fails * lr: bug fixes * ncm: implement ncm.for-initialize + ncm.for-safemode * lr: ncm::ProgramId::Invalid -> ncm::InvalidProgramId * ncm: fix open directory mode on 1.0.0 * ncm: fix fs use, implement more of < 4.0.0 for-initialize/safemode * ncm: implement packagedcontent -> content for building metadb * ncm: fix save data flag management * ncm: address some review suggestions (thanks @leoetlino!) * updater: use fs bindings * fs: implement MountCode * fs: prefer make_unique to operator new * ncm: implement remaining ContentMetaDatabaseBuilder functionality Co-authored-by: Michael Scire <SciresM@gmail.com>
2020-03-08 08:06:23 +00:00
/// Evaluates a boolean expression, and succeeds if that expression is true.
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess())
/// Helpers for pattern-matching on a result expression, if the result would fail.
#define R_CURRENT_RESULT _tmp_r_try_catch_current_result
#define R_TRY_CATCH(res_expr) \
{ \
2020-02-23 07:05:14 +00:00
const auto R_CURRENT_RESULT = (res_expr); \
if (R_FAILED(R_CURRENT_RESULT)) { \
if (false)
#define R_CATCH(...) \
} else if (::ams::result::impl::EvaluateAnyResultIncludes<__VA_ARGS__>(R_CURRENT_RESULT)) { \
if (true)
#define R_CATCH_MODULE(__module__) \
2020-04-27 17:33:51 +00:00
} else if ((R_CURRENT_RESULT).GetModule() == ::ams::R_NAMESPACE_MODULE_ID(__module__)) { \
if (true)
#define R_CONVERT(catch_type, convert_type) \
R_CATCH(catch_type) { R_THROW(static_cast<::ams::Result>(convert_type)); }
#define R_CATCH_ALL() \
} else if (R_FAILED(R_CURRENT_RESULT)) { \
if (true)
#define R_CONVERT_ALL(convert_type) \
R_CATCH_ALL() { R_THROW(static_cast<::ams::Result>(convert_type)); }
#define R_CATCH_RETHROW(catch_type) \
R_CONVERT(catch_type, R_CURRENT_RESULT)
#define R_END_TRY_CATCH \
else if (R_FAILED(R_CURRENT_RESULT)) { \
R_THROW(R_CURRENT_RESULT); \
} \
} \
}
#define R_END_TRY_CATCH_WITH_ASSERT \
else { \
R_ASSERT(R_CURRENT_RESULT); \
} \
} \
}
2020-02-23 07:05:14 +00:00
#define R_END_TRY_CATCH_WITH_ABORT_UNLESS \
else { \
2020-02-23 07:05:14 +00:00
R_ABORT_UNLESS(R_CURRENT_RESULT); \
} \
} \
}