Skip to content

Commit f96a661

Browse files
committed
Refactoring fallback_byteswap to fix build
1 parent 092e0a7 commit f96a661

File tree

1 file changed

+31
-24
lines changed

1 file changed

+31
-24
lines changed

include/mdcomp/bigendian_io.hh

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,37 @@ namespace detail {
174174
template <class... Ts>
175175
overloaded(Ts...) -> overloaded<Ts...>;
176176

177+
template <std::unsigned_integral T>
178+
[[nodiscard]] CONST_INLINE constexpr T fallback_byteswap(T value) noexcept {
179+
using uint_t = std::make_unsigned_t<std::remove_cvref_t<T>>;
180+
// Fallback implementation that handles even __int24 etc.
181+
constexpr size_t const nbits = CHAR_BIT;
182+
constexpr size_t const delta = 2ULL * nbits;
183+
184+
size_t bit_offset = nbits * (sizeof(T) + 1);
185+
size_t shift_amount = bit_offset - delta;
186+
uint_t low_byte_mask = std::numeric_limits<uint8_t>::max();
187+
auto high_byte_mask = static_cast<uint_t>(low_byte_mask << shift_amount);
188+
uint_t new_value = value;
189+
for (size_t ii = 0; ii < sizeof(T) / 2; ++ii) {
190+
bit_offset -= delta;
191+
uint_t const low_byte = new_value & low_byte_mask;
192+
uint_t const high_byte = new_value & high_byte_mask;
193+
new_value ^= low_byte;
194+
new_value ^= high_byte;
195+
new_value ^= static_cast<uint_t>(low_byte << bit_offset);
196+
new_value ^= static_cast<uint_t>(high_byte >> bit_offset);
197+
low_byte_mask = std::rotl(low_byte_mask, nbits);
198+
high_byte_mask = std::rotr(high_byte_mask, nbits);
199+
}
200+
return uint_t(new_value & std::numeric_limits<uint_t>::max());
201+
};
202+
203+
static_assert(fallback_byteswap(uint8_t{0x35U}) == uint8_t{0x35U});
204+
static_assert(fallback_byteswap(uint16_t{0x1357U}) == uint16_t{0x5713U});
205+
static_assert(fallback_byteswap(0x01234567U) == 0x67452301U);
206+
static_assert(fallback_byteswap(0x0123456789abcdefULL) == 0xefcdab8967452301ULL);
207+
177208
// Mashed together implementation based on libstdc++/libc++/MS STL.
178209
// GCC/clang both have a 128-bit integer type, which this implementation
179210
// supports; but MSVC compiler does not support a 128-bit integer, so this
@@ -183,30 +214,6 @@ namespace detail {
183214
#if defined(__cpp_lib_byteswap) && __cpp_lib_byteswap >= 202110L
184215
return std::byteswap(value);
185216
#else
186-
constexpr auto fallback_byteswap = []<typename UT>(UT val) noexcept {
187-
using uint_t = std::make_unsigned_t<std::remove_cvref_t<UT>>;
188-
// Fallback implementation that handles even __int24 etc.
189-
constexpr size_t const nbits = CHAR_BIT;
190-
constexpr size_t const delta = 2ULL * nbits;
191-
192-
size_t bit_offset = nbits * (sizeof(T) + 1);
193-
size_t shift_amount = bit_offset - delta;
194-
uint_t low_byte_mask = std::numeric_limits<uint8_t>::max();
195-
auto high_byte_mask = static_cast<uint_t>(low_byte_mask << shift_amount);
196-
uint_t new_value = val;
197-
for (size_t ii = 0; ii < sizeof(T) / 2; ++ii) {
198-
bit_offset -= delta;
199-
uint_t const low_byte = new_value & low_byte_mask;
200-
uint_t const high_byte = new_value & high_byte_mask;
201-
new_value ^= low_byte;
202-
new_value ^= high_byte;
203-
new_value ^= static_cast<uint_t>(low_byte << bit_offset);
204-
new_value ^= static_cast<uint_t>(high_byte >> bit_offset);
205-
low_byte_mask = std::rotl(low_byte_mask, nbits);
206-
high_byte_mask = std::rotr(high_byte_mask, nbits);
207-
}
208-
return uint_t(new_value & std::numeric_limits<uint_t>::max());
209-
};
210217
if constexpr (CHAR_BIT == 8) {
211218
if (!std::is_constant_evaluated()) {
212219
constexpr auto const builtin_bswap = overloaded(

0 commit comments

Comments
 (0)