16inline constexpr bool BIG = std::endian::native == std::endian::big;
17inline constexpr bool LITTLE = std::endian::native == std::endian::little;
18static_assert(
BIG ||
LITTLE,
"mixed endian not supported");
21[[nodiscard]]
static inline uint16_t byteswap16(uint16_t x)
28 return uint16_t(((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8));
33[[nodiscard]]
static inline uint32_t byteswap32(uint32_t x)
35#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))
38 return __builtin_bswap32(x);
41 ((x << 8) & 0x00ff0000) |
42 ((x >> 8) & 0x0000ff00) |
48[[nodiscard]]
static inline uint64_t byteswap64(uint64_t x)
50#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))
53 return __builtin_bswap64(x);
55 return (uint64_t(byteswap32(narrow_cast<uint32_t>(x >> 0))) << 32) |
56 (uint64_t(byteswap32(narrow_cast<uint32_t>(x >> 32))) << 0);
61[[nodiscard]]
static inline uint16_t byteswap(uint16_t x) {
return byteswap16(x); }
62[[nodiscard]]
static inline uint32_t byteswap(uint32_t x) {
return byteswap32(x); }
63[[nodiscard]]
static inline uint64_t byteswap(uint64_t x) {
return byteswap64(x); }
68 [[nodiscard]]
inline auto operator()(std::integral
auto t)
const {
return t; }
73 [[nodiscard]]
inline auto operator()(std::integral
auto t)
const {
return byteswap(
t); }
80template<std::
integral T, std::invocable<T> Op>
class EndianT {
83 explicit EndianT(T t_) { Op op; t = op(t_); }
84 [[nodiscard]]
inline operator T()
const { Op op;
return op(t); }
125static_assert(
sizeof(
B16) == 2,
"must have size 2");
126static_assert(
sizeof(
L16) == 2,
"must have size 2");
127static_assert(
sizeof(
B32) == 4,
"must have size 4");
128static_assert(
sizeof(
L32) == 4,
"must have size 4");
129static_assert(
sizeof(
B64) == 8,
"must have size 8");
130static_assert(
sizeof(
L64) == 8,
"must have size 8");
131static_assert(
alignof(
B16) <= 2,
"may have alignment 2");
132static_assert(
alignof(
L16) <= 2,
"may have alignment 2");
133static_assert(
alignof(
B32) <= 4,
"may have alignment 4");
134static_assert(
alignof(
L32) <= 4,
"may have alignment 4");
135static_assert(
alignof(
B64) <= 8,
"may have alignment 8");
136static_assert(
alignof(
L64) <= 8,
"may have alignment 8");
142 *std::bit_cast<B16*>(p) = x;
146 *std::bit_cast<L16*>(p) = x;
150 *std::bit_cast<B32*>(p) = x;
154 *std::bit_cast<L32*>(p) = x;
157[[nodiscard]]
inline uint16_t
readB16(
const void* p)
159 return *std::bit_cast<const B16*>(p);
161[[nodiscard]]
inline uint16_t
readL16(
const void* p)
163 return *std::bit_cast<const L16*>(p);
165[[nodiscard]]
inline uint32_t
readB32(
const void* p)
167 return *std::bit_cast<const B32*>(p);
169[[nodiscard]]
inline uint32_t
readL32(
const void* p)
171 return *std::bit_cast<const L32*>(p);
181template<
bool SWAP>
static ALWAYS_INLINE void write_UA(
void* p, std::integral
auto x)
183 if constexpr (SWAP) x = byteswap(x);
184 memcpy(p, &x,
sizeof(x));
188 write_UA<LITTLE>(p, x);
196 assert(x < 0x1000000);
197 auto* v =
static_cast<uint8_t*
>(p);
198 v[0] = (x >> 0) & 0xff;
199 v[1] = (x >> 8) & 0xff;
200 v[2] = (x >> 16) & 0xff;
204 write_UA<LITTLE>(p, x);
212 write_UA<LITTLE>(p, x);
219template<
bool SWAP, std::
integral T> [[nodiscard]]
static ALWAYS_INLINE T read_UA(
const void* p)
222 memcpy(&x, p,
sizeof(x));
223 if constexpr (SWAP) x = byteswap(x);
228 return read_UA<LITTLE, uint16_t>(p);
232 return read_UA<BIG, uint16_t>(p);
236 const auto* v =
static_cast<const uint8_t*
>(p);
237 return (v[0] << 0) | (v[1] << 8) | (v[2] << 16);
241 return read_UA<LITTLE, uint32_t>(p);
245 return read_UA<BIG, uint32_t>(p);
249 return read_UA<LITTLE, uint64_t>(p);
253 return read_UA<BIG, uint64_t>(p);
261 [[nodiscard]]
inline operator uint16_t()
const {
return read_UA_B16(x.data()); }
264 std::array<uint8_t, 2> x;
269 [[nodiscard]]
inline operator uint16_t()
const {
return read_UA_L16(x.data()); }
272 std::array<uint8_t, 2> x;
277 inline operator uint32_t()
const {
return read_UA_L24(x.data()); }
280 std::array<uint8_t, 3> x;
285 [[nodiscard]]
inline operator uint32_t()
const {
return read_UA_B32(x.data()); }
288 std::array<uint8_t, 4> x;
293 [[nodiscard]]
inline operator uint32_t()
const {
return read_UA_L32(x.data()); }
296 std::array<uint8_t, 4> x;
299static_assert(
sizeof(UA_B16) == 2,
"must have size 2");
300static_assert(
sizeof(UA_L16) == 2,
"must have size 2");
301static_assert(
sizeof(UA_L24) == 3,
"must have size 3");
302static_assert(
sizeof(UA_B32) == 4,
"must have size 4");
303static_assert(
sizeof(UA_L32) == 4,
"must have size 4");
304static_assert(
alignof(UA_B16) == 1,
"must have alignment 1");
305static_assert(
alignof(UA_L16) == 1,
"must have alignment 1");
306static_assert(
alignof(UA_L24) == 1,
"must have alignment 1");
307static_assert(
alignof(UA_B32) == 1,
"must have alignment 1");
308static_assert(
alignof(UA_L32) == 1,
"must have alignment 1");
322template<
typename>
struct Big;
323template<>
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