ReXGlue SDK
Loading...
Searching...
No Matches
endian.h
Go to the documentation of this file.
1
12
13#pragma once
14
15#include <bit>
16#include <cstdint>
17#include <cstring>
18#include <stdexcept>
19#include <string>
20#include <string_view>
21#include <type_traits>
22
23#include <rex/platform.h>
24#include <rex/assert.h>
25#include <rex/types.h>
26
27namespace rex::memory {
28
34REX_API void Copy128Aligned(void* dest, const void* src, size_t count);
35
41REX_API void copy_and_swap_16_aligned(void* dest, const void* src, size_t count);
42
48REX_API void copy_and_swap_16_unaligned(void* dest, const void* src, size_t count);
49
55REX_API void copy_and_swap_32_aligned(void* dest, const void* src, size_t count);
56
62REX_API void copy_and_swap_32_unaligned(void* dest, const void* src, size_t count);
63
69REX_API void copy_and_swap_64_aligned(void* dest, const void* src, size_t count);
70
76REX_API void copy_and_swap_64_unaligned(void* dest, const void* src, size_t count);
77
83REX_API void copy_and_swap_16_in_32_aligned(void* dest, const void* src, size_t count);
84
90REX_API void copy_and_swap_16_in_32_unaligned(void* dest, const void* src, size_t count);
91
97template <typename T>
98void copy_and_swap(T* dest, const T* src, size_t count) {
99 bool is_aligned =
100 reinterpret_cast<uintptr_t>(dest) % 32 == 0 && reinterpret_cast<uintptr_t>(src) % 32 == 0;
101 if (sizeof(T) == 1) {
102 std::memcpy(dest, src, count);
103 } else if (sizeof(T) == 2) {
104 auto ps = reinterpret_cast<const u16*>(src);
105 auto pd = reinterpret_cast<u16*>(dest);
106 if (is_aligned) {
107 copy_and_swap_16_aligned(pd, ps, count);
108 } else {
109 copy_and_swap_16_unaligned(pd, ps, count);
110 }
111 } else if (sizeof(T) == 4) {
112 auto ps = reinterpret_cast<const u32*>(src);
113 auto pd = reinterpret_cast<u32*>(dest);
114 if (is_aligned) {
115 copy_and_swap_32_aligned(pd, ps, count);
116 } else {
117 copy_and_swap_32_unaligned(pd, ps, count);
118 }
119 } else if (sizeof(T) == 8) {
120 auto ps = reinterpret_cast<const u64*>(src);
121 auto pd = reinterpret_cast<u64*>(dest);
122 if (is_aligned) {
123 copy_and_swap_64_aligned(pd, ps, count);
124 } else {
125 copy_and_swap_64_unaligned(pd, ps, count);
126 }
127 } else {
128 REX_ASSERT_ALWAYS("Invalid memory::copy_and_swap size");
129 }
130}
131
133template <typename T>
134inline T load(const void* mem) {
135 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
136 T result;
137 std::memcpy(&result, mem, sizeof(T));
138 return result;
139}
140
147template <typename T>
148inline T load_and_swap(const void* mem) {
149 return byte_swap(load<T>(mem));
150}
151
157template <>
158inline std::string load_and_swap<std::string>(const void* mem) {
159 std::string value;
160 for (i32 i = 0;; ++i) {
161 auto c = load_and_swap<u8>(reinterpret_cast<const u8*>(mem) + i);
162 if (!c) {
163 break;
164 }
165 value.push_back(static_cast<char>(c));
166 }
167 return value;
168}
169
175template <>
176inline std::u16string load_and_swap<std::u16string>(const void* mem) {
177 std::u16string value;
178 for (i32 i = 0;; ++i) {
179 auto c = load_and_swap<u16>(reinterpret_cast<const u16*>(mem) + i);
180 if (!c) {
181 break;
182 }
183 value.push_back(static_cast<wchar_t>(c));
184 }
185 return value;
186}
187
189template <typename T>
190inline void store(void* mem, const T& value) {
191 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
192 std::memcpy(mem, &value, sizeof(T));
193}
194
200template <typename T>
201inline void store_and_swap(void* mem, const T& value) {
202 store(mem, byte_swap(value));
203}
204
206template <>
207inline void store_and_swap<std::string_view>(void* mem, const std::string_view& value) {
208 for (size_t i = 0; i < value.size(); ++i) {
209 store_and_swap<u8>(reinterpret_cast<u8*>(mem) + i, value[i]);
210 }
211}
212
214template <>
215inline void store_and_swap<std::string>(void* mem, const std::string& value) {
216 return store_and_swap<std::string_view>(mem, value);
217}
218
220template <>
221inline void store_and_swap<std::u16string_view>(void* mem, const std::u16string_view& value) {
222 for (size_t i = 0; i < value.size(); ++i) {
223 store_and_swap<u16>(reinterpret_cast<u16*>(mem) + i, value[i]);
224 }
225}
226
228template <>
229inline void store_and_swap<std::u16string>(void* mem, const std::u16string& value) {
230 return store_and_swap<std::u16string_view>(mem, value);
231}
232
238constexpr u32 LoadUint24BE(const u8* p) {
239 return (static_cast<u32>(p[0]) << 16) | (static_cast<u32>(p[1]) << 8) | static_cast<u32>(p[2]);
240}
241
247constexpr u32 LoadUint24LE(const u8* p) {
248 return (static_cast<u32>(p[2]) << 16) | (static_cast<u32>(p[1]) << 8) | static_cast<u32>(p[0]);
249}
250
257constexpr void StoreUint24LE(u8* p, u32 value) {
258 p[2] = static_cast<u8>((value >> 16) & 0xFF);
259 p[1] = static_cast<u8>((value >> 8) & 0xFF);
260 p[0] = static_cast<u8>(value & 0xFF);
261}
262
264using FourCCT = u32;
265
273constexpr FourCCT make_fourcc(char a, char b, char c, char d) {
274 return ((static_cast<FourCCT>(a) << 24) | (static_cast<FourCCT>(b) << 16) |
275 (static_cast<FourCCT>(c) << 8) | static_cast<FourCCT>(d));
276}
277
284constexpr FourCCT make_fourcc(const std::string_view fourcc) {
285 if (fourcc.length() != 4) {
286 throw std::runtime_error("Invalid fourcc length");
287 }
288 return make_fourcc(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
289}
290
291} // namespace rex::memory
#define REX_ASSERT_ALWAYS(...)
Definition assert.h:102
Definition endian.h:27
void copy_and_swap_16_in_32_aligned(void *dest, const void *src, size_t count)
void copy_and_swap_32_unaligned(void *dest, const void *src, size_t count)
void store_and_swap< std::string_view >(void *mem, const std::string_view &value)
Definition endian.h:207
void copy_and_swap_64_aligned(void *dest, const void *src, size_t count)
u32 FourCCT
Definition endian.h:264
void store_and_swap(void *mem, const T &value)
Definition endian.h:201
void copy_and_swap_16_unaligned(void *dest, const void *src, size_t count)
std::string load_and_swap< std::string >(const void *mem)
Definition endian.h:158
void copy_and_swap(T *dest, const T *src, size_t count)
Definition endian.h:98
constexpr u32 LoadUint24LE(const u8 *p)
Definition endian.h:247
void copy_and_swap_64_unaligned(void *dest, const void *src, size_t count)
void store(void *mem, const T &value)
Definition endian.h:190
constexpr void StoreUint24LE(u8 *p, u32 value)
Definition endian.h:257
void copy_and_swap_32_aligned(void *dest, const void *src, size_t count)
void store_and_swap< std::string >(void *mem, const std::string &value)
Definition endian.h:215
void store_and_swap< std::u16string >(void *mem, const std::u16string &value)
Definition endian.h:229
void copy_and_swap_16_aligned(void *dest, const void *src, size_t count)
constexpr u32 LoadUint24BE(const u8 *p)
Definition endian.h:238
void Copy128Aligned(void *dest, const void *src, size_t count)
std::u16string load_and_swap< std::u16string >(const void *mem)
Definition endian.h:176
T load(const void *mem)
Definition endian.h:134
void store_and_swap< std::u16string_view >(void *mem, const std::u16string_view &value)
Definition endian.h:221
T load_and_swap(const void *mem)
Definition endian.h:148
void copy_and_swap_16_in_32_unaligned(void *dest, const void *src, size_t count)
constexpr FourCCT make_fourcc(char a, char b, char c, char d)
Definition endian.h:273
constexpr T byte_swap(T value) noexcept
Definition types.h:52
Platform flags, packing macros and export markers.
#define REX_API
Definition platform.h:177
Integer types, byte order wrappers and size literals.