33#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) || (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__)
34 #define RAV_LITTLE_ENDIAN 0
35 #define RAV_BIG_ENDIAN 1
42 #warning "Big endian systems have not been tested yet"
44 #define RAV_LITTLE_ENDIAN 1
45 #define RAV_BIG_ENDIAN 0
55#if defined(__clang__) || defined(__GNUC__)
56 #define RAV_BYTE_SWAP_16(x) __builtin_bswap16(x)
57 #define RAV_BYTE_SWAP_32(x) __builtin_bswap32(x)
58 #define RAV_BYTE_SWAP_64(x) __builtin_bswap64(x)
59#elif defined(_MSC_VER)
61 #define RAV_BYTE_SWAP_16(x) _byteswap_ushort(x)
62 #define RAV_BYTE_SWAP_32(x) _byteswap_ulong(x)
63 #define RAV_BYTE_SWAP_64(x) _byteswap_uint64(x)
65 #error "Unsupported compiler"
75inline void swap_bytes(uint8_t* data,
const size_t size) {
77 if (data ==
nullptr || size == 0) {
81 for (
size_t i = 0; i < size / 2; ++i) {
82 std::swap(data[i], data[size - i - 1]);
92inline void swap_bytes(uint8_t* data,
const size_t size,
const size_t stride) {
94 if (data ==
nullptr || size == 0 || stride <= 1) {
98 for (
size_t i = 0; i < size; i += stride) {
99 for (
size_t j = 0; j < stride / 2; ++j) {
100 std::swap(data[i + j], data[i + stride - j - 1]);
110template<
typename Type, std::enable_if_t<std::is_trivially_copyable_v<Type>,
bool> = true>
113 if constexpr (
sizeof(Type) == 1) {
115 }
else if constexpr (
sizeof(Type) == 2) {
116 return static_cast<Type
>(RAV_BYTE_SWAP_16(
static_cast<uint16_t
>(value)));
117 }
else if constexpr (
sizeof(Type) == 4) {
118 return static_cast<Type
>(RAV_BYTE_SWAP_32(
static_cast<uint32_t
>(value)));
119 }
else if constexpr (
sizeof(Type) == 8) {
120 return static_cast<Type
>(RAV_BYTE_SWAP_64(
static_cast<uint64_t
>(value)));
122 swap_bytes(
reinterpret_cast<uint8_t*
>(&value),
sizeof(value));
134 static_assert(
sizeof(float) ==
sizeof(uint32_t),
"Float must be 32 bits");
141 u.i = RAV_BYTE_SWAP_32(u.i);
152 static_assert(
sizeof(double) ==
sizeof(uint64_t),
"Double must be 64 bits");
159 u.i = RAV_BYTE_SWAP_64(u.i);
169template<
typename Type, std::enable_if_t<std::is_trivially_copyable_v<Type>,
bool> = true>
184template<
typename Type, std::enable_if_t<std::is_trivially_copyable_v<Type>,
bool> = true>
199template<
typename Type, std::enable_if_t<std::is_trivially_copyable_v<Type>,
bool> = true>
202 std::memcpy(std::addressof(value), data,
sizeof(Type));
212template<
typename Type, std::enable_if_t<std::is_trivially_copyable_v<Type>,
bool> = true>
223template<
typename Type, std::enable_if_t<std::is_trivially_copyable_v<Type>,
bool> = true>
234template<
typename Type, std::enable_if_t<std::is_trivially_copyable_v<Type>,
bool> = true>
236 std::memcpy(dst, std::addressof(value),
sizeof(Type));
245template<
typename Type, std::enable_if_t<std::is_trivially_copyable_v<Type>,
bool> = true>
256template<
typename Type, std::enable_if_t<std::is_trivially_copyable_v<Type>,
bool> = true>
266 static size_t native_one = 1;
267 return reinterpret_cast<uint8_t*
>(&native_one)[0] == 1;
279 if (is_little_endian_runtime()) {
#define RAV_THROW_EXCEPTION(...)
float swap_bytes< float >(const float value)
Specialization of swap_bytes for floats.
static constexpr bool big_endian
Type read_le(const uint8_t *data)
Reads a little-endian value from the given data.
void swap_bytes(uint8_t *data, const size_t size)
Swaps given amount of bytes in the given data, in place.
Type swap_if_le(const Type value)
Swaps the bytes of the given value if the system is little-endian.
Type read_ne(const uint8_t *data)
Reads a value from the given data in native byte order (not to be confused with network-endian).
bool is_little_endian_at_runtime() noexcept
Checks if the system is little-endian at runtime.
static constexpr bool little_endian
Type read_be(const uint8_t *data)
Reads a big-endian value from the given data.
void write_le(uint8_t *dst, const Type value)
Writes a little-endian value to the given destination.
void write_be(uint8_t *dst, const Type value)
Writes a big-endian value to the given destination.
Type swap_if_be(const Type value)
Swaps the bytes of the given value if the system is big-endian.
double swap_bytes< double >(const double value)
Specialization of swap_bytes for doubles.
void validate_byte_order()
Validates whether the compiled byte order matches the runtime byte order.
void write_ne(uint8_t *dst, const Type value)
Writes a value to the given destination in native byte order (not to be confused with network-endian)...