Skip to content

Commit 092e0a7

Browse files
committed
Clarifying fallback byteswap implementation
1 parent c2619cb commit 092e0a7

File tree

1 file changed

+20
-16
lines changed

1 file changed

+20
-16
lines changed

include/mdcomp/bigendian_io.hh

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -187,27 +187,26 @@ namespace detail {
187187
using uint_t = std::make_unsigned_t<std::remove_cvref_t<UT>>;
188188
// Fallback implementation that handles even __int24 etc.
189189
constexpr size_t const nbits = CHAR_BIT;
190+
constexpr size_t const delta = 2ULL * nbits;
190191

191-
size_t diff = nbits * (sizeof(T) - 1);
192-
uint_t mask1 = std::numeric_limits<uint8_t>::max();
193-
auto mask2 = static_cast<uint_t>(mask1 << diff);
194-
uint_t new_value = val;
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;
195197
for (size_t ii = 0; ii < sizeof(T) / 2; ++ii) {
196-
uint_t const byte1 = new_value & mask1;
197-
uint_t const byte2 = new_value & mask2;
198-
auto const byte3 = static_cast<uint_t>(byte1 << diff);
199-
auto const byte4 = static_cast<uint_t>(byte2 >> diff);
200-
new_value ^= byte1;
201-
new_value ^= byte2;
202-
new_value ^= byte3;
203-
new_value ^= byte4;
204-
mask1 = std::rotl(mask1, nbits);
205-
mask2 = std::rotr(mask2, nbits);
206-
diff -= 2ULL * nbits;
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);
207207
}
208208
return uint_t(new_value & std::numeric_limits<uint_t>::max());
209209
};
210-
// NOLINTNEXTLINE(misc-redundant-expression)
211210
if constexpr (CHAR_BIT == 8) {
212211
if (!std::is_constant_evaluated()) {
213212
constexpr auto const builtin_bswap = overloaded(
@@ -258,6 +257,11 @@ namespace detail {
258257
#endif
259258
}
260259

260+
static_assert(byteswap_impl(uint8_t{0x35U}) == uint8_t{0x35U});
261+
static_assert(byteswap_impl(uint16_t{0x1357U}) == uint16_t{0x5713U});
262+
static_assert(byteswap_impl(0x01234567U) == 0x67452301U);
263+
static_assert(byteswap_impl(0x0123456789abcdefULL) == 0xefcdab8967452301ULL);
264+
261265
template <std::integral T>
262266
[[nodiscard]] CONST_INLINE constexpr T byteswap(T value) noexcept {
263267
// Need this to handle "(unsigned)? long long" and "(unsigned)? long".

0 commit comments

Comments
 (0)