@@ -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