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