18#if HI_COMPILER == HI_CC_MSVC
28hi_warning_ignore_msvc(26472);
30namespace hi::inline
v1 {
32template<std::
unsigned_
integral T>
33[[nodiscard]]
constexpr T byte_swap(T x)
noexcept
35 if (not std::is_constant_evaluated()) {
36#if HI_COMPILER == HI_CC_CLANG || HI_COMPILER == HI_CC_GCC
37 if constexpr (
sizeof(T) ==
sizeof(uint64_t)) {
38 return static_cast<T
>(__builtin_bswap64(
static_cast<uint64_t
>(x)));
39 }
else if constexpr (
sizeof(T) ==
sizeof(uint32_t)) {
40 return static_cast<T
>(__builtin_bswap32(
static_cast<uint32_t
>(x)));
41 }
else if constexpr (
sizeof(T) ==
sizeof(uint16_t)) {
42 return static_cast<T
>(__builtin_bswap16(
static_cast<uint16_t
>(x)));
44#elif HI_COMPILER == HI_CC_MSVC
45 if constexpr (
sizeof(T) ==
sizeof(uint64_t)) {
46 return static_cast<T
>(_byteswap_uint64(
static_cast<uint64_t
>(x)));
47 }
else if constexpr (
sizeof(T) ==
sizeof(
unsigned long)) {
48 return static_cast<T
>(_byteswap_ulong(
static_cast<unsigned long>(x)));
49 }
else if constexpr (
sizeof(T) ==
sizeof(
unsigned short)) {
50 return static_cast<T
>(_byteswap_ushort(
static_cast<unsigned short>(x)));
55 if constexpr (
sizeof(T) == 1) {
59 for (
auto i = 0_uz; i !=
sizeof(T); ++i) {
61 r |=
static_cast<uint8_t
>(x);
68template<std::
signed_
integral T>
69[[nodiscard]]
constexpr T byte_swap(T x)
noexcept
71 return static_cast<T
>(byte_swap(
static_cast<std::make_unsigned_t<T>
>(x)));
74template<std::
floating_po
int T>
75[[nodiscard]]
constexpr T byte_swap(T x)
noexcept
77 if constexpr (std::is_same_v<T, float>) {
78 auto utmp = std::bit_cast<uint32_t>(x);
79 utmp = byte_swap(utmp);
80 return std::bit_cast<float>(x);
81 }
else if constexpr (std::is_same_v<T, double>) {
82 auto utmp = std::bit_cast<uint64_t>(x);
83 utmp = byte_swap(utmp);
84 return std::bit_cast<double>(x);
92template<std::
integral T>
95 if constexpr (std::endian::native == std::endian::little) {
104template<std::
integral T>
107 if constexpr (std::endian::native == std::endian::big) {
116template<std::
integral T>
119 if constexpr (std::endian::native == std::endian::little) {
128template<std::
integral T>
131 if constexpr (std::endian::native == std::endian::big) {
145template<numeric T, std::endian Endian = std::endian::native>
146[[nodiscard]]
constexpr T
load(T
const *src)
noexcept
149 if constexpr (Endian != std::endian::native) {
150 value = byte_swap(value);
162template<numeric T, std::endian Endian = std::endian::native,
byte_like B>
163[[nodiscard]]
constexpr T
load(B
const *src)
noexcept
165 auto value = unaligned_load<T>(src);
166 if constexpr (Endian != std::endian::native) {
167 value = byte_swap(value);
179template<numeric T, std::endian Endian = std::endian::native>
180[[nodiscard]]
inline T
load(
void const *src)
noexcept
182 auto value = unaligned_load<T>(src);
183 if constexpr (Endian != std::endian::native) {
184 value = byte_swap(value);
196[[nodiscard]]
constexpr T
load_le(T
const *src)
noexcept
198 return load<T, std::endian::little>(src);
207template<numeric T,
byte_like B>
208[[nodiscard]]
constexpr T
load_le(B
const *src)
noexcept
210 return load<T, std::endian::little>(src);
220[[nodiscard]]
inline T
load_le(
void const *src)
noexcept
222 return load<T, std::endian::little>(src);
232[[nodiscard]]
constexpr T
load_be(T
const *src)
noexcept
234 return load<T, std::endian::big>(src);
243template<numeric T,
byte_like B>
244[[nodiscard]]
constexpr T
load_be(B
const *src)
noexcept
246 return load<T, std::endian::big>(src);
256[[nodiscard]]
inline T
load_be(
void const *src)
noexcept
258 return load<T, std::endian::big>(src);
276template<
unsigned int NumBits,
byte_like B>
277[[nodiscard]]
constexpr auto load_bits_be(B
const *src,
size_t bit_index)
noexcept
279 static_assert(NumBits <=
sizeof(
unsigned long long) * CHAR_BIT);
281 constexpr auto num_bits = NumBits;
282 constexpr auto num_bytes = (num_bits + CHAR_BIT - 1) / CHAR_BIT;
287 std::conditional_t<num_bytes <
sizeof(
unsigned short),
unsigned short,
288 std::conditional_t<num_bytes <
sizeof(
unsigned int),
unsigned int,
289 std::conditional_t<num_bytes <
sizeof(
unsigned long),
unsigned long,
unsigned long long>>>;
292 constexpr auto value_bits =
sizeof(value_type) * CHAR_BIT;
294 hilet byte_offset = bit_index / CHAR_BIT;
295 hilet bit_offset = bit_index % CHAR_BIT;
298 if constexpr (num_bits == CHAR_BIT) {
299 if (bit_offset == 0) {
300 return char_cast<value_type>(src[byte_offset]);
311 if constexpr (num_bytes ==
sizeof(value_type)) {
315 auto bits_done = value_bits - bit_offset;
316 if (bits_done < num_bits) {
317 auto rest = char_cast<value_type>(src[byte_offset +
sizeof(value_type)]);
318 rest >>= CHAR_BIT - bit_offset;
324 r >>= value_bits - num_bits;
330template<std::endian Endian = std::endian::native, numeric T,
byte_like B>
331constexpr void store(T value, B
const *dst)
noexcept
333 if constexpr (Endian != std::endian::native) {
334 value = byte_swap(value);
336 unaligned_store<T>(value, dst);
339template<std::endian Endian = std::endian::native, numeric T>
340constexpr void store(T value,
void const *dst)
noexcept
342 if constexpr (Endian != std::endian::native) {
343 value = byte_swap(value);
345 unaligned_store<T>(value, dst);
348template<numeric T,
byte_like B>
349constexpr void store_le(T value, B
const *dst)
noexcept
351 store<std::endian::little>(value, dst);
355inline void store_le(T value,
void const *dst)
noexcept
357 store<std::endian::little>(value, dst);
360template<numeric T,
byte_like B>
361constexpr void store_be(T value, B
const *dst)
noexcept
363 store<std::endian::big>(value, dst);
367inline void store_be(T value,
void const *dst)
noexcept
369 store<std::endian::big>(value, dst);
373template<
typename T, std::endian E, std::
size_t A = alignof(T)>
375 using value_type = T;
376 constexpr static std::endian endian = E;
379 alignas(A) std::byte _value[
sizeof(T)];
381 [[nodiscard]]
constexpr value_type operator*()
const noexcept
383 return load<value_type, endian>(_value);
386 constexpr endian_buf_t& operator=(value_type x)
noexcept
388 store<endian>(x, _value);
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:323
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
constexpr T big_to_native(T x)
Convert an integral from big-to-native endian.
Definition endian.hpp:105
constexpr T little_to_native(T x)
Convert an integral from little-to-native endian.
Definition endian.hpp:93
constexpr T native_to_big(T x)
Convert an integral from native-to-big endian.
Definition endian.hpp:129
constexpr T load_le(T const *src) noexcept
Load of a numeric value encoded in little-endian format.
Definition endian.hpp:196
constexpr T native_to_little(T x)
Convert an integral from native-to-little endian.
Definition endian.hpp:117
constexpr T load_be(T const *src) noexcept
Load of a numeric value encoded in big-endian format.
Definition endian.hpp:232
constexpr auto load_bits_be(B const *src, size_t bit_index) noexcept
Unaligned load bits from a big-endian buffer at a bit-offset.
Definition endian.hpp:277
constexpr T load(T const *src) noexcept
Load a numeric value from memory.
Definition endian.hpp:146
Horizontal/Vertical alignment combination.
Definition alignment.hpp:231
Definition endian.hpp:374