15inline constexpr bool BIG = std::endian::native == std::endian::big;
16inline constexpr bool LITTLE = std::endian::native == std::endian::little;
17static_assert(
BIG ||
LITTLE,
"mixed endian not supported");
20[[nodiscard]]
static inline uint16_t byteswap16(uint16_t x)
27 return uint16_t(((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8));
32[[nodiscard]]
static inline uint32_t byteswap32(uint32_t x)
34#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))
37 return __builtin_bswap32(x);
40 ((x << 8) & 0x00ff0000) |
41 ((x >> 8) & 0x0000ff00) |
47[[nodiscard]]
static inline uint64_t byteswap64(uint64_t x)
49#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))
52 return __builtin_bswap64(x);
54 return (uint64_t(byteswap32(narrow_cast<uint32_t>(x >> 0))) << 32) |
55 (uint64_t(byteswap32(narrow_cast<uint32_t>(x >> 32))) << 0);
60[[nodiscard]]
static inline uint16_t byteswap(uint16_t x) {
return byteswap16(x); }
61[[nodiscard]]
static inline uint32_t byteswap(uint32_t x) {
return byteswap32(x); }
62[[nodiscard]]
static inline uint64_t byteswap(uint64_t x) {
return byteswap64(x); }
67 [[nodiscard]]
inline auto operator()(std::integral
auto t)
const {
return t; }
72 [[nodiscard]]
inline auto operator()(std::integral
auto t)
const {
return byteswap(
t); }
79template<std::
integral T, std::invocable<T> Op>
class EndianT {
83 [[nodiscard]]
inline operator T()
const { Op op;
return op(t); }
124static_assert(
sizeof(
B16) == 2,
"must have size 2");
125static_assert(
sizeof(
L16) == 2,
"must have size 2");
126static_assert(
sizeof(
B32) == 4,
"must have size 4");
127static_assert(
sizeof(
L32) == 4,
"must have size 4");
128static_assert(
sizeof(
B64) == 8,
"must have size 8");
129static_assert(
sizeof(
L64) == 8,
"must have size 8");
130static_assert(
alignof(
B16) <= 2,
"may have alignment 2");
131static_assert(
alignof(
L16) <= 2,
"may have alignment 2");
132static_assert(
alignof(
B32) <= 4,
"may have alignment 4");
133static_assert(
alignof(
L32) <= 4,
"may have alignment 4");
134static_assert(
alignof(
B64) <= 8,
"may have alignment 8");
135static_assert(
alignof(
L64) <= 8,
"may have alignment 8");
141 *
reinterpret_cast<B16*
>(p) = x;
145 *
reinterpret_cast<L16*
>(p) = x;
149 *
reinterpret_cast<B32*
>(p) = x;
153 *
reinterpret_cast<L32*
>(p) = x;
156[[nodiscard]]
inline uint16_t
readB16(
const void* p)
158 return *
reinterpret_cast<const B16*
>(p);
160[[nodiscard]]
inline uint16_t
readL16(
const void* p)
162 return *
reinterpret_cast<const L16*
>(p);
164[[nodiscard]]
inline uint32_t
readB32(
const void* p)
166 return *
reinterpret_cast<const B32*
>(p);
168[[nodiscard]]
inline uint32_t
readL32(
const void* p)
170 return *
reinterpret_cast<const L32*
>(p);
180template<
bool SWAP>
static ALWAYS_INLINE void write_UA(
void* p, std::integral
auto x)
182 if constexpr (SWAP) x = byteswap(x);
183 memcpy(p, &x,
sizeof(x));
187 write_UA<LITTLE>(p, x);
195 assert(x < 0x1000000);
196 auto* v =
static_cast<uint8_t*
>(p);
197 v[0] = (x >> 0) & 0xff;
198 v[1] = (x >> 8) & 0xff;
199 v[2] = (x >> 16) & 0xff;
203 write_UA<LITTLE>(p, x);
211 write_UA<LITTLE>(p, x);
218template<
bool SWAP, std::
integral T> [[nodiscard]]
static ALWAYS_INLINE T read_UA(
const void* p)
221 memcpy(&x, p,
sizeof(x));
222 if constexpr (SWAP) x = byteswap(x);
227 return read_UA<LITTLE, uint16_t>(p);
231 return read_UA<BIG, uint16_t>(p);
235 const auto* v =
static_cast<const uint8_t*
>(p);
236 return (v[0] << 0) | (v[1] << 8) | (v[2] << 16);
240 return read_UA<LITTLE, uint32_t>(p);
244 return read_UA<BIG, uint32_t>(p);
248 return read_UA<LITTLE, uint64_t>(p);
252 return read_UA<BIG, uint64_t>(p);
260 [[nodiscard]]
inline operator uint16_t()
const {
return read_UA_B16(x.data()); }
263 std::array<uint8_t, 2> x;
268 [[nodiscard]]
inline operator uint16_t()
const {
return read_UA_L16(x.data()); }
271 std::array<uint8_t, 2> x;
276 inline operator uint32_t()
const {
return read_UA_L24(x.data()); }
279 std::array<uint8_t, 3> x;
284 [[nodiscard]]
inline operator uint32_t()
const {
return read_UA_B32(x.data()); }
287 std::array<uint8_t, 4> x;
292 [[nodiscard]]
inline operator uint32_t()
const {
return read_UA_L32(x.data()); }
295 std::array<uint8_t, 4> x;
298static_assert(
sizeof(UA_B16) == 2,
"must have size 2");
299static_assert(
sizeof(UA_L16) == 2,
"must have size 2");
300static_assert(
sizeof(UA_L24) == 3,
"must have size 3");
301static_assert(
sizeof(UA_B32) == 4,
"must have size 4");
302static_assert(
sizeof(UA_L32) == 4,
"must have size 4");
303static_assert(
alignof(UA_B16) == 1,
"must have alignment 1");
304static_assert(
alignof(UA_L16) == 1,
"must have alignment 1");
305static_assert(
alignof(UA_L24) == 1,
"must have alignment 1");
306static_assert(
alignof(UA_B32) == 1,
"must have alignment 1");
307static_assert(
alignof(UA_L32) == 1,
"must have alignment 1");
321template<
typename>
struct Big;
322template<>
struct Big<uint8_t > {
using type = uint8_t; };
UA_B16 & operator=(uint16_t a)
UA_B32 & operator=(uint32_t a)
UA_L16 & operator=(uint16_t a)
UA_L24 & operator=(uint32_t a)
UA_L32 & operator=(uint32_t a)
uint16_t readB16(const void *p)
ALWAYS_INLINE uint32_t read_UA_L24(const void *p)
ALWAYS_INLINE uint16_t read_UA_B16(const void *p)
void writeB16(void *p, uint16_t x)
ALWAYS_INLINE void write_UA_B32(void *p, uint32_t x)
ALWAYS_INLINE void write_UA_B64(void *p, uint64_t x)
uint32_t readL32(const void *p)
ALWAYS_INLINE void write_UA_L24(void *p, uint32_t x)
ALWAYS_INLINE void write_UA_B16(void *p, uint16_t x)
void writeL32(void *p, uint32_t x)
ALWAYS_INLINE uint64_t read_UA_L64(const void *p)
ALWAYS_INLINE uint32_t read_UA_B32(const void *p)
void writeB32(void *p, uint32_t x)
ALWAYS_INLINE void write_UA_L64(void *p, uint64_t x)
ALWAYS_INLINE uint16_t read_UA_L16(const void *p)
ALWAYS_INLINE uint64_t read_UA_B64(const void *p)
EndianT< uint16_t, ConvBig< BIG > > B16
ALWAYS_INLINE void write_UA_L32(void *p, uint32_t x)
EndianT< uint32_t, ConvBig< BIG > > B32
ALWAYS_INLINE void write_UA_L16(void *p, uint16_t x)
EndianT< uint32_t, ConvLittle< BIG > > L32
uint16_t readL16(const void *p)
uint32_t readB32(const void *p)
EndianT< uint16_t, ConvLittle< BIG > > L16
EndianT< uint64_t, ConvBig< BIG > > B64
ALWAYS_INLINE uint32_t read_UA_L32(const void *p)
EndianT< uint64_t, ConvLittle< BIG > > L64
void writeL16(void *p, uint16_t x)
auto operator()(std::integral auto t) const
auto operator()(std::integral auto t) const