ReXGlue SDK
Loading...
Searching...
No Matches
types.h
Go to the documentation of this file.
1
13
14#pragma once
15
16#include <atomic>
17#include <bit>
18#include <compare>
19#include <concepts>
20#include <cstddef>
21#include <cstdint>
22#include <cstring>
23#include <string_view>
24#include <type_traits>
25
26#include <rex/assert.h>
27#include <rex/platform.h>
28
29static_assert((std::endian::native == std::endian::big) ||
30 (std::endian::native == std::endian::little));
31
32namespace rex {
33
34using u8 = uint8_t;
35using u16 = uint16_t;
36using u32 = uint32_t;
37using u64 = uint64_t;
38
39using i8 = int8_t;
40using i16 = int16_t;
41using i32 = int32_t;
42using i64 = int64_t;
43
44using f32 = float;
45using f64 = double;
46
47static_assert(sizeof(f32) == 4, "f32 must be 4 bytes");
48static_assert(sizeof(f64) == 8, "f64 must be 8 bytes");
49
51template <class T>
52constexpr T byte_swap(T value) noexcept {
53 static_assert(sizeof(T) == 8 || sizeof(T) == 4 || sizeof(T) == 2 || sizeof(T) == 1,
54 "byte_swap(T value): Type T has illegal size");
55 if constexpr (sizeof(T) == 1) {
56 return value;
57 } else {
58 using UintT =
59 std::conditional_t<sizeof(T) == 8, u64, std::conditional_t<sizeof(T) == 4, u32, u16>>;
60 return std::bit_cast<T>(std::byteswap(std::bit_cast<UintT>(value)));
61 }
62}
63
65template <typename T, std::endian E>
66struct EndianValue {
67 using value_type = T;
68
69 EndianValue() = default;
70
71 EndianValue(const T& src) { Set(src); }
72
73 EndianValue(const EndianValue&) = default;
74 EndianValue& operator=(const EndianValue&) = default;
75
79 operator T() const { return Get(); }
80
82 void Set(const T& src) {
83 if constexpr (std::endian::native == E) {
84 value = src;
85 } else {
86 value = rex::byte_swap(src);
87 }
88 }
89
93 T Get() const {
94 if constexpr (std::endian::native == E) {
95 return value;
96 }
97 return rex::byte_swap(value);
98 }
99
105 T Load(std::memory_order order) const {
106 static_assert(std::atomic_ref<T>::is_always_lock_free);
107 REX_ASSERT(std::bit_cast<uintptr_t>(&value) % std::atomic_ref<T>::required_alignment == 0);
108 const T raw = std::atomic_ref<T>(const_cast<T&>(value)).load(order);
109 if constexpr (std::endian::native == E) {
110 return raw;
111 }
112 return rex::byte_swap(raw);
113 }
114
116 void Store(T src, std::memory_order order) {
117 static_assert(std::atomic_ref<T>::is_always_lock_free);
118 REX_ASSERT(std::bit_cast<uintptr_t>(&value) % std::atomic_ref<T>::required_alignment == 0);
119 if constexpr (std::endian::native != E) {
120 src = rex::byte_swap(src);
121 }
122 std::atomic_ref<T>(value).store(src, order);
123 }
124
132 bool CompareExchange(T& expected, T desired, std::memory_order order) {
133 static_assert(std::atomic_ref<T>::is_always_lock_free);
134 REX_ASSERT(std::bit_cast<uintptr_t>(&value) % std::atomic_ref<T>::required_alignment == 0);
135 T raw_expected = expected;
136 if constexpr (std::endian::native != E) {
137 raw_expected = rex::byte_swap(expected);
138 desired = rex::byte_swap(desired);
139 }
140 if (std::atomic_ref<T>(value).compare_exchange_strong(raw_expected, desired, order)) {
141 return true;
142 }
143 if constexpr (std::endian::native != E) {
144 expected = rex::byte_swap(raw_expected);
145 } else {
146 expected = raw_expected;
147 }
148 return false;
149 }
150
151 EndianValue<T, E>& operator+=(int a) {
152 *this = *this + a;
153 return *this;
154 }
155
156 EndianValue<T, E>& operator-=(int a) {
157 *this = *this - a;
158 return *this;
159 }
160
161 EndianValue<T, E>& operator++() {
162 *this += 1;
163 return *this;
164 }
165
166 EndianValue<T, E> operator++(int) {
167 *this += 1;
168 return (*this - 1);
169 }
170
171 EndianValue<T, E>& operator--() {
172 *this -= 1;
173 return *this;
174 }
175
176 EndianValue<T, E> operator--(int) {
177 *this -= 1;
178 return (*this + 1);
179 }
180
182};
183
184template <typename T>
186
187template <typename T>
189
190template <typename T>
191struct IsBEType : std::false_type {};
192
193template <typename T>
194struct IsBEType<rex::BE<T>> : std::true_type {};
195
196template <typename T>
197inline constexpr bool is_be_type_v = IsBEType<T>::value;
198
199using GuestAddrT = u32;
200using host_addr_t = uintptr_t;
201
203using be_u8 = u8;
204using be_u16 = BE<u16>;
205using be_u32 = BE<u32>;
206using be_u64 = BE<u64>;
207
209using be_i8 = i8;
210using be_i16 = BE<i16>;
211using be_i32 = BE<i32>;
212using be_i64 = BE<i64>;
213
214using be_f32 = BE<f32>;
215using be_f64 = BE<f64>;
216
217} // namespace rex
218
219using u8 = rex::u8;
220using i8 = rex::i8;
221using u16 = rex::u16;
222using i16 = rex::i16;
223using u32 = rex::u32;
224using i32 = rex::i32;
225using u64 = rex::u64;
226using i64 = rex::i64;
227using f32 = rex::f32;
228using f64 = rex::f64;
229
230using be_u16 = rex::be_u16;
231using be_u32 = rex::be_u32;
232using be_u64 = rex::be_u64;
233using be_i16 = rex::be_i16;
234using be_i32 = rex::be_i32;
235using be_i64 = rex::be_i64;
236using be_f32 = rex::be_f32;
237using be_f64 = rex::be_f64;
238
239namespace rex {
240
242constexpr size_t operator""_KiB(unsigned long long int x) {
243 return 1024ULL * x;
244}
245
247constexpr size_t operator""_MiB(unsigned long long int x) {
248 return 1024_KiB * x;
249}
250
252constexpr size_t operator""_GiB(unsigned long long int x) {
253 return 1024_MiB * x;
254}
255
257constexpr size_t operator""_TiB(unsigned long long int x) {
258 return 1024_GiB * x;
259}
260
262constexpr size_t operator""_PiB(unsigned long long int x) {
263 return 1024_TiB * x;
264}
265
266} // namespace rex
#define REX_ASSERT(cond,...)
Definition assert.h:84
Definition app.h:36
i8 be_i8
Definition types.h:209
constexpr T byte_swap(T value) noexcept
Definition types.h:52
u8 be_u8
Definition types.h:203
Platform flags, packing macros and export markers.
Definition types.h:66
T Get() const
Definition types.h:93
void Set(const T &src)
Definition types.h:82
void Store(T src, std::memory_order order)
Definition types.h:116
T Load(std::memory_order order) const
Definition types.h:105
bool CompareExchange(T &expected, T desired, std::memory_order order)
Definition types.h:132
Definition types.h:191