diff --git a/rpcs3/util/endian.hpp b/rpcs3/util/endian.hpp index e826856cfd..6d9aa7489d 100644 --- a/rpcs3/util/endian.hpp +++ b/rpcs3/util/endian.hpp @@ -221,6 +221,29 @@ namespace stx } } +private: + // Compatible bit pattern cast + template + static To right_arg_cast(const T2& rhs) noexcept + { + return std::bit_cast(static_cast>(rhs)); + } + + template + static To right_arg_cast(const se_t& rhs) noexcept + { + if constexpr ((std::is_integral_v || std::is_enum_v) && std::is_convertible_v && sizeof(R) == sizeof(T)) + { + // Optimization: allow to reuse bit pattern of any se_t with bit-compatible type + return std::bit_cast(rhs); + } + else + { + return std::bit_cast(static_cast>(rhs.value())); + } + } + +public: template bool operator==(const T2& rhs) const noexcept { @@ -230,13 +253,14 @@ namespace stx { if constexpr (sizeof(T) >= sizeof(R)) { - if constexpr (std::is_enum_v && std::is_convertible_v && std::is_convertible_v) + if constexpr (std::is_convertible_v && std::is_convertible_v) { - return std::bit_cast(m_data) == std::bit_cast(static_cast>(rhs)); + return std::bit_cast(m_data) == right_arg_cast(rhs); } else { - return std::bit_cast(m_data) == std::bit_cast(static_cast>(rhs)); + // Compare with strict type on the right side (possibly scoped enum) + return std::bit_cast(m_data) == right_arg_cast(rhs); } } } @@ -251,6 +275,63 @@ namespace stx return !operator==(rhs); } +private: + template + static constexpr bool check_args_for_bitwise_op() + { + using R = simple_t; + + if constexpr ((std::is_integral_v || std::is_enum_v) && (std::is_integral_v || std::is_enum_v)) + { + if constexpr (std::is_convertible_v && std::is_convertible_v && sizeof(T) >= sizeof(R)) + { + return true; + } + } + + return false; + } + +public: + template + auto operator&(const T2& rhs) const noexcept + { + if constexpr (check_args_for_bitwise_op()) + { + return std::bit_cast>(static_cast(std::bit_cast(m_data) & right_arg_cast(rhs))); + } + else + { + return value() & rhs; + } + } + + template + auto operator|(const T2& rhs) const noexcept + { + if constexpr (check_args_for_bitwise_op()) + { + return std::bit_cast>(static_cast(std::bit_cast(m_data) | right_arg_cast(rhs))); + } + else + { + return value() | rhs; + } + } + + template + auto operator^(const T2& rhs) const noexcept + { + if constexpr (check_args_for_bitwise_op()) + { + return std::bit_cast>(static_cast(std::bit_cast(m_data) ^ right_arg_cast(rhs))); + } + else + { + return value() ^ rhs; + } + } + template se_t& operator+=(const T1& rhs) {