Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / endian / detail / endian_reverse.hpp
1 #ifndef BOOST_ENDIAN_DETAIL_ENDIAN_REVERSE_HPP_INCLUDED
2 #define BOOST_ENDIAN_DETAIL_ENDIAN_REVERSE_HPP_INCLUDED
3
4 // Copyright 2019 Peter Dimov
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // http://www.boost.org/LICENSE_1_0.txt
8
9 #include <boost/endian/detail/integral_by_size.hpp>
10 #include <boost/endian/detail/intrinsic.hpp>
11 #include <boost/type_traits/is_integral.hpp>
12 #include <boost/type_traits/is_same.hpp>
13 #include <boost/static_assert.hpp>
14 #include <boost/cstdint.hpp>
15 #include <boost/config.hpp>
16 #include <cstddef>
17 #include <cstring>
18
19 #if defined(BOOST_ENDIAN_NO_INTRINSICS)
20 # if defined(BOOST_NO_CXX14_CONSTEXPR)
21 #  define BOOST_ENDIAN_CONSTEXPR
22 # else
23 #  define BOOST_ENDIAN_CONSTEXPR constexpr
24 # endif
25 #else
26 # if defined(BOOST_ENDIAN_CONSTEXPR_INTRINSICS)
27 #  define BOOST_ENDIAN_CONSTEXPR BOOST_CONSTEXPR
28 # else
29 #  define BOOST_ENDIAN_CONSTEXPR
30 # endif
31 #endif
32
33 namespace boost
34 {
35 namespace endian
36 {
37
38 namespace detail
39 {
40
41 //  -- portable approach suggested by tymofey, with avoidance of undefined behavior
42 //     as suggested by Giovanni Piero Deretta, with a further refinement suggested
43 //     by Pyry Jahkola.
44 //  -- intrinsic approach suggested by reviewers, and by David Stone, who provided
45 //     his Boost licensed macro implementation (detail/intrinsic.hpp)
46
47 inline uint8_t BOOST_CONSTEXPR endian_reverse_impl( uint8_t x ) BOOST_NOEXCEPT
48 {
49     return x;
50 }
51
52 inline uint16_t BOOST_ENDIAN_CONSTEXPR endian_reverse_impl( uint16_t x ) BOOST_NOEXCEPT
53 {
54 #ifdef BOOST_ENDIAN_NO_INTRINSICS
55
56     return (x << 8) | (x >> 8);
57
58 #else
59
60     return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(x);
61
62 #endif
63 }
64
65 inline uint32_t BOOST_ENDIAN_CONSTEXPR endian_reverse_impl( uint32_t x ) BOOST_NOEXCEPT
66 {
67 #ifdef BOOST_ENDIAN_NO_INTRINSICS
68
69     uint32_t step16 = x << 16 | x >> 16;
70     return ((step16 << 8) & 0xff00ff00) | ((step16 >> 8) & 0x00ff00ff);
71
72 #else
73
74     return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(x);
75
76 #endif
77 }
78
79 inline uint64_t BOOST_ENDIAN_CONSTEXPR endian_reverse_impl( uint64_t x ) BOOST_NOEXCEPT
80 {
81 #ifdef BOOST_ENDIAN_NO_INTRINSICS
82
83     uint64_t step32 = x << 32 | x >> 32;
84     uint64_t step16 = (step32 & 0x0000FFFF0000FFFFULL) << 16 | (step32 & 0xFFFF0000FFFF0000ULL) >> 16;
85     return (step16 & 0x00FF00FF00FF00FFULL) << 8 | (step16 & 0xFF00FF00FF00FF00ULL) >> 8;
86
87 #else
88
89     return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(x);
90
91 # endif
92 }
93
94 #if defined(BOOST_HAS_INT128)
95
96 inline uint128_type BOOST_ENDIAN_CONSTEXPR endian_reverse_impl( uint128_type x ) BOOST_NOEXCEPT
97 {
98     return endian_reverse_impl( static_cast<uint64_t>( x >> 64 ) ) |
99         static_cast<uint128_type>( endian_reverse_impl( static_cast<uint64_t>( x ) ) ) << 64;
100 }
101
102 #endif
103
104 } // namespace detail
105
106 // Requires:
107 //    T is non-bool integral
108
109 template<class T> inline BOOST_CONSTEXPR T endian_reverse( T x ) BOOST_NOEXCEPT
110 {
111     BOOST_STATIC_ASSERT( is_integral<T>::value && !(is_same<T, bool>::value) );
112
113     typedef typename detail::integral_by_size< sizeof(T) >::type uintN_t;
114
115     return static_cast<T>( detail::endian_reverse_impl( static_cast<uintN_t>( x ) ) );
116 }
117
118 template <class EndianReversible>
119 inline void endian_reverse_inplace(EndianReversible& x) BOOST_NOEXCEPT
120 {
121     x = endian_reverse( x );
122 }
123
124 } // namespace endian
125 } // namespace boost
126
127 #endif  // BOOST_ENDIAN_DETAIL_ENDIAN_REVERSE_HPP_INCLUDED