#pragma once namespace vm { // Tag which allows to construct vm objects from the address value static struct addr_tag_t {} constexpr addr{}; template class _ptr_base; template class _ref_base { AT m_addr; static_assert(!std::is_pointer::value, "vm::_ref_base<> error: invalid type (pointer)"); static_assert(!std::is_reference::value, "vm::_ref_base<> error: invalid type (reference)"); static_assert(!std::is_function::value, "vm::_ref_base<> error: invalid type (function)"); static_assert(!std::is_void::value, "vm::_ref_base<> error: invalid type (void)"); public: using type = T; using addr_type = std::remove_cv_t; _ref_base() = default; _ref_base(const _ref_base&) = default; constexpr _ref_base(addr_type addr, const addr_tag_t&) : m_addr(addr) { } constexpr addr_type addr() const { return m_addr; } T& get_ref() const { return *static_cast(vm::base(VM_CAST(m_addr))); } // convert to vm pointer vm::_ptr_base ptr() const { return{ VM_CAST(m_addr), vm::addr }; } operator to_ne_t() const { return get_ref(); } operator T&() const { return get_ref(); } T& operator =(const _ref_base& right) { return get_ref() = right.get_ref(); } T& operator =(const T& right) const { return get_ref() = right; } decltype(auto) operator ++(int) { return get_ref()++; } decltype(auto) operator ++() { return ++get_ref(); } decltype(auto) operator --(int) { return get_ref()--; } decltype(auto) operator --() { return --get_ref(); } template decltype(auto) operator +=(const T2& right) { return get_ref() += right; } template decltype(auto) operator -=(const T2& right) { return get_ref() -= right; } template decltype(auto) operator *=(const T2& right) { return get_ref() *= right; } template decltype(auto) operator /=(const T2& right) { return get_ref() /= right; } template decltype(auto) operator %=(const T2& right) { return get_ref() %= right; } template decltype(auto) operator &=(const T2& right) { return get_ref() &= right; } template decltype(auto) operator |=(const T2& right) { return get_ref() |= right; } template decltype(auto) operator ^=(const T2& right) { return get_ref() ^= right; } template decltype(auto) operator <<=(const T2& right) { return get_ref() <<= right; } template decltype(auto) operator >>=(const T2& right) { return get_ref() >>= right; } }; // Native endianness reference to LE data template using refl = _ref_base, AT>; // Native endianness reference to BE data template using refb = _ref_base, AT>; // BE reference to LE data template using brefl = _ref_base, to_be_t>; // BE reference to BE data template using brefb = _ref_base, to_be_t>; // LE reference to LE data template using lrefl = _ref_base, to_le_t>; // LE reference to BE data template using lrefb = _ref_base, to_le_t>; namespace ps3 { // default reference for PS3 HLE functions (Native endianness reference to BE data) template using ref = refb; // default reference for PS3 HLE structures (BE reference to BE data) template using bref = brefb; } namespace psv { // default reference for PSV HLE functions (Native endianness reference to LE data) template using ref = refl; // default reference for PSV HLE structures (LE reference to LE data) template using lref = lrefl; } } // external specialization for to_se<> (change AT's endianness to BE/LE) template struct to_se, Se> { using type = vm::_ref_base::type>; }; // external specialization for to_ne<> (change AT's endianness to native) template struct to_ne> { using type = vm::_ref_base::type>; }; namespace fmt { // external specialization for fmt::format function template struct unveil, false> { using result_type = typename unveil::result_type; static inline result_type get_value(const vm::_ref_base& arg) { return unveil::get_value(arg.addr()); } }; } // external specializations for PPU GPR (SC_FUNC.h, CB_FUNC.h) template struct cast_ppu_gpr; template struct cast_ppu_gpr, false> { static inline u64 to_gpr(const vm::_ref_base& value) { return cast_ppu_gpr::value>::to_gpr(value.addr()); } static inline vm::_ref_base from_gpr(const u64 reg) { return{ cast_ppu_gpr::value>::from_gpr(reg), vm::addr }; } }; // external specializations for ARMv7 GPR template struct cast_armv7_gpr; template struct cast_armv7_gpr, false> { static inline u32 to_gpr(const vm::_ref_base& value) { return cast_armv7_gpr::value>::to_gpr(value.addr()); } static inline vm::_ref_base from_gpr(const u32 reg) { return{ cast_armv7_gpr::value>::from_gpr(reg), vm::addr }; } };