Refactor endian_reverse into its own header, make it work for long and long long

This commit is contained in:
Peter Dimov
2019-04-26 20:24:27 +03:00
parent e9feff0abb
commit a2025a9320
3 changed files with 116 additions and 141 deletions

View File

@ -8,12 +8,12 @@
#ifndef BOOST_ENDIAN_CONVERSION_HPP
#define BOOST_ENDIAN_CONVERSION_HPP
#include <boost/config.hpp>
#include <boost/predef/other/endian.h>
#include <boost/cstdint.hpp>
#include <boost/endian/detail/intrinsic.hpp>
#include <boost/endian/detail/endian_reverse.hpp>
#include <boost/core/scoped_enum.hpp>
#include <boost/predef/other/endian.h>
#include <boost/static_assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/config.hpp>
#include <algorithm>
#include <cstring> // 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<class T> inline T endian_load( T x ) BOOST_NOEXCEPT;
// reverse byte order unless native endianness is big
template <class EndianReversible >
@ -123,6 +114,7 @@ namespace endian
//------------------------------------------------------------------------------------//
// reverse in place
// in detail/endian_reverse.hpp
template <class EndianReversible>
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<uint16_t>(x) << 8)
| (static_cast<uint16_t>(x) >> 8);
# else
return static_cast<int16_t>(
BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(static_cast<uint16_t>(x)));
# endif
}
inline int32_t endian_reverse(int32_t x) BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_NO_INTRINSICS
uint32_t step16;
step16 = static_cast<uint32_t>(x) << 16 | static_cast<uint32_t>(x) >> 16;
return
((static_cast<uint32_t>(step16) << 8) & 0xff00ff00)
| ((static_cast<uint32_t>(step16) >> 8) & 0x00ff00ff);
# else
return static_cast<int32_t>(
BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(static_cast<uint32_t>(x)));
# endif
}
inline int64_t endian_reverse(int64_t x) BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_NO_INTRINSICS
uint64_t step32, step16;
step32 = static_cast<uint64_t>(x) << 32 | static_cast<uint64_t>(x) >> 32;
step16 = (step32 & 0x0000FFFF0000FFFFULL) << 16
| (step32 & 0xFFFF0000FFFF0000ULL) >> 16;
return static_cast<int64_t>((step16 & 0x00FF00FF00FF00FFULL) << 8
| (step16 & 0xFF00FF00FF00FF00ULL) >> 8);
# else
return static_cast<int64_t>(
BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(static_cast<uint64_t>(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<char>( endian_reverse( static_cast<uint8_t>(x) ) );
}
#if !defined(BOOST_NO_CXX11_CHAR16_T)
inline char16_t endian_reverse(char16_t x) BOOST_NOEXCEPT
{
return static_cast<char16_t>( endian_reverse( static_cast<uint16_t>(x) ) );
}
#endif
template <class EndianReversible >
inline EndianReversible big_to_native(EndianReversible x) BOOST_NOEXCEPT
{
@ -376,13 +255,6 @@ namespace endian
// reverse-in-place implementation //
//--------------------------------------------------------------------------------------//
// reverse in place
template <class EndianReversible>
inline void endian_reverse_inplace(EndianReversible& x) BOOST_NOEXCEPT
{
x = endian_reverse(x);
}
template <class EndianReversibleInplace>
# if BOOST_ENDIAN_BIG_BYTE
inline void big_to_native_inplace(EndianReversibleInplace&) BOOST_NOEXCEPT {}

View File

@ -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 <boost/endian/detail/integral_by_size.hpp>
#include <boost/endian/detail/intrinsic.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/static_assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/config.hpp>
#include <cstddef>
#include <cstring>
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<class T> inline T endian_reverse( T x ) BOOST_NOEXCEPT
{
BOOST_STATIC_ASSERT( is_integral<T>::value && !is_same<T, bool>::value );
typedef typename detail::integral_by_size< sizeof(T) >::type uintN_t;
return static_cast<T>( detail::endian_reverse_impl( static_cast<uintN_t>( x ) ) );
}
template <class EndianReversible>
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

View File

@ -138,11 +138,11 @@ int main()
test<int>();
test<unsigned int>();
// test<long>();
// test<unsigned long>();
test<long>();
test<unsigned long>();
// test<long long>();
// test<unsigned long long>();
test<long long>();
test<unsigned long long>();
#if !defined(BOOST_NO_CXX11_CHAR16_T)
test<char16_t>();