From a2025a93200756d8f837a4c4c0ff184033ea2a9b Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 26 Apr 2019 20:24:27 +0300 Subject: [PATCH] Refactor endian_reverse into its own header, make it work for long and long long --- include/boost/endian/conversion.hpp | 146 ++---------------- .../boost/endian/detail/endian_reverse.hpp | 103 ++++++++++++ test/endian_reverse_test.cpp | 8 +- 3 files changed, 116 insertions(+), 141 deletions(-) create mode 100644 include/boost/endian/detail/endian_reverse.hpp diff --git a/include/boost/endian/conversion.hpp b/include/boost/endian/conversion.hpp index a316a3d..894a461 100644 --- a/include/boost/endian/conversion.hpp +++ b/include/boost/endian/conversion.hpp @@ -8,12 +8,12 @@ #ifndef BOOST_ENDIAN_CONVERSION_HPP #define BOOST_ENDIAN_CONVERSION_HPP -#include -#include -#include -#include +#include #include +#include #include +#include +#include #include #include // for memcpy @@ -49,19 +49,10 @@ namespace endian // // //--------------------------------------------------------------------------------------// - // customization for exact-length arithmetic types. See doc/conversion.html/#FAQ. - // Note: The omission of a overloads for the arithmetic type (typically long, or - // long long) not assigned to one of the exact length typedefs is a deliberate - // design decision. Such overloads would be non-portable and thus error prone. - - inline int8_t endian_reverse(int8_t x) BOOST_NOEXCEPT; - inline int16_t endian_reverse(int16_t x) BOOST_NOEXCEPT; - inline int32_t endian_reverse(int32_t x) BOOST_NOEXCEPT; - inline int64_t endian_reverse(int64_t x) BOOST_NOEXCEPT; - inline uint8_t endian_reverse(uint8_t x) BOOST_NOEXCEPT; - inline uint16_t endian_reverse(uint16_t x) BOOST_NOEXCEPT; - inline uint32_t endian_reverse(uint32_t x) BOOST_NOEXCEPT; - inline uint64_t endian_reverse(uint64_t x) BOOST_NOEXCEPT; + // reverse byte order + // requires T to be a non-bool integral type + // in detail/endian_reverse.hpp + template inline T endian_load( T x ) BOOST_NOEXCEPT; // reverse byte order unless native endianness is big template @@ -123,6 +114,7 @@ namespace endian //------------------------------------------------------------------------------------// // reverse in place + // in detail/endian_reverse.hpp template inline void endian_reverse_inplace(EndianReversible& x) BOOST_NOEXCEPT; // Effects: x = endian_reverse(x) @@ -183,119 +175,6 @@ namespace endian inline void little_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT; } // namespace detail -//--------------------------------------------------------------------------------------// -// // -// return-by-value implementation // -// // -// -- portable approach suggested by tymofey, with avoidance of undefined behavior // -// as suggested by Giovanni Piero Deretta, with a further refinement suggested // -// by Pyry Jahkola. // -// -- intrinsic approach suggested by reviewers, and by David Stone, who provided // -// his Boost licensed macro implementation (detail/intrinsic.hpp) // -// // -//--------------------------------------------------------------------------------------// - - inline int8_t endian_reverse(int8_t x) BOOST_NOEXCEPT - { - return x; - } - - inline int16_t endian_reverse(int16_t x) BOOST_NOEXCEPT - { -# ifdef BOOST_ENDIAN_NO_INTRINSICS - return (static_cast(x) << 8) - | (static_cast(x) >> 8); -# else - return static_cast( - BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(static_cast(x))); -# endif - } - - inline int32_t endian_reverse(int32_t x) BOOST_NOEXCEPT - { -# ifdef BOOST_ENDIAN_NO_INTRINSICS - uint32_t step16; - step16 = static_cast(x) << 16 | static_cast(x) >> 16; - return - ((static_cast(step16) << 8) & 0xff00ff00) - | ((static_cast(step16) >> 8) & 0x00ff00ff); -# else - return static_cast( - BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(static_cast(x))); -# endif - } - - inline int64_t endian_reverse(int64_t x) BOOST_NOEXCEPT - { -# ifdef BOOST_ENDIAN_NO_INTRINSICS - uint64_t step32, step16; - step32 = static_cast(x) << 32 | static_cast(x) >> 32; - step16 = (step32 & 0x0000FFFF0000FFFFULL) << 16 - | (step32 & 0xFFFF0000FFFF0000ULL) >> 16; - return static_cast((step16 & 0x00FF00FF00FF00FFULL) << 8 - | (step16 & 0xFF00FF00FF00FF00ULL) >> 8); -# else - return static_cast( - BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(static_cast(x))); -# endif - } - - inline uint8_t endian_reverse(uint8_t x) BOOST_NOEXCEPT - { - return x; - } - - inline uint16_t endian_reverse(uint16_t x) BOOST_NOEXCEPT - { -# ifdef BOOST_ENDIAN_NO_INTRINSICS - return (x << 8) - | (x >> 8); -# else - return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(x); -# endif - } - - inline uint32_t endian_reverse(uint32_t x) BOOST_NOEXCEPT - { -# ifdef BOOST_ENDIAN_NO_INTRINSICS - uint32_t step16; - step16 = x << 16 | x >> 16; - return - ((step16 << 8) & 0xff00ff00) - | ((step16 >> 8) & 0x00ff00ff); -# else - return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(x); -# endif - } - - inline uint64_t endian_reverse(uint64_t x) BOOST_NOEXCEPT - { -# ifdef BOOST_ENDIAN_NO_INTRINSICS - uint64_t step32, step16; - step32 = x << 32 | x >> 32; - step16 = (step32 & 0x0000FFFF0000FFFFULL) << 16 - | (step32 & 0xFFFF0000FFFF0000ULL) >> 16; - return (step16 & 0x00FF00FF00FF00FFULL) << 8 - | (step16 & 0xFF00FF00FF00FF00ULL) >> 8; -# else - return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(x); -# endif - } - - // overloads for char and char16_t, which otherwise use int32_t - - inline char endian_reverse(char x) BOOST_NOEXCEPT - { - return static_cast( endian_reverse( static_cast(x) ) ); - } - -#if !defined(BOOST_NO_CXX11_CHAR16_T) - inline char16_t endian_reverse(char16_t x) BOOST_NOEXCEPT - { - return static_cast( endian_reverse( static_cast(x) ) ); - } -#endif - template inline EndianReversible big_to_native(EndianReversible x) BOOST_NOEXCEPT { @@ -376,13 +255,6 @@ namespace endian // reverse-in-place implementation // //--------------------------------------------------------------------------------------// - // reverse in place - template - inline void endian_reverse_inplace(EndianReversible& x) BOOST_NOEXCEPT - { - x = endian_reverse(x); - } - template # if BOOST_ENDIAN_BIG_BYTE inline void big_to_native_inplace(EndianReversibleInplace&) BOOST_NOEXCEPT {} diff --git a/include/boost/endian/detail/endian_reverse.hpp b/include/boost/endian/detail/endian_reverse.hpp new file mode 100644 index 0000000..cb80c79 --- /dev/null +++ b/include/boost/endian/detail/endian_reverse.hpp @@ -0,0 +1,103 @@ +#ifndef BOOST_ENDIAN_DETAIL_ENDIAN_REVERSE_HPP_INCLUDED +#define BOOST_ENDIAN_DETAIL_ENDIAN_REVERSE_HPP_INCLUDED + +// Copyright 2019 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ +namespace endian +{ + +namespace detail +{ + +// -- portable approach suggested by tymofey, with avoidance of undefined behavior +// as suggested by Giovanni Piero Deretta, with a further refinement suggested +// by Pyry Jahkola. +// -- intrinsic approach suggested by reviewers, and by David Stone, who provided +// his Boost licensed macro implementation (detail/intrinsic.hpp) + +inline uint8_t endian_reverse_impl( uint8_t x ) BOOST_NOEXCEPT +{ + return x; +} + +inline uint16_t endian_reverse_impl( uint16_t x ) BOOST_NOEXCEPT +{ +#ifdef BOOST_ENDIAN_NO_INTRINSICS + + return (x << 8) | (x >> 8); + +#else + + return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(x); + +#endif +} + +inline uint32_t endian_reverse_impl(uint32_t x) BOOST_NOEXCEPT +{ +#ifdef BOOST_ENDIAN_NO_INTRINSICS + + uint32_t step16 = x << 16 | x >> 16; + return ((step16 << 8) & 0xff00ff00) | ((step16 >> 8) & 0x00ff00ff); + +#else + + return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(x); + +#endif +} + +inline uint64_t endian_reverse_impl(uint64_t x) BOOST_NOEXCEPT +{ +#ifdef BOOST_ENDIAN_NO_INTRINSICS + + uint64_t step32 = x << 32 | x >> 32; + uint64_t step16 = (step32 & 0x0000FFFF0000FFFFULL) << 16 | (step32 & 0xFFFF0000FFFF0000ULL) >> 16; + return (step16 & 0x00FF00FF00FF00FFULL) << 8 | (step16 & 0xFF00FF00FF00FF00ULL) >> 8; + +#else + + return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(x); + +# endif +} + +} // namespace detail + +// Requires: +// T is non-bool integral + +template inline T endian_reverse( T x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( is_integral::value && !is_same::value ); + + typedef typename detail::integral_by_size< sizeof(T) >::type uintN_t; + + return static_cast( detail::endian_reverse_impl( static_cast( x ) ) ); +} + +template +inline void endian_reverse_inplace(EndianReversible& x) BOOST_NOEXCEPT +{ + x = endian_reverse( x ); +} + +} // namespace endian +} // namespace boost + +#endif // BOOST_ENDIAN_DETAIL_ENDIAN_REVERSE_HPP_INCLUDED diff --git a/test/endian_reverse_test.cpp b/test/endian_reverse_test.cpp index dac1840..9dbba16 100644 --- a/test/endian_reverse_test.cpp +++ b/test/endian_reverse_test.cpp @@ -138,11 +138,11 @@ int main() test(); test(); - // test(); - // test(); + test(); + test(); - // test(); - // test(); + test(); + test(); #if !defined(BOOST_NO_CXX11_CHAR16_T) test();