diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp index 19ad05a8..650a3dc9 100644 --- a/include/intx/intx.hpp +++ b/include/intx/intx.hpp @@ -536,6 +536,40 @@ inline constexpr unsigned clz(uint128 x) noexcept return x[1] == 0 ? clz(x[0]) + 64 : clz(x[1]); } +template +T bswap(T x) noexcept = delete; // Disable type auto promotion + +inline constexpr uint8_t bswap(uint8_t x) noexcept +{ + return x; +} + +inline constexpr uint16_t bswap(uint16_t x) noexcept +{ +#if __has_builtin(__builtin_bswap16) + return __builtin_bswap16(x); +#else + #ifdef _MSC_VER + if (!is_constant_evaluated()) + return _byteswap_ushort(x); + #endif + return static_cast((x << 8) | (x >> 8)); +#endif +} + +inline constexpr uint32_t bswap(uint32_t x) noexcept +{ +#if __has_builtin(__builtin_bswap32) + return __builtin_bswap32(x); +#else + #ifdef _MSC_VER + if (!is_constant_evaluated()) + return _byteswap_ulong(x); + #endif + const auto a = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0x00FF00FF); + return (a << 16) | (a >> 16); +#endif +} inline constexpr uint64_t bswap(uint64_t x) noexcept { diff --git a/test/unittests/test_builtins.cpp b/test/unittests/test_builtins.cpp index 7259f7f7..99221dbf 100644 --- a/test/unittests/test_builtins.cpp +++ b/test/unittests/test_builtins.cpp @@ -141,3 +141,60 @@ TEST(builtins, is_constant_evaluated) EXPECT_EQ(nonconstexpr_func_res, 1); #endif } + +static_assert(bswap(uint8_t{0x81}) == 0x81); +static_assert(bswap(uint16_t{0x8681}) == 0x8186); +static_assert(bswap(uint32_t{0x86818082}) == 0x82808186); +static_assert(bswap(uint64_t{0x8680808081808082}) == 0x8280808180808086); +TEST(builtins, bswap) +{ + uint8_t x8 = 0x86; + EXPECT_EQ(bswap(x8), 0x86); + uint16_t x16 = 0x8681; + EXPECT_EQ(bswap(x16), 0x8186); + uint32_t x32 = 0x86818082; + EXPECT_EQ(bswap(x32), 0x82808186); + uint64_t x64 = 0x8680808081808082; + EXPECT_EQ(bswap(x64), 0x8280808180808086); + uint128 x128 = uint128{0x8680808081808082, 0x8080838080848085}; + EXPECT_EQ(bswap(x128), (uint128{0x8580848080838080, 0x8280808180808086})); +} + +TEST(builtins, be_load_uint8_t) +{ + constexpr auto size = sizeof(uint8_t); + uint8_t data[size]{}; + data[0] = 0x81; + const auto x = be::unsafe::load(data); + EXPECT_EQ(x, 0x81); +} + +TEST(builtins, be_load_uint16_t) +{ + constexpr auto size = sizeof(uint16_t); + uint8_t data[size]{}; + data[0] = 0x80; + data[size - 1] = 1; + const auto x = be::unsafe::load(data); + EXPECT_EQ(x, (uint16_t{1} << (sizeof(uint16_t) * 8 - 1)) | 1); +} + +TEST(builtins, be_load_uint32_t) +{ + constexpr auto size = sizeof(uint32_t); + uint8_t data[size]{}; + data[0] = 0x80; + data[size - 1] = 1; + const auto x = be::unsafe::load(data); + EXPECT_EQ(x, (uint32_t{1} << (sizeof(uint32_t) * 8 - 1)) | 1); +} + +TEST(builtins, be_load_uint64_t) +{ + constexpr auto size = sizeof(uint64_t); + uint8_t data[size]{}; + data[0] = 0x80; + data[size - 1] = 1; + const auto x = be::unsafe::load(data); + EXPECT_EQ(x, (uint64_t{1} << (sizeof(uint64_t) * 8 - 1)) | 1); +} diff --git a/test/unittests/test_intx.cpp b/test/unittests/test_intx.cpp index c72e4fcb..173534f0 100644 --- a/test/unittests/test_intx.cpp +++ b/test/unittests/test_intx.cpp @@ -334,7 +334,6 @@ TYPED_TEST(uint_test, count_significant_bytes) EXPECT_EQ(count_significant_bytes(x), sizeof(TypeParam)); } -static_assert(bswap(uint64_t{0x6600000001000002}) == 0x0200000100000066, ""); TYPED_TEST(uint_test, bswap) { auto x = TypeParam{1};