diff --git a/include/boost/core/bit.hpp b/include/boost/core/bit.hpp index 5612f71..2de69ac 100644 --- a/include/boost/core/bit.hpp +++ b/include/boost/core/bit.hpp @@ -792,6 +792,60 @@ typedef endian::type endian_type; #undef BOOST_CORE_BIT_NATIVE_INITIALIZER +// byteswap + +namespace detail +{ + +BOOST_CONSTEXPR inline boost::uint8_t byteswap_impl( boost::uint8_t x ) BOOST_NOEXCEPT +{ + return x; +} + +BOOST_CONSTEXPR inline boost::uint16_t byteswap_impl( boost::uint16_t x ) BOOST_NOEXCEPT +{ + return (x << 8) | (x >> 8); +} + +BOOST_CXX14_CONSTEXPR inline boost::uint32_t byteswap_impl( boost::uint32_t x ) BOOST_NOEXCEPT +{ + boost::uint32_t step16 = x << 16 | x >> 16; + return ((step16 << 8) & 0xff00ff00) | ((step16 >> 8) & 0x00ff00ff); +} + +BOOST_CXX14_CONSTEXPR inline boost::uint64_t byteswap_impl( boost::uint64_t x ) BOOST_NOEXCEPT +{ + boost::uint64_t step32 = x << 32 | x >> 32; + boost::uint64_t step16 = (step32 & 0x0000FFFF0000FFFFULL) << 16 | (step32 & 0xFFFF0000FFFF0000ULL) >> 16; + return (step16 & 0x00FF00FF00FF00FFULL) << 8 | (step16 & 0xFF00FF00FF00FF00ULL) >> 8; +} + +} // namespace detail + +template BOOST_CXX14_CONSTEXPR T byteswap( T x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( std::numeric_limits::is_integer ); + + BOOST_STATIC_ASSERT( sizeof(T) == sizeof(boost::uint8_t) || sizeof(T) == sizeof(boost::uint16_t) || sizeof(T) == sizeof(boost::uint32_t) || sizeof(T) == sizeof(boost::uint64_t) ); + + BOOST_IF_CONSTEXPR ( sizeof(T) == sizeof(boost::uint8_t) ) + { + return static_cast( boost::core::detail::byteswap_impl( static_cast( x ) ) ); + } + else BOOST_IF_CONSTEXPR ( sizeof(T) == sizeof(boost::uint16_t) ) + { + return static_cast( boost::core::detail::byteswap_impl( static_cast( x ) ) ); + } + else BOOST_IF_CONSTEXPR ( sizeof(T) == sizeof(boost::uint32_t) ) + { + return static_cast( boost::core::detail::byteswap_impl( static_cast( x ) ) ); + } + else + { + return static_cast( boost::core::detail::byteswap_impl( static_cast( x ) ) ); + } +} + } // namespace core } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 66bc8ab..0a8e8dd 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -296,6 +296,8 @@ run bit_popcount_test.cpp : : : $(pedantic-errors) ; run bit_endian_test.cpp : : : $(pedantic-errors) ; +run bit_byteswap_test.cpp + : : : $(pedantic-errors) ; compile-fail bit_width_fail.cpp : off ; @@ -308,6 +310,7 @@ compile has_single_bit_test_cx.cpp ; compile bit_floor_test_cx.cpp ; compile bit_ceil_test_cx.cpp ; compile bit_popcount_test_cx.cpp ; +compile bit_byteswap_test_cx.cpp ; run type_name_test.cpp ; diff --git a/test/bit_byteswap_test.cpp b/test/bit_byteswap_test.cpp new file mode 100644 index 0000000..850cbfa --- /dev/null +++ b/test/bit_byteswap_test.cpp @@ -0,0 +1,26 @@ +// Test for boost/core/bit.hpp (byteswap) +// +// Copyright 2023 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +int main() +{ + BOOST_TEST_EQ( boost::core::byteswap( (boost::int8_t)0x01 ), 0x01 ); + BOOST_TEST_EQ( boost::core::byteswap( (boost::uint8_t)0xF1 ), 0xF1 ); + + BOOST_TEST_EQ( boost::core::byteswap( (boost::int16_t)0x0102 ), 0x0201 ); + BOOST_TEST_EQ( boost::core::byteswap( (boost::uint16_t)0xF1E2 ), 0xE2F1 ); + + BOOST_TEST_EQ( boost::core::byteswap( (boost::int32_t)0x01020304 ), 0x04030201 ); + BOOST_TEST_EQ( boost::core::byteswap( (boost::uint32_t)0xF1E2D3C4u ), 0xC4D3E2F1u ); + + BOOST_TEST_EQ( boost::core::byteswap( (boost::int64_t)0x0102030405060708ll ), 0x0807060504030201ll ); + BOOST_TEST_EQ( boost::core::byteswap( (boost::uint64_t)0xF1E2D3C4B5A69788ull ), 0x8897A6B5C4D3E2F1ull ); + + return boost::report_errors(); +} diff --git a/test/bit_byteswap_test_cx.cpp b/test/bit_byteswap_test_cx.cpp new file mode 100644 index 0000000..384d87b --- /dev/null +++ b/test/bit_byteswap_test_cx.cpp @@ -0,0 +1,37 @@ +// constexpr test for boost/core/bit.hpp (bit_width) +// +// Copyright 2023 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +#if defined(BOOST_NO_CXX14_CONSTEXPR) + +BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" ) + +#elif defined(BOOST_MSVC) && BOOST_MSVC / 10 == 191 + +BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC is " BOOST_STRINGIZE(BOOST_MSVC) ) + +#else + +#include +#include + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +STATIC_ASSERT( boost::core::byteswap( (std::int8_t)0x01 ) == 0x01 ); +STATIC_ASSERT( boost::core::byteswap( (std::uint8_t)0xF1 ) == 0xF1 ); + +STATIC_ASSERT( boost::core::byteswap( (std::int16_t)0x0102 ) == 0x0201 ); +STATIC_ASSERT( boost::core::byteswap( (std::uint16_t)0xF1E2 ) == 0xE2F1 ); + +STATIC_ASSERT( boost::core::byteswap( (std::int32_t)0x01020304 ) == 0x04030201 ); +STATIC_ASSERT( boost::core::byteswap( (std::uint32_t)0xF1E2D3C4u ) == 0xC4D3E2F1u ); + +STATIC_ASSERT( boost::core::byteswap( (std::int64_t)0x0102030405060708ll ) == 0x0807060504030201ll ); +STATIC_ASSERT( boost::core::byteswap( (std::uint64_t)0xF1E2D3C4B5A69788ull ) == 0x8897A6B5C4D3E2F1ull ); + +#endif