From d7aca60d7257f2a06d0e21ea97bf9520f8f91a8a Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 23 Apr 2024 22:29:24 +0300 Subject: [PATCH] Add u16 support to endian.hpp --- include/boost/uuid/detail/endian.hpp | 85 +++++++++++++++++++ test/test_detail_endian.cpp | 120 +++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) diff --git a/include/boost/uuid/detail/endian.hpp b/include/boost/uuid/detail/endian.hpp index 21ed124..7ec2cb8 100644 --- a/include/boost/uuid/detail/endian.hpp +++ b/include/boost/uuid/detail/endian.hpp @@ -46,6 +46,11 @@ namespace detail { #if defined(__GNUC__) || defined(__clang__) +inline std::uint16_t byteswap( std::uint16_t x ) +{ + return __builtin_bswap16( x ); +} + inline std::uint32_t byteswap( std::uint32_t x ) { return __builtin_bswap32( x ); @@ -58,6 +63,11 @@ inline std::uint64_t byteswap( std::uint64_t x ) #elif defined(_MSC_VER) +inline std::uint16_t byteswap( std::uint16_t x ) +{ + return _byteswap_ushort( x ); +} + inline std::uint32_t byteswap( std::uint32_t x ) { return _byteswap_ulong( x ); @@ -70,6 +80,11 @@ inline std::uint64_t byteswap( std::uint64_t x ) #else +inline std::uint16_t byteswap( std::uint16_t x ) +{ + return static_cast( x << 8 | x >> 8 ); +} + inline std::uint32_t byteswap( std::uint32_t x ) { std::uint32_t step16 = x << 16 | x >> 16; @@ -94,6 +109,47 @@ inline __uint128_t byteswap( __uint128_t x ) #endif +// load_*_u16 + +inline std::uint16_t load_native_u16( void const* p ) +{ + std::uint16_t tmp; + std::memcpy( &tmp, p, sizeof( tmp ) ); + return tmp; +} + +inline std::uint16_t load_little_u16( void const* p ) +{ + std::uint16_t tmp; + std::memcpy( &tmp, p, sizeof( tmp ) ); + +#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_LITTLE_ENDIAN + + return tmp; + +#else + + return detail::byteswap( tmp ); + +#endif +} + +inline std::uint16_t load_big_u16( void const* p ) +{ + std::uint16_t tmp; + std::memcpy( &tmp, p, sizeof( tmp ) ); + +#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_BIG_ENDIAN + + return tmp; + +#else + + return detail::byteswap( tmp ); + +#endif +} + // load_*_u32 inline std::uint32_t load_native_u32( void const* p ) @@ -221,6 +277,35 @@ inline __uint128_t load_big_u128( void const* p ) #endif +// store_*_u16 + +inline void store_native_u16( void* p, std::uint16_t v ) +{ + std::memcpy( p, &v, sizeof( v ) ); +} + +inline void store_little_u16( void* p, std::uint16_t v ) +{ +#if BOOST_UUID_BYTE_ORDER != BOOST_UUID_ORDER_LITTLE_ENDIAN + + v = detail::byteswap( v ); + +#endif + + std::memcpy( p, &v, sizeof( v ) ); +} + +inline void store_big_u16( void* p, std::uint16_t v ) +{ +#if BOOST_UUID_BYTE_ORDER != BOOST_UUID_ORDER_BIG_ENDIAN + + v = detail::byteswap( v ); + +#endif + + std::memcpy( p, &v, sizeof( v ) ); +} + // store_*_u32 inline void store_native_u32( void* p, std::uint32_t v ) diff --git a/test/test_detail_endian.cpp b/test/test_detail_endian.cpp index c2fb263..1c795c9 100644 --- a/test/test_detail_endian.cpp +++ b/test/test_detail_endian.cpp @@ -10,6 +10,24 @@ int main() { namespace detail = boost::uuids::detail; + // byteswap u16 + + { + std::uint16_t x = 0x0102; + std::uint16_t y = 0x0201; + + BOOST_TEST_EQ( detail::byteswap( x ), y ); + BOOST_TEST_EQ( detail::byteswap( y ), x ); + } + + { + std::uint16_t x = 0xFFEE; + std::uint16_t y = 0xEEFF; + + BOOST_TEST_EQ( detail::byteswap( x ), y ); + BOOST_TEST_EQ( detail::byteswap( y ), x ); + } + // byteswap u32 { @@ -60,6 +78,48 @@ int main() #endif + // load u16 + + { + std::uint16_t x = 0x0102; + std::uint16_t y = 0x0201; + + unsigned char data[] = { 0x01, 0x02 }; + + BOOST_TEST_EQ( detail::load_little_u16( data ), y ); + BOOST_TEST_EQ( detail::load_big_u16( data ), x ); + +#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_LITTLE_ENDIAN + + BOOST_TEST_EQ( detail::load_native_u16( data ), y ); + +#else + + BOOST_TEST_EQ( detail::load_native_u16( data ), x ); + +#endif + } + + { + std::uint16_t x = 0xFFEE; + std::uint16_t y = 0xEEFF; + + unsigned char data[] = { 0xFF, 0xEE }; + + BOOST_TEST_EQ( detail::load_little_u16( data ), y ); + BOOST_TEST_EQ( detail::load_big_u16( data ), x ); + +#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_LITTLE_ENDIAN + + BOOST_TEST_EQ( detail::load_native_u16( data ), y ); + +#else + + BOOST_TEST_EQ( detail::load_native_u16( data ), x ); + +#endif + } + // load u32 { @@ -170,6 +230,66 @@ int main() #endif + // store u16 + + { + std::uint16_t x = 0x0102; + std::uint16_t y = 0x0201; + + unsigned char data[ 2 ] = {}; + + detail::store_little_u16( data, x ); + BOOST_TEST_EQ( detail::load_little_u16( data ), x ); + BOOST_TEST_EQ( detail::load_big_u16( data ), y ); + + detail::store_big_u16( data, x ); + BOOST_TEST_EQ( detail::load_little_u16( data ), y ); + BOOST_TEST_EQ( detail::load_big_u16( data ), x ); + + detail::store_native_u16( data, x ); + +#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_LITTLE_ENDIAN + + BOOST_TEST_EQ( detail::load_little_u16( data ), x ); + BOOST_TEST_EQ( detail::load_big_u16( data ), y ); + +#else + + BOOST_TEST_EQ( detail::load_little_u16( data ), y ); + BOOST_TEST_EQ( detail::load_big_u16( data ), x ); + +#endif + } + + { + std::uint16_t x = 0xFFEE; + std::uint16_t y = 0xEEFF; + + unsigned char data[ 2 ] = {}; + + detail::store_little_u16( data, x ); + BOOST_TEST_EQ( detail::load_little_u16( data ), x ); + BOOST_TEST_EQ( detail::load_big_u16( data ), y ); + + detail::store_big_u16( data, x ); + BOOST_TEST_EQ( detail::load_little_u16( data ), y ); + BOOST_TEST_EQ( detail::load_big_u16( data ), x ); + + detail::store_native_u16( data, x ); + +#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_LITTLE_ENDIAN + + BOOST_TEST_EQ( detail::load_little_u16( data ), x ); + BOOST_TEST_EQ( detail::load_big_u16( data ), y ); + +#else + + BOOST_TEST_EQ( detail::load_little_u16( data ), y ); + BOOST_TEST_EQ( detail::load_big_u16( data ), x ); + +#endif + } + // store u32 {