12#include "concepts.hpp"
23#if HI_COMPILER == HI_CC_MSVC
33hi_warning_ignore_msvc(26472)
35namespace hi::inline v1 {
37template<std::
unsigned_
integral T>
38[[nodiscard]] T byte_swap(T x)
noexcept
40#if HI_COMPILER == HI_CC_CLANG || HI_COMPILER == HI_CC_GCC
41 if constexpr (
sizeof(T) ==
sizeof(uint64_t)) {
42 return static_cast<T
>(__builtin_bswap64(
static_cast<uint64_t
>(x)));
43 }
else if constexpr (
sizeof(T) ==
sizeof(uint32_t)) {
44 return static_cast<T
>(__builtin_bswap32(
static_cast<uint32_t
>(x)));
45 }
else if constexpr (
sizeof(T) ==
sizeof(uint16_t)) {
46 return static_cast<T
>(__builtin_bswap16(
static_cast<uint16_t
>(x)));
50#elif HI_COMPILER == HI_CC_MSVC
51 if constexpr (
sizeof(T) ==
sizeof(uint64_t)) {
52 return static_cast<T
>(_byteswap_uint64(
static_cast<uint64_t
>(x)));
53 }
else if constexpr (
sizeof(T) ==
sizeof(
unsigned long)) {
54 return static_cast<T
>(_byteswap_ulong(
static_cast<unsigned long>(x)));
55 }
else if constexpr (
sizeof(T) ==
sizeof(
unsigned short)) {
56 return static_cast<T
>(_byteswap_ushort(
static_cast<unsigned short>(x)));
61#error "Byteswap not implemented for this compiler."
65template<std::
signed_
integral T>
66[[nodiscard]] T byte_swap(T x)
noexcept
68 return static_cast<T
>(byte_swap(
static_cast<std::make_unsigned_t<T>
>(x)));
71template<std::
floating_po
int T>
72[[nodiscard]] T byte_swap(T x)
noexcept
74 if constexpr (std::is_same_v<T, float>) {
75 auto utmp = std::bit_cast<uint32_t>(x);
76 utmp = byte_swap(utmp);
77 return std::bit_cast<float>(x);
78 }
else if constexpr (std::is_same_v<T, double>) {
79 auto utmp = std::bit_cast<uint64_t>(x);
80 utmp = byte_swap(utmp);
81 return std::bit_cast<double>(x);
87template<std::
integral T>
88[[nodiscard]] T little_to_native(T x)
90 if constexpr (std::endian::native == std::endian::little) {
97template<std::
integral T>
98[[nodiscard]] T big_to_native(T x)
100 if constexpr (std::endian::native == std::endian::big) {
107template<std::
integral T>
108[[nodiscard]] T native_to_little(T x)
110 if constexpr (std::endian::native == std::endian::little) {
117template<std::
integral T>
118[[nodiscard]] T native_to_big(T x)
120 if constexpr (std::endian::native == std::endian::big) {
127template<
typename T, std::endian E, std::
size_t A = alignof(T)>
129 alignas(A) std::byte _value[
sizeof(T)];
131 [[nodiscard]] T value() const noexcept
136 return E == std::endian::native ? x : byte_swap(x);
139 endian_buf_t &set_value(T x)
noexcept
141 if constexpr (E != std::endian::native) {
149 endian_buf_t &operator=(T x)
noexcept
154 operator T() const noexcept
160using big_uint64_buf_t = endian_buf_t<uint64_t, std::endian::big, 1>;
161using big_uint32_buf_t = endian_buf_t<uint32_t, std::endian::big, 1>;
162using big_uint16_buf_t = endian_buf_t<uint16_t, std::endian::big, 1>;
163using big_int64_buf_t = endian_buf_t<int64_t, std::endian::big, 1>;
164using big_int32_buf_t = endian_buf_t<int32_t, std::endian::big, 1>;
165using big_int16_buf_t = endian_buf_t<int16_t, std::endian::big, 1>;
166using little_uint64_buf_t = endian_buf_t<uint64_t, std::endian::little, 1>;
167using little_uint32_buf_t = endian_buf_t<uint32_t, std::endian::little, 1>;
168using little_uint16_buf_t = endian_buf_t<uint16_t, std::endian::little, 1>;
169using little_int64_buf_t = endian_buf_t<int64_t, std::endian::little, 1>;
170using little_int32_buf_t = endian_buf_t<int32_t, std::endian::little, 1>;
171using little_int16_buf_t = endian_buf_t<int16_t, std::endian::little, 1>;
172using native_uint64_buf_t = endian_buf_t<uint64_t, std::endian::native, 1>;
173using native_uint32_buf_t = endian_buf_t<uint32_t, std::endian::native, 1>;
174using native_uint16_buf_t = endian_buf_t<uint16_t, std::endian::native, 1>;
175using native_int64_buf_t = endian_buf_t<int64_t, std::endian::native, 1>;
176using native_int32_buf_t = endian_buf_t<int32_t, std::endian::native, 1>;
177using native_int16_buf_t = endian_buf_t<int16_t, std::endian::native, 1>;
179using big_uint64_buf_at = endian_buf_t<uint64_t, std::endian::big>;
180using big_uint32_buf_at = endian_buf_t<uint32_t, std::endian::big>;
181using big_uint16_buf_at = endian_buf_t<uint16_t, std::endian::big>;
182using big_int64_buf_at = endian_buf_t<int64_t, std::endian::big>;
183using big_int32_buf_at = endian_buf_t<int32_t, std::endian::big>;
184using big_int16_buf_at = endian_buf_t<int16_t, std::endian::big>;
185using little_uint64_buf_at = endian_buf_t<uint64_t, std::endian::little>;
186using little_uint32_buf_at = endian_buf_t<uint32_t, std::endian::little>;
187using little_uint16_buf_at = endian_buf_t<uint16_t, std::endian::little>;
188using little_int64_buf_at = endian_buf_t<int64_t, std::endian::little>;
189using little_int32_buf_at = endian_buf_t<int32_t, std::endian::little>;
190using little_int16_buf_at = endian_buf_t<int16_t, std::endian::little>;
191using native_uint64_buf_at = endian_buf_t<uint64_t, std::endian::native>;
192using native_uint32_buf_at = endian_buf_t<uint32_t, std::endian::native>;
193using native_uint16_buf_at = endian_buf_t<uint16_t, std::endian::native>;
194using native_int64_buf_at = endian_buf_t<int64_t, std::endian::native>;
195using native_int32_buf_at = endian_buf_t<int32_t, std::endian::native>;
196using native_int16_buf_at = endian_buf_t<int16_t, std::endian::native>;
201hi_force_inline T load(
void const *src)
noexcept
203#if HI_COMPILER == HI_CC_MSVC
204 return *
reinterpret_cast<__unaligned T
const *
>(src);
206#error "missing implementation for load()"
213hi_force_inline T load_le(
void const *src)
noexcept
215 return little_to_native(load<T>(src));
221hi_force_inline T load_be(
void const *src)
noexcept
223 return big_to_native(load<T>(src));
231template<std::
unsigned_
integral T>
232hi_force_inline
void unaligned_load_le(T& r,
void const *src)
noexcept
235 if constexpr (
sizeof(T) == 8) {
236 r = _mm_extract_epi64(_mm_loadu_si64(src), 0);
237 }
else if constexpr (
sizeof(T) == 4) {
238 r = _mm_extract_epi32(_mm_loadu_si32(src), 0);
239 }
else if constexpr (
sizeof(T) == 2) {
240 r = _mm_extract_epi16(_mm_loadu_si16(src), 0);
241 }
else if constexpr (
sizeof(T) == 1) {
242 r = *
reinterpret_cast<uint8_t const*
>(src);
244 hi_static_no_default();
247 auto src_ =
reinterpret_cast<uint8_t
const *
>(src);
267template<std::
unsigned_
integral T>
268hi_force_inline
void unaligned_load_le(T& r,
void const *src,
size_t size,
size_t offset = 0) noexcept
270 hi_axiom(offset <
sizeof(T));
271 hi_axiom(size <=
sizeof(T));
272 hi_axiom(size + offset <=
sizeof(T));
274 auto src_ =
reinterpret_cast<uint8_t
const *
>(src);
276 hilet first = offset * CHAR_BIT;
277 hilet last = (first + size) * CHAR_BIT;
279 for (
auto i = first; i != last; i += CHAR_BIT) {
280 r |= wide_cast<T>(*src_++) << i;
This file includes required definitions.
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
Functions and macros for handling architectural difference between compilers, CPUs and operating syst...