// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include #include "common/common_types.h" namespace Common { template class TypedAddress { public: // Constructors. constexpr inline TypedAddress() : m_address(0) {} constexpr inline TypedAddress(uint64_t a) : m_address(a) {} template constexpr inline explicit TypedAddress(const U* ptr) : m_address(reinterpret_cast(ptr)) {} // Copy constructor. constexpr inline TypedAddress(const TypedAddress& rhs) = default; // Assignment operator. constexpr inline TypedAddress& operator=(const TypedAddress& rhs) = default; // Arithmetic operators. template constexpr inline TypedAddress operator+(I rhs) const { static_assert(std::is_integral_v); return m_address + rhs; } constexpr inline TypedAddress operator+(TypedAddress rhs) const { return m_address + rhs.m_address; } constexpr inline TypedAddress operator++() { return ++m_address; } constexpr inline TypedAddress operator++(int) { return m_address++; } template constexpr inline TypedAddress operator-(I rhs) const { static_assert(std::is_integral_v); return m_address - rhs; } constexpr inline ptrdiff_t operator-(TypedAddress rhs) const { return m_address - rhs.m_address; } constexpr inline TypedAddress operator--() { return --m_address; } constexpr inline TypedAddress operator--(int) { return m_address--; } template constexpr inline TypedAddress operator+=(I rhs) { static_assert(std::is_integral_v); m_address += rhs; return *this; } template constexpr inline TypedAddress operator-=(I rhs) { static_assert(std::is_integral_v); m_address -= rhs; return *this; } // Logical operators. constexpr inline uint64_t operator&(uint64_t mask) const { return m_address & mask; } constexpr inline uint64_t operator|(uint64_t mask) const { return m_address | mask; } template constexpr inline TypedAddress operator|=(I rhs) { static_assert(std::is_integral_v); m_address |= rhs; return *this; } constexpr inline uint64_t operator<<(int shift) const { return m_address << shift; } constexpr inline uint64_t operator>>(int shift) const { return m_address >> shift; } template constexpr inline size_t operator/(U size) const { return m_address / size; } constexpr explicit operator bool() const { return m_address != 0; } // constexpr inline uint64_t operator%(U align) const { return m_address % align; } // Comparison operators. constexpr bool operator==(const TypedAddress&) const = default; constexpr auto operator<=>(const TypedAddress&) const = default; // For convenience, also define comparison operators versus uint64_t. constexpr inline bool operator==(uint64_t rhs) const { return m_address == rhs; } // Allow getting the address explicitly, for use in accessors. constexpr inline uint64_t GetValue() const { return m_address; } private: uint64_t m_address{}; }; struct PhysicalAddressTag {}; struct VirtualAddressTag {}; struct ProcessAddressTag {}; using PhysicalAddress = TypedAddress; using VirtualAddress = TypedAddress; using ProcessAddress = TypedAddress; // Define accessors. template concept IsTypedAddress = std::same_as || std::same_as || std::same_as; template constexpr inline T Null = [] { if constexpr (std::is_same::value) { return 0; } else { static_assert(std::is_same::value || std::is_same::value || std::is_same::value); return T(0); } }(); // Basic type validations. static_assert(sizeof(PhysicalAddress) == sizeof(uint64_t)); static_assert(sizeof(VirtualAddress) == sizeof(uint64_t)); static_assert(sizeof(ProcessAddress) == sizeof(uint64_t)); static_assert(std::is_trivially_copyable_v); static_assert(std::is_trivially_copyable_v); static_assert(std::is_trivially_copyable_v); static_assert(std::is_trivially_copy_constructible_v); static_assert(std::is_trivially_copy_constructible_v); static_assert(std::is_trivially_copy_constructible_v); static_assert(std::is_trivially_move_constructible_v); static_assert(std::is_trivially_move_constructible_v); static_assert(std::is_trivially_move_constructible_v); static_assert(std::is_trivially_copy_assignable_v); static_assert(std::is_trivially_copy_assignable_v); static_assert(std::is_trivially_copy_assignable_v); static_assert(std::is_trivially_move_assignable_v); static_assert(std::is_trivially_move_assignable_v); static_assert(std::is_trivially_move_assignable_v); static_assert(std::is_trivially_destructible_v); static_assert(std::is_trivially_destructible_v); static_assert(std::is_trivially_destructible_v); static_assert(Null == 0); static_assert(Null == Null); static_assert(Null == Null); static_assert(Null == Null); // Constructor/assignment validations. static_assert([] { const PhysicalAddress a(5); PhysicalAddress b(a); return b; }() == PhysicalAddress(5)); static_assert([] { const PhysicalAddress a(5); PhysicalAddress b(10); b = a; return b; }() == PhysicalAddress(5)); // Arithmetic validations. static_assert(PhysicalAddress(10) + 5 == PhysicalAddress(15)); static_assert(PhysicalAddress(10) - 5 == PhysicalAddress(5)); static_assert([] { PhysicalAddress v(10); v += 5; return v; }() == PhysicalAddress(15)); static_assert([] { PhysicalAddress v(10); v -= 5; return v; }() == PhysicalAddress(5)); static_assert(PhysicalAddress(10)++ == PhysicalAddress(10)); static_assert(++PhysicalAddress(10) == PhysicalAddress(11)); static_assert(PhysicalAddress(10)-- == PhysicalAddress(10)); static_assert(--PhysicalAddress(10) == PhysicalAddress(9)); // Logical validations. static_assert((PhysicalAddress(0b11111111) >> 1) == 0b01111111); static_assert((PhysicalAddress(0b10101010) >> 1) == 0b01010101); static_assert((PhysicalAddress(0b11111111) << 1) == 0b111111110); static_assert((PhysicalAddress(0b01010101) << 1) == 0b10101010); static_assert((PhysicalAddress(0b11111111) & 0b01010101) == 0b01010101); static_assert((PhysicalAddress(0b11111111) & 0b10101010) == 0b10101010); static_assert((PhysicalAddress(0b01010101) & 0b10101010) == 0b00000000); static_assert((PhysicalAddress(0b00000000) | 0b01010101) == 0b01010101); static_assert((PhysicalAddress(0b11111111) | 0b01010101) == 0b11111111); static_assert((PhysicalAddress(0b10101010) | 0b01010101) == 0b11111111); // Comparisons. static_assert(PhysicalAddress(0) == PhysicalAddress(0)); static_assert(PhysicalAddress(0) != PhysicalAddress(1)); static_assert(PhysicalAddress(0) < PhysicalAddress(1)); static_assert(PhysicalAddress(0) <= PhysicalAddress(1)); static_assert(PhysicalAddress(1) > PhysicalAddress(0)); static_assert(PhysicalAddress(1) >= PhysicalAddress(0)); static_assert(!(PhysicalAddress(0) == PhysicalAddress(1))); static_assert(!(PhysicalAddress(0) != PhysicalAddress(0))); static_assert(!(PhysicalAddress(1) < PhysicalAddress(0))); static_assert(!(PhysicalAddress(1) <= PhysicalAddress(0))); static_assert(!(PhysicalAddress(0) > PhysicalAddress(1))); static_assert(!(PhysicalAddress(0) >= PhysicalAddress(1))); } // namespace Common template constexpr inline uint64_t GetInteger(Common::TypedAddress address) { return address.GetValue(); } template <> struct fmt::formatter { constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); } template auto format(const Common::PhysicalAddress& addr, FormatContext& ctx) { return fmt::format_to(ctx.out(), "{:#x}", static_cast(addr.GetValue())); } }; template <> struct fmt::formatter { constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); } template auto format(const Common::ProcessAddress& addr, FormatContext& ctx) { return fmt::format_to(ctx.out(), "{:#x}", static_cast(addr.GetValue())); } }; template <> struct fmt::formatter { constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); } template auto format(const Common::VirtualAddress& addr, FormatContext& ctx) { return fmt::format_to(ctx.out(), "{:#x}", static_cast(addr.GetValue())); } }; namespace std { template <> struct hash { size_t operator()(const Common::PhysicalAddress& k) const noexcept { return k.GetValue(); } }; template <> struct hash { size_t operator()(const Common::ProcessAddress& k) const noexcept { return k.GetValue(); } }; template <> struct hash { size_t operator()(const Common::VirtualAddress& k) const noexcept { return k.GetValue(); } }; } // namespace std