Branch data Line data Source code
1 : : #ifndef bqtEndianHH
2 : : #define bqtEndianHH
3 : :
4 : : #include <cstdint>
5 : : #include <type_traits>
6 : : #include <tuple>
7 : :
8 : : #if defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L
9 : : # include <bit>
10 : : static constexpr bool LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK = (std::endian::native == std::endian::little);
11 : : static constexpr bool BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK = (std::endian::native == std::endian::big);
12 : : #else
13 : :
14 : : #if defined(__x86_64) || defined(__i386)
15 : : static constexpr bool LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK = true;
16 : : static constexpr bool BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK = false;
17 : : #else
18 : : static constexpr bool LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK = false;
19 : : static constexpr bool BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK = true;
20 : : #endif
21 : :
22 : : #endif
23 : :
24 : 321 : extern inline std::uint_least16_t BSwap16(std::uint_least16_t value)
25 : : {
26 : : #ifdef __GNUC
27 : : return __builtin_bswap16(value);
28 : : #else
29 : 321 : return (value >> 8) | (value << 8);
30 : : #endif
31 : : }
32 : 163 : extern inline std::uint_least32_t BSwap32(std::uint_least32_t value)
33 : : {
34 : : #ifdef __GNUC
35 : : return __builtin_bswap32(value);
36 : : #else
37 : 1 : return (BSwap16(value >> 16)) | (BSwap16(value) << 16);
38 : : #endif
39 : : }
40 : 2 : extern inline std::uint_least64_t BSwap64(std::uint_least64_t value)
41 : : {
42 : : #ifdef __GNUC
43 : : return __builtin_bswap64(value);
44 : : #else
45 : 2 : return (BSwap32(value >> 32)) | ((uint_fast64_t)BSwap32(value) << 32);
46 : : #endif
47 : : }
48 : :
49 : : template<std::size_t... Indexes>
50 : 4 : extern inline std::uint_fast64_t Read(const void* p)
51 : : {
52 : 4 : const unsigned char* data = (const unsigned char*)p;
53 : :
54 : 4 : std::tuple ord{ Indexes... };
55 : 4 : return [&]<std::size_t... I>(std::index_sequence<I...>)
56 : : {
57 : 4 : return ((std::uint_fast64_t(data[ std::get<I>(ord) ]) << (8*I))
58 : 4 : | ...);
59 : 4 : }( std::make_index_sequence<sizeof...(Indexes)>{} );
60 : : }
61 : : template<std::size_t... Indexes>
62 : : extern inline void Write(void* p, std::uint_fast64_t value)
63 : : {
64 : : unsigned char* data = (unsigned char*)p;
65 : :
66 : : std::tuple ord{ Indexes... };
67 : : return [&]<std::size_t... I>(std::index_sequence<I...>)
68 : : {
69 : : ( (data[ std::get<I>(ord) ] = (value >> (8*I))), ... );
70 : : }( std::make_index_sequence<sizeof...(Indexes)>{} );
71 : : }
72 : :
73 : 1033271 : extern inline std::uint_fast16_t R8(const void* p)
74 : : {
75 : 773257 : const unsigned char* data = (const unsigned char*)p;
76 : 1033271 : return data[0];
77 : : }
78 : 639534 : extern inline std::uint_fast16_t R16(const void* p)
79 : : {
80 : 639534 : if constexpr(LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
81 : 639534 : return *(const std::uint_least16_t*)p;
82 : : else if constexpr(BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
83 : : return BSwap16(*(const std::uint_least16_t*)p);
84 : : else //LCOV_EXCL_BR_LINE
85 : : return Read<0,1>(p);
86 : : }
87 : 158 : extern inline std::uint_fast16_t R16r(const void* p)
88 : : {
89 : 158 : if constexpr(BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
90 : : return *(const std::uint_least16_t*)p;
91 : 158 : else if constexpr(LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
92 [ + + ]: 159 : return BSwap16(*(const std::uint_least16_t*)p);
93 : : else //LCOV_EXCL_BR_LINE
94 : : return Read<1,0>(p);
95 : : }
96 : 3 : extern inline std::uint_fast32_t R24(const void* p)
97 : : {
98 : : /* Note: This might be faster if implemented through R32 and a bitwise and,
99 : : * but we cannot do that because we don't know if the third byte is a valid
100 : : * memory location.
101 : : */
102 : 1 : return Read<0,1,2>(p);
103 : : }
104 : 1 : extern inline std::uint_fast32_t R24r(const void* p)
105 : : {
106 : 1 : return Read<2,1,0>(p);
107 : : }
108 : 63 : extern inline std::uint_fast32_t R32(const void* p)
109 : : {
110 : 63 : if constexpr(LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
111 : 59 : return *(const std::uint_least32_t*)p;
112 : : else if constexpr(BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
113 : : return BSwap32(*(const std::uint_least32_t*)p);
114 : : else //LCOV_EXCL_BR_LINE
115 : : return Read<0,1,2,3>(p);
116 : : }
117 : 159 : extern inline std::uint_fast32_t R32r(const void* p)
118 : : {
119 : 159 : if constexpr(BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
120 : : return *(const std::uint_least32_t*)p;
121 : 159 : else if constexpr(LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
122 [ + + ]: 159 : return BSwap32(*(const std::uint_least32_t*)p);
123 : : else //LCOV_EXCL_BR_LINE
124 : : return Read<3,2,1,0>(p);
125 : : }
126 : :
127 : : #define L (uint_fast64_t)
128 : :
129 : 1 : extern inline std::uint_fast64_t R64(const void* p)
130 : : {
131 : 1 : if constexpr(LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
132 : 1 : return *(const std::uint_least64_t*)p;
133 : : else if constexpr(BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
134 : : return BSwap64(*(const std::uint_least64_t*)p);
135 : : else //LCOV_EXCL_BR_LINE
136 : : return Read<0,1,2,3,4,5,6,7>(p);
137 : : }
138 : 1 : extern inline std::uint_fast64_t R64r(const void* p)
139 : : {
140 : 1 : if constexpr(BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
141 : : return *(const std::uint_least64_t*)p;
142 : 1 : else if constexpr(LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
143 : 1 : return BSwap64(*(const std::uint_least64_t*)p);
144 : : else //LCOV_EXCL_BR_LINE
145 : : return Read<7,6,5,4,3,2,1,0>(p);
146 : : }
147 : :
148 : : #undef L
149 : :
150 : 1672809 : extern inline std::uint_fast64_t Rn(const void* p, unsigned bytes)
151 : : {
152 : 1672809 : const unsigned char* data = (const unsigned char*)p;
153 : 1672809 : switch(bytes) //LCOV_EXCL_BR_LINE
154 : : {
155 : : #ifdef __GNUC__
156 : 0 : default: __builtin_unreachable(); //LCOV_EXCL_BR_LINE
157 : : #else
158 : : case 0: return 0; //LCOV_EXCL_BR_LINE
159 : : default: [[fallthrough]]; //LCOV_EXCL_BR_LINE
160 : : #endif
161 : 1 : case 8: return R64(p);
162 : 1 : case 4: return R32(p);
163 : 639533 : case 2: return R16(p);
164 : 1033270 : case 1: return R8(p);
165 : 1 : case 7: return R32(p) | (std::uint_fast64_t(R24(data+4)) << 32);
166 : 1 : case 6: return R32(p) | (std::uint_fast64_t(R16(data+4)) << 32);
167 : 1 : case 5: return R32(p) | (std::uint_fast64_t(R8(data+4)) << 32);
168 : 1 : case 3: return R24(p);
169 : : }
170 : : }
171 : :
172 : 8 : extern inline void W8(void* p, std::uint_fast8_t value)
173 : : {
174 : 8 : unsigned char* data = (unsigned char*)p;
175 : 8 : data[0] = value;
176 : 7 : }
177 : 2 : extern inline void W16(void* p, std::uint_fast16_t value)
178 : : {
179 : 2 : if constexpr(LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
180 : 2 : *(uint_least16_t*)p = value;
181 : : else if constexpr(BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
182 : : *(uint_least16_t*)p = BSwap16(value);
183 : : else
184 : : Write<0,1>(p, value);
185 : 1 : }
186 : 1 : extern inline void W24(void* p, std::uint_fast32_t value)
187 : : {
188 : 1 : unsigned char* data = (unsigned char*)p;
189 : 1 : W16(data+0, value);
190 : 1 : W8(data+2, value >> 16u);
191 : 1 : }
192 : 4 : extern inline void W32(void* p, std::uint_fast32_t value)
193 : : {
194 : 4 : if constexpr(LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
195 : 4 : *(uint_least32_t*)p = value;
196 : : else if constexpr(BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
197 : : *(uint_least32_t*)p = BSwap32(value);
198 : : else //LCOV_EXCL_BR_LINE
199 : : Write<0,1,2,3>(p, value);
200 : 4 : }
201 : 1 : extern inline void W64(void* p, std::uint_fast64_t value)
202 : : {
203 : 1 : if constexpr(LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
204 : 1 : *(uint_least64_t*)p = value;
205 : : else if constexpr(BIG_ENDIAN_AND_UNALIGNED_ACCESS_OK) //LCOV_EXCL_BR_LINE
206 : : *(uint_least64_t*)p = BSwap64(value);
207 : : else //LCOV_EXCL_BR_LINE
208 : : Write<0,1,2,3,4,5,6,7>(p, value);
209 : 1 : }
210 : :
211 : 8 : extern inline void Wn(void* p, std::uint_fast64_t value, unsigned bytes)
212 : : {
213 : 8 : unsigned char* data = (unsigned char*)p;
214 : 8 : switch(bytes) //LCOV_EXCL_BR_LINE
215 : : {
216 : 1 : case 8: W64(p, value); break;
217 : 1 : case 7: W8(data+6, value>>48); [[fallthrough]];
218 : 2 : case 6: W8(data+5, value>>40); [[fallthrough]];
219 : 3 : case 5: W8(data+4, value>>32); [[fallthrough]];
220 : 4 : case 4: W32(p, value); break;
221 : 1 : case 3: W24(p, value); break;
222 : 1 : case 2: W16(p, value); break;
223 : 1 : case 1: W8(p, value); break;
224 : : #ifdef __GNUC__
225 : 0 : default: __builtin_unreachable(); //LCOV_EXCL_BR_LINE
226 : : #endif
227 : : }
228 : 8 : }
229 : :
230 : : #endif
|