Skip to content

Commit

Permalink
Add support for bswap of small types
Browse files Browse the repository at this point in the history
Add implementation of bswap uint8_t, uint16_t and uint32_t and delete
other overloading. Also add tests for be::unsafe::load to make sure
they work correctly now.

Co-Authored-By: Paweł Bylica <pawel@hepcolgum.band>
  • Loading branch information
rodiazet and chfast committed Feb 15, 2022
1 parent ceb8640 commit ef40d49
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 1 deletion.
34 changes: 34 additions & 0 deletions include/intx/intx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,40 @@ inline constexpr unsigned clz(uint128 x) noexcept
return x[1] == 0 ? clz(x[0]) + 64 : clz(x[1]);
}

template <typename T>
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<uint16_t>((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
{
Expand Down
57 changes: 57 additions & 0 deletions test/unittests/test_builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t>(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<uint16_t>(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<uint32_t>(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<uint64_t>(data);
EXPECT_EQ(x, (uint64_t{1} << (sizeof(uint64_t) * 8 - 1)) | 1);
}
1 change: 0 additions & 1 deletion test/unittests/test_intx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down

0 comments on commit ef40d49

Please sign in to comment.