summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/typed_address.h320
2 files changed, 321 insertions, 0 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 61ab68864..90805babe 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -132,6 +132,7 @@ add_library(common STATIC
132 time_zone.h 132 time_zone.h
133 tiny_mt.h 133 tiny_mt.h
134 tree.h 134 tree.h
135 typed_address.h
135 uint128.h 136 uint128.h
136 unique_function.h 137 unique_function.h
137 uuid.cpp 138 uuid.cpp
diff --git a/src/common/typed_address.h b/src/common/typed_address.h
new file mode 100644
index 000000000..cf7bbeae1
--- /dev/null
+++ b/src/common/typed_address.h
@@ -0,0 +1,320 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <compare>
7#include <type_traits>
8#include <fmt/format.h>
9
10#include "common/common_types.h"
11
12namespace Common {
13
14template <bool Virtual, typename T>
15class TypedAddress {
16public:
17 // Constructors.
18 constexpr inline TypedAddress() : m_address(0) {}
19 constexpr inline TypedAddress(uint64_t a) : m_address(a) {}
20
21 template <typename U>
22 constexpr inline explicit TypedAddress(const U* ptr)
23 : m_address(reinterpret_cast<uint64_t>(ptr)) {}
24
25 // Copy constructor.
26 constexpr inline TypedAddress(const TypedAddress& rhs) = default;
27
28 // Assignment operator.
29 constexpr inline TypedAddress& operator=(const TypedAddress& rhs) = default;
30
31 // Arithmetic operators.
32 template <typename I>
33 constexpr inline TypedAddress operator+(I rhs) const {
34 static_assert(std::is_integral_v<I>);
35 return m_address + rhs;
36 }
37
38 constexpr inline TypedAddress operator+(TypedAddress rhs) const {
39 return m_address + rhs.m_address;
40 }
41
42 constexpr inline TypedAddress operator++() {
43 return ++m_address;
44 }
45
46 constexpr inline TypedAddress operator++(int) {
47 return m_address++;
48 }
49
50 template <typename I>
51 constexpr inline TypedAddress operator-(I rhs) const {
52 static_assert(std::is_integral_v<I>);
53 return m_address - rhs;
54 }
55
56 constexpr inline ptrdiff_t operator-(TypedAddress rhs) const {
57 return m_address - rhs.m_address;
58 }
59
60 constexpr inline TypedAddress operator--() {
61 return --m_address;
62 }
63
64 constexpr inline TypedAddress operator--(int) {
65 return m_address--;
66 }
67
68 template <typename I>
69 constexpr inline TypedAddress operator+=(I rhs) {
70 static_assert(std::is_integral_v<I>);
71 m_address += rhs;
72 return *this;
73 }
74
75 template <typename I>
76 constexpr inline TypedAddress operator-=(I rhs) {
77 static_assert(std::is_integral_v<I>);
78 m_address -= rhs;
79 return *this;
80 }
81
82 // Logical operators.
83 constexpr inline uint64_t operator&(uint64_t mask) const {
84 return m_address & mask;
85 }
86
87 constexpr inline uint64_t operator|(uint64_t mask) const {
88 return m_address | mask;
89 }
90
91 template <typename I>
92 constexpr inline TypedAddress operator|=(I rhs) {
93 static_assert(std::is_integral_v<I>);
94 m_address |= rhs;
95 return *this;
96 }
97
98 constexpr inline uint64_t operator<<(int shift) const {
99 return m_address << shift;
100 }
101
102 constexpr inline uint64_t operator>>(int shift) const {
103 return m_address >> shift;
104 }
105
106 template <typename U>
107 constexpr inline size_t operator/(U size) const {
108 return m_address / size;
109 }
110
111 constexpr explicit operator bool() const {
112 return m_address != 0;
113 }
114
115 // constexpr inline uint64_t operator%(U align) const { return m_address % align; }
116
117 // Comparison operators.
118 constexpr bool operator==(const TypedAddress&) const = default;
119 constexpr bool operator!=(const TypedAddress&) const = default;
120 constexpr auto operator<=>(const TypedAddress&) const = default;
121
122 // For convenience, also define comparison operators versus uint64_t.
123 constexpr inline bool operator==(uint64_t rhs) const {
124 return m_address == rhs;
125 }
126
127 constexpr inline bool operator!=(uint64_t rhs) const {
128 return m_address != rhs;
129 }
130
131 // Allow getting the address explicitly, for use in accessors.
132 constexpr inline uint64_t GetValue() const {
133 return m_address;
134 }
135
136private:
137 uint64_t m_address{};
138};
139
140struct PhysicalAddressTag {};
141struct VirtualAddressTag {};
142struct ProcessAddressTag {};
143
144using PhysicalAddress = TypedAddress<false, PhysicalAddressTag>;
145using VirtualAddress = TypedAddress<true, VirtualAddressTag>;
146using ProcessAddress = TypedAddress<true, ProcessAddressTag>;
147
148// Define accessors.
149template <typename T>
150concept IsTypedAddress = std::same_as<T, PhysicalAddress> || std::same_as<T, VirtualAddress> ||
151 std::same_as<T, ProcessAddress>;
152
153template <typename T>
154constexpr inline T Null = [] {
155 if constexpr (std::is_same<T, uint64_t>::value) {
156 return 0;
157 } else {
158 static_assert(std::is_same<T, PhysicalAddress>::value ||
159 std::is_same<T, VirtualAddress>::value ||
160 std::is_same<T, ProcessAddress>::value);
161 return T(0);
162 }
163}();
164
165// Basic type validations.
166static_assert(sizeof(PhysicalAddress) == sizeof(uint64_t));
167static_assert(sizeof(VirtualAddress) == sizeof(uint64_t));
168static_assert(sizeof(ProcessAddress) == sizeof(uint64_t));
169
170static_assert(std::is_trivially_copyable_v<PhysicalAddress>);
171static_assert(std::is_trivially_copyable_v<VirtualAddress>);
172static_assert(std::is_trivially_copyable_v<ProcessAddress>);
173
174static_assert(std::is_trivially_copy_constructible_v<PhysicalAddress>);
175static_assert(std::is_trivially_copy_constructible_v<VirtualAddress>);
176static_assert(std::is_trivially_copy_constructible_v<ProcessAddress>);
177
178static_assert(std::is_trivially_move_constructible_v<PhysicalAddress>);
179static_assert(std::is_trivially_move_constructible_v<VirtualAddress>);
180static_assert(std::is_trivially_move_constructible_v<ProcessAddress>);
181
182static_assert(std::is_trivially_copy_assignable_v<PhysicalAddress>);
183static_assert(std::is_trivially_copy_assignable_v<VirtualAddress>);
184static_assert(std::is_trivially_copy_assignable_v<ProcessAddress>);
185
186static_assert(std::is_trivially_move_assignable_v<PhysicalAddress>);
187static_assert(std::is_trivially_move_assignable_v<VirtualAddress>);
188static_assert(std::is_trivially_move_assignable_v<ProcessAddress>);
189
190static_assert(std::is_trivially_destructible_v<PhysicalAddress>);
191static_assert(std::is_trivially_destructible_v<VirtualAddress>);
192static_assert(std::is_trivially_destructible_v<ProcessAddress>);
193
194static_assert(Null<uint64_t> == 0);
195static_assert(Null<PhysicalAddress> == Null<uint64_t>);
196static_assert(Null<VirtualAddress> == Null<uint64_t>);
197static_assert(Null<ProcessAddress> == Null<uint64_t>);
198
199// Constructor/assignment validations.
200static_assert([] {
201 const PhysicalAddress a(5);
202 PhysicalAddress b(a);
203 return b;
204}() == PhysicalAddress(5));
205static_assert([] {
206 const PhysicalAddress a(5);
207 PhysicalAddress b(10);
208 b = a;
209 return b;
210}() == PhysicalAddress(5));
211
212// Arithmetic validations.
213static_assert(PhysicalAddress(10) + 5 == PhysicalAddress(15));
214static_assert(PhysicalAddress(10) - 5 == PhysicalAddress(5));
215static_assert([] {
216 PhysicalAddress v(10);
217 v += 5;
218 return v;
219}() == PhysicalAddress(15));
220static_assert([] {
221 PhysicalAddress v(10);
222 v -= 5;
223 return v;
224}() == PhysicalAddress(5));
225static_assert(PhysicalAddress(10)++ == PhysicalAddress(10));
226static_assert(++PhysicalAddress(10) == PhysicalAddress(11));
227static_assert(PhysicalAddress(10)-- == PhysicalAddress(10));
228static_assert(--PhysicalAddress(10) == PhysicalAddress(9));
229
230// Logical validations.
231static_assert((PhysicalAddress(0b11111111) >> 1) == 0b01111111);
232static_assert((PhysicalAddress(0b10101010) >> 1) == 0b01010101);
233static_assert((PhysicalAddress(0b11111111) << 1) == 0b111111110);
234static_assert((PhysicalAddress(0b01010101) << 1) == 0b10101010);
235static_assert((PhysicalAddress(0b11111111) & 0b01010101) == 0b01010101);
236static_assert((PhysicalAddress(0b11111111) & 0b10101010) == 0b10101010);
237static_assert((PhysicalAddress(0b01010101) & 0b10101010) == 0b00000000);
238static_assert((PhysicalAddress(0b00000000) | 0b01010101) == 0b01010101);
239static_assert((PhysicalAddress(0b11111111) | 0b01010101) == 0b11111111);
240static_assert((PhysicalAddress(0b10101010) | 0b01010101) == 0b11111111);
241
242// Comparisons.
243static_assert(PhysicalAddress(0) == PhysicalAddress(0));
244static_assert(PhysicalAddress(0) != PhysicalAddress(1));
245static_assert(PhysicalAddress(0) < PhysicalAddress(1));
246static_assert(PhysicalAddress(0) <= PhysicalAddress(1));
247static_assert(PhysicalAddress(1) > PhysicalAddress(0));
248static_assert(PhysicalAddress(1) >= PhysicalAddress(0));
249
250static_assert(!(PhysicalAddress(0) == PhysicalAddress(1)));
251static_assert(!(PhysicalAddress(0) != PhysicalAddress(0)));
252static_assert(!(PhysicalAddress(1) < PhysicalAddress(0)));
253static_assert(!(PhysicalAddress(1) <= PhysicalAddress(0)));
254static_assert(!(PhysicalAddress(0) > PhysicalAddress(1)));
255static_assert(!(PhysicalAddress(0) >= PhysicalAddress(1)));
256
257} // namespace Common
258
259template <bool Virtual, typename T>
260constexpr inline uint64_t GetInteger(Common::TypedAddress<Virtual, T> address) {
261 return address.GetValue();
262}
263
264template <>
265struct fmt::formatter<Common::PhysicalAddress> {
266 constexpr auto parse(fmt::format_parse_context& ctx) {
267 return ctx.begin();
268 }
269 template <typename FormatContext>
270 auto format(const Common::PhysicalAddress& addr, FormatContext& ctx) {
271 return fmt::format_to(ctx.out(), "{:#x}", static_cast<u64>(addr.GetValue()));
272 }
273};
274
275template <>
276struct fmt::formatter<Common::ProcessAddress> {
277 constexpr auto parse(fmt::format_parse_context& ctx) {
278 return ctx.begin();
279 }
280 template <typename FormatContext>
281 auto format(const Common::ProcessAddress& addr, FormatContext& ctx) {
282 return fmt::format_to(ctx.out(), "{:#x}", static_cast<u64>(addr.GetValue()));
283 }
284};
285
286template <>
287struct fmt::formatter<Common::VirtualAddress> {
288 constexpr auto parse(fmt::format_parse_context& ctx) {
289 return ctx.begin();
290 }
291 template <typename FormatContext>
292 auto format(const Common::VirtualAddress& addr, FormatContext& ctx) {
293 return fmt::format_to(ctx.out(), "{:#x}", static_cast<u64>(addr.GetValue()));
294 }
295};
296
297namespace std {
298
299template <>
300struct hash<Common::PhysicalAddress> {
301 size_t operator()(const Common::PhysicalAddress& k) const noexcept {
302 return k.GetValue();
303 }
304};
305
306template <>
307struct hash<Common::ProcessAddress> {
308 size_t operator()(const Common::ProcessAddress& k) const noexcept {
309 return k.GetValue();
310 }
311};
312
313template <>
314struct hash<Common::VirtualAddress> {
315 size_t operator()(const Common::VirtualAddress& k) const noexcept {
316 return k.GetValue();
317 }
318};
319
320} // namespace std