#pragma once namespace vm { template struct _ref_base { AT m_addr; // don't access directly 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)"); AT addr() const { return m_addr; } template static std::enable_if_t::value, _ref_base> make(const AT2& addr) { return{ addr }; } T& get_ref() const { return vm::get_ref(VM_CAST(m_addr)); } T& priv_ref() const { return vm::priv_ref(VM_CAST(m_addr)); } // TODO: conversion operator (seems hard to define it correctly) //template::value || std::is_convertible, CT>::value>> operator CT() const //{ // return get_ref(); //} operator to_ne_t() const { return get_ref(); } explicit operator T&() const { return get_ref(); } // copy assignment operator: // returns T& by default, this may be wrong if called assignment operator has different return type T& operator =(const _ref_base& right) { static_assert(!std::is_const::value, "vm::_ref_base<> error: operator= is not available for const reference"); return get_ref() = right.get_ref(); } template auto operator =(const _ref_base& right) const -> decltype(std::declval() = std::declval()) { return get_ref() = right.get_ref(); } template auto operator =(const CT& right) const -> decltype(std::declval() = std::declval()) { 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; } } // postfix increment operator for vm::_ref_base template inline auto operator ++(const vm::_ref_base& ref, int) -> decltype(std::declval()++) { return ref.get_ref()++; } // prefix increment operator for vm::_ref_base template inline auto operator ++(const vm::_ref_base& ref) -> decltype(++std::declval()) { return ++ref.get_ref(); } // postfix decrement operator for vm::_ref_base template inline auto operator --(const vm::_ref_base& ref, int) -> decltype(std::declval()--) { return ref.get_ref()--; } // prefix decrement operator for vm::_ref_base template inline auto operator --(const vm::_ref_base& ref) -> decltype(--std::declval()) { return --ref.get_ref(); } // addition assignment operator for vm::_ref_base template inline auto operator +=(const vm::_ref_base& ref, const T2& right) -> decltype(std::declval() += std::declval()) { return ref.get_ref() += right; } // subtraction assignment operator for vm::_ref_base template inline auto operator -=(const vm::_ref_base& ref, const T2& right) -> decltype(std::declval() -= std::declval()) { return ref.get_ref() -= right; } // multiplication assignment operator for vm::_ref_base template inline auto operator *=(const vm::_ref_base& ref, const T2& right) -> decltype(std::declval() *= std::declval()) { return ref.get_ref() *= right; } // division assignment operator for vm::_ref_base template inline auto operator /=(const vm::_ref_base& ref, const T2& right) -> decltype(std::declval() /= std::declval()) { return ref.get_ref() /= right; } // modulo assignment operator for vm::_ref_base template inline auto operator %=(const vm::_ref_base& ref, const T2& right) -> decltype(std::declval() %= std::declval()) { return ref.get_ref() %= right; } // bitwise AND assignment operator for vm::_ref_base template inline auto operator &=(const vm::_ref_base& ref, const T2& right) -> decltype(std::declval() &= std::declval()) { return ref.get_ref() &= right; } // bitwise OR assignment operator for vm::_ref_base template inline auto operator |=(const vm::_ref_base& ref, const T2& right) -> decltype(std::declval() |= std::declval()) { return ref.get_ref() |= right; } // bitwise XOR assignment operator for vm::_ref_base template inline auto operator ^=(const vm::_ref_base& ref, const T2& right) -> decltype(std::declval() ^= std::declval()) { return ref.get_ref() ^= right; } // bitwise left shift assignment operator for vm::_ref_base template inline auto operator <<=(const vm::_ref_base& ref, const T2& right) -> decltype(std::declval() <<= std::declval()) { return ref.get_ref() <<= right; } // bitwise right shift assignment operator for vm::_ref_base template inline auto operator >>=(const vm::_ref_base& ref, const T2& right) -> decltype(std::declval() >>= std::declval()) { return ref.get_ref() >>= right; } // external specialization for is_be_t<> (true if AT's endianness is BE) template struct is_be_t> : public std::integral_constant::value> { }; // external specialization for is_le_t<> (true if AT's endianness is LE) template struct is_le_t> : public std::integral_constant::value> { }; // external specialization for to_ne_t<> (change AT's endianness to native) template struct to_ne> { using type = vm::_ref_base>; }; // external specialization for to_be_t<> (change AT's endianness to BE) template struct to_be> { using type = vm::_ref_base>; }; // external specialization for to_le_t<> (change AT's endianness to LE) template struct to_le> { using type = vm::_ref_base>; }; namespace fmt { // external specialization for fmt::format function template struct unveil, false> { using result_type = typename unveil::result_type; force_inline static 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> { force_inline static u64 to_gpr(const vm::_ref_base& value) { return cast_ppu_gpr::value>::to_gpr(value.addr()); } force_inline static vm::_ref_base from_gpr(const u64 reg) { return vm::_ref_base::make(cast_ppu_gpr::value>::from_gpr(reg)); } }; // external specializations for ARMv7 GPR template struct cast_armv7_gpr; template struct cast_armv7_gpr, false> { force_inline static u32 to_gpr(const vm::_ref_base& value) { return cast_armv7_gpr::value>::to_gpr(value.addr()); } force_inline static vm::_ref_base from_gpr(const u32 reg) { return vm::_ref_base::make(cast_armv7_gpr::value>::from_gpr(reg)); } };