48 lines
1.1 KiB
C++
48 lines
1.1 KiB
C++
|
#pragma once
|
||
|
|
||
|
#include <bit>
|
||
|
#include <base/types.hpp>
|
||
|
|
||
|
namespace base {
|
||
|
|
||
|
// required until C++23 support :(
|
||
|
namespace detail {
|
||
|
|
||
|
template <class T, class U>
|
||
|
constexpr T PunCast(U v) {
|
||
|
return *std::bit_cast<const T*>(&v);
|
||
|
}
|
||
|
|
||
|
template <class T>
|
||
|
constexpr T ByteSwap(T v) {
|
||
|
if constexpr(sizeof(T) == 2)
|
||
|
return static_cast<T>(__builtin_bswap16(PunCast<u16>(v)));
|
||
|
else if constexpr(sizeof(T) == 4)
|
||
|
return static_cast<T>(__builtin_bswap32(PunCast<u32>(v)));
|
||
|
else if constexpr(sizeof(T) == 8)
|
||
|
return static_cast<T>(__builtin_bswap64(PunCast<u64>(v)));
|
||
|
|
||
|
return v;
|
||
|
}
|
||
|
|
||
|
} // namespace detail
|
||
|
|
||
|
/// A network-order field, swapped automatically
|
||
|
template <class T>
|
||
|
struct [[gnu::packed]] NetworkOrder {
|
||
|
constexpr NetworkOrder() = default;
|
||
|
constexpr NetworkOrder(T v) : field(SwapIfRequired(v)) {}
|
||
|
|
||
|
operator T() const { return SwapIfRequired(field); }
|
||
|
|
||
|
private:
|
||
|
constexpr static T SwapIfRequired(T value) {
|
||
|
if constexpr(std::endian::native == std::endian::little)
|
||
|
return detail::ByteSwap(value);
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
T field;
|
||
|
};
|
||
|
} // namespace base
|