1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Copyright (C) 2016 Intel Corporation. |
5 | ** Contact: https://www.qt.io/licensing/ |
6 | ** |
7 | ** This file is part of the QtCore module of the Qt Toolkit. |
8 | ** |
9 | ** $QT_BEGIN_LICENSE:LGPL$ |
10 | ** Commercial License Usage |
11 | ** Licensees holding valid commercial Qt licenses may use this file in |
12 | ** accordance with the commercial license agreement provided with the |
13 | ** Software or, alternatively, in accordance with the terms contained in |
14 | ** a written agreement between you and The Qt Company. For licensing terms |
15 | ** and conditions see https://www.qt.io/terms-conditions. For further |
16 | ** information use the contact form at https://www.qt.io/contact-us. |
17 | ** |
18 | ** GNU Lesser General Public License Usage |
19 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
20 | ** General Public License version 3 as published by the Free Software |
21 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
22 | ** packaging of this file. Please review the following information to |
23 | ** ensure the GNU Lesser General Public License version 3 requirements |
24 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
25 | ** |
26 | ** GNU General Public License Usage |
27 | ** Alternatively, this file may be used under the terms of the GNU |
28 | ** General Public License version 2.0 or (at your option) the GNU General |
29 | ** Public license version 3 or any later version approved by the KDE Free |
30 | ** Qt Foundation. The licenses are as published by the Free Software |
31 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
32 | ** included in the packaging of this file. Please review the following |
33 | ** information to ensure the GNU General Public License requirements will |
34 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
35 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
36 | ** |
37 | ** $QT_END_LICENSE$ |
38 | ** |
39 | ****************************************************************************/ |
40 | |
41 | #ifndef QENDIAN_H |
42 | #define QENDIAN_H |
43 | |
44 | #include <QtCore/qfloat16.h> |
45 | #include <QtCore/qglobal.h> |
46 | |
47 | // include stdlib.h and hope that it defines __GLIBC__ for glibc-based systems |
48 | #include <stdlib.h> |
49 | #include <string.h> |
50 | |
51 | #ifdef min // MSVC |
52 | #undef min |
53 | #undef max |
54 | #endif |
55 | |
56 | QT_BEGIN_NAMESPACE |
57 | |
58 | /* |
59 | * ENDIAN FUNCTIONS |
60 | */ |
61 | |
62 | // Used to implement a type-safe and alignment-safe copy operation |
63 | // If you want to avoid the memcpy, you must write specializations for these functions |
64 | template <typename T> Q_ALWAYS_INLINE void qToUnaligned(const T src, void *dest) |
65 | { |
66 | // Using sizeof(T) inside memcpy function produces internal compiler error with |
67 | // MSVC2008/ARM in tst_endian -> use extra indirection to resolve size of T. |
68 | const size_t size = sizeof(T); |
69 | #if __has_builtin(__builtin_memcpy) |
70 | __builtin_memcpy |
71 | #else |
72 | memcpy |
73 | #endif |
74 | (dest, &src, size); |
75 | } |
76 | |
77 | template <typename T> Q_ALWAYS_INLINE T qFromUnaligned(const void *src) |
78 | { |
79 | T dest; |
80 | const size_t size = sizeof(T); |
81 | #if __has_builtin(__builtin_memcpy) |
82 | __builtin_memcpy |
83 | #else |
84 | memcpy |
85 | #endif |
86 | (&dest, src, size); |
87 | return dest; |
88 | } |
89 | |
90 | // These definitions are written so that they are recognized by most compilers |
91 | // as bswap and replaced with single instruction builtins if available. |
92 | inline constexpr quint64 qbswap_helper(quint64 source) |
93 | { |
94 | return 0 |
95 | | ((source & Q_UINT64_C(0x00000000000000ff)) << 56) |
96 | | ((source & Q_UINT64_C(0x000000000000ff00)) << 40) |
97 | | ((source & Q_UINT64_C(0x0000000000ff0000)) << 24) |
98 | | ((source & Q_UINT64_C(0x00000000ff000000)) << 8) |
99 | | ((source & Q_UINT64_C(0x000000ff00000000)) >> 8) |
100 | | ((source & Q_UINT64_C(0x0000ff0000000000)) >> 24) |
101 | | ((source & Q_UINT64_C(0x00ff000000000000)) >> 40) |
102 | | ((source & Q_UINT64_C(0xff00000000000000)) >> 56); |
103 | } |
104 | |
105 | inline constexpr quint32 qbswap_helper(quint32 source) |
106 | { |
107 | return 0 |
108 | | ((source & 0x000000ff) << 24) |
109 | | ((source & 0x0000ff00) << 8) |
110 | | ((source & 0x00ff0000) >> 8) |
111 | | ((source & 0xff000000) >> 24); |
112 | } |
113 | |
114 | inline constexpr quint16 qbswap_helper(quint16 source) |
115 | { |
116 | return quint16( 0 |
117 | | ((source & 0x00ff) << 8) |
118 | | ((source & 0xff00) >> 8) ); |
119 | } |
120 | |
121 | inline constexpr quint8 qbswap_helper(quint8 source) |
122 | { |
123 | return source; |
124 | } |
125 | |
126 | /* |
127 | * T qbswap(T source). |
128 | * Changes the byte order of a value from big endian to little endian or vice versa. |
129 | * This function can be used if you are not concerned about alignment issues, |
130 | * and it is therefore a bit more convenient and in most cases more efficient. |
131 | */ |
132 | template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>> |
133 | inline constexpr T qbswap(T source) |
134 | { |
135 | return T(qbswap_helper(typename QIntegerForSizeof<T>::Unsigned(source))); |
136 | } |
137 | |
138 | // floating specializations |
139 | template<typename Float> |
140 | Float qbswapFloatHelper(Float source) |
141 | { |
142 | // memcpy call in qFromUnaligned is recognized by optimizer as a correct way of type prunning |
143 | auto temp = qFromUnaligned<typename QIntegerForSizeof<Float>::Unsigned>(&source); |
144 | temp = qbswap(temp); |
145 | return qFromUnaligned<Float>(&temp); |
146 | } |
147 | |
148 | inline qfloat16 qbswap(qfloat16 source) |
149 | { |
150 | return qbswapFloatHelper(source); |
151 | } |
152 | |
153 | inline float qbswap(float source) |
154 | { |
155 | return qbswapFloatHelper(source); |
156 | } |
157 | |
158 | inline double qbswap(double source) |
159 | { |
160 | return qbswapFloatHelper(source); |
161 | } |
162 | |
163 | /* |
164 | * qbswap(const T src, const void *dest); |
165 | * Changes the byte order of \a src from big endian to little endian or vice versa |
166 | * and stores the result in \a dest. |
167 | * There is no alignment requirements for \a dest. |
168 | */ |
169 | template <typename T> inline void qbswap(const T src, void *dest) |
170 | { |
171 | qToUnaligned<T>(qbswap(src), dest); |
172 | } |
173 | |
174 | template <int Size> void *qbswap(const void *source, qsizetype count, void *dest) noexcept; |
175 | template<> inline void *qbswap<1>(const void *source, qsizetype count, void *dest) noexcept |
176 | { |
177 | return source != dest ? memcpy(dest, source, size_t(count)) : dest; |
178 | } |
179 | template<> Q_CORE_EXPORT void *qbswap<2>(const void *source, qsizetype count, void *dest) noexcept; |
180 | template<> Q_CORE_EXPORT void *qbswap<4>(const void *source, qsizetype count, void *dest) noexcept; |
181 | template<> Q_CORE_EXPORT void *qbswap<8>(const void *source, qsizetype count, void *dest) noexcept; |
182 | |
183 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
184 | |
185 | template <typename T> inline constexpr T qToBigEndian(T source) |
186 | { return source; } |
187 | template <typename T> inline constexpr T qFromBigEndian(T source) |
188 | { return source; } |
189 | template <typename T> inline constexpr T qToLittleEndian(T source) |
190 | { return qbswap(source); } |
191 | template <typename T> inline constexpr T qFromLittleEndian(T source) |
192 | { return qbswap(source); } |
193 | template <typename T> inline void qToBigEndian(T src, void *dest) |
194 | { qToUnaligned<T>(src, dest); } |
195 | template <typename T> inline void qToLittleEndian(T src, void *dest) |
196 | { qbswap<T>(src, dest); } |
197 | |
198 | template <typename T> inline void qToBigEndian(const void *source, qsizetype count, void *dest) |
199 | { if (source != dest) memcpy(dest, source, count * sizeof(T)); } |
200 | template <typename T> inline void qToLittleEndian(const void *source, qsizetype count, void *dest) |
201 | { qbswap<sizeof(T)>(source, count, dest); } |
202 | template <typename T> inline void qFromBigEndian(const void *source, qsizetype count, void *dest) |
203 | { if (source != dest) memcpy(dest, source, count * sizeof(T)); } |
204 | template <typename T> inline void qFromLittleEndian(const void *source, qsizetype count, void *dest) |
205 | { qbswap<sizeof(T)>(source, count, dest); } |
206 | #else // Q_LITTLE_ENDIAN |
207 | |
208 | template <typename T> inline constexpr T qToBigEndian(T source) |
209 | { return qbswap(source); } |
210 | template <typename T> inline constexpr T qFromBigEndian(T source) |
211 | { return qbswap(source); } |
212 | template <typename T> inline constexpr T qToLittleEndian(T source) |
213 | { return source; } |
214 | template <typename T> inline constexpr T qFromLittleEndian(T source) |
215 | { return source; } |
216 | template <typename T> inline void qToBigEndian(T src, void *dest) |
217 | { qbswap<T>(src, dest); } |
218 | template <typename T> inline void qToLittleEndian(T src, void *dest) |
219 | { qToUnaligned<T>(src, dest); } |
220 | |
221 | template <typename T> inline void qToBigEndian(const void *source, qsizetype count, void *dest) |
222 | { qbswap<sizeof(T)>(source, count, dest); } |
223 | template <typename T> inline void qToLittleEndian(const void *source, qsizetype count, void *dest) |
224 | { if (source != dest) memcpy(dest, source, count * sizeof(T)); } |
225 | template <typename T> inline void qFromBigEndian(const void *source, qsizetype count, void *dest) |
226 | { qbswap<sizeof(T)>(source, count, dest); } |
227 | template <typename T> inline void qFromLittleEndian(const void *source, qsizetype count, void *dest) |
228 | { if (source != dest) memcpy(dest, source, count * sizeof(T)); } |
229 | #endif // Q_BYTE_ORDER == Q_BIG_ENDIAN |
230 | |
231 | |
232 | /* T qFromLittleEndian(const void *src) |
233 | * This function will read a little-endian encoded value from \a src |
234 | * and return the value in host-endian encoding. |
235 | * There is no requirement that \a src must be aligned. |
236 | */ |
237 | template <typename T> inline T qFromLittleEndian(const void *src) |
238 | { |
239 | return qFromLittleEndian(qFromUnaligned<T>(src)); |
240 | } |
241 | |
242 | template <> inline quint8 qFromLittleEndian<quint8>(const void *src) |
243 | { return static_cast<const quint8 *>(src)[0]; } |
244 | template <> inline qint8 qFromLittleEndian<qint8>(const void *src) |
245 | { return static_cast<const qint8 *>(src)[0]; } |
246 | |
247 | /* This function will read a big-endian (also known as network order) encoded value from \a src |
248 | * and return the value in host-endian encoding. |
249 | * There is no requirement that \a src must be aligned. |
250 | */ |
251 | template <class T> inline T qFromBigEndian(const void *src) |
252 | { |
253 | return qFromBigEndian(qFromUnaligned<T>(src)); |
254 | } |
255 | |
256 | template <> inline quint8 qFromBigEndian<quint8>(const void *src) |
257 | { return static_cast<const quint8 *>(src)[0]; } |
258 | template <> inline qint8 qFromBigEndian<qint8>(const void *src) |
259 | { return static_cast<const qint8 *>(src)[0]; } |
260 | |
261 | template<class S> |
262 | class QSpecialInteger |
263 | { |
264 | typedef typename S::StorageType T; |
265 | T val; |
266 | public: |
267 | QSpecialInteger() = default; |
268 | explicit constexpr QSpecialInteger(T i) : val(S::toSpecial(i)) {} |
269 | |
270 | QSpecialInteger &operator =(T i) { val = S::toSpecial(i); return *this; } |
271 | operator T() const { return S::fromSpecial(val); } |
272 | |
273 | bool operator ==(QSpecialInteger<S> i) const { return val == i.val; } |
274 | bool operator !=(QSpecialInteger<S> i) const { return val != i.val; } |
275 | |
276 | QSpecialInteger &operator +=(T i) |
277 | { return (*this = S::fromSpecial(val) + i); } |
278 | QSpecialInteger &operator -=(T i) |
279 | { return (*this = S::fromSpecial(val) - i); } |
280 | QSpecialInteger &operator *=(T i) |
281 | { return (*this = S::fromSpecial(val) * i); } |
282 | QSpecialInteger &operator >>=(T i) |
283 | { return (*this = S::fromSpecial(val) >> i); } |
284 | QSpecialInteger &operator <<=(T i) |
285 | { return (*this = S::fromSpecial(val) << i); } |
286 | QSpecialInteger &operator /=(T i) |
287 | { return (*this = S::fromSpecial(val) / i); } |
288 | QSpecialInteger &operator %=(T i) |
289 | { return (*this = S::fromSpecial(val) % i); } |
290 | QSpecialInteger &operator |=(T i) |
291 | { return (*this = S::fromSpecial(val) | i); } |
292 | QSpecialInteger &operator &=(T i) |
293 | { return (*this = S::fromSpecial(val) & i); } |
294 | QSpecialInteger &operator ^=(T i) |
295 | { return (*this = S::fromSpecial(val) ^ i); } |
296 | QSpecialInteger &operator ++() |
297 | { return (*this = S::fromSpecial(val) + 1); } |
298 | QSpecialInteger &operator --() |
299 | { return (*this = S::fromSpecial(val) - 1); } |
300 | QSpecialInteger operator ++(int) |
301 | { |
302 | QSpecialInteger<S> pre = *this; |
303 | *this += 1; |
304 | return pre; |
305 | } |
306 | QSpecialInteger operator --(int) |
307 | { |
308 | QSpecialInteger<S> pre = *this; |
309 | *this -= 1; |
310 | return pre; |
311 | } |
312 | |
313 | static constexpr QSpecialInteger max() |
314 | { return QSpecialInteger(std::numeric_limits<T>::max()); } |
315 | static constexpr QSpecialInteger min() |
316 | { return QSpecialInteger(std::numeric_limits<T>::min()); } |
317 | }; |
318 | |
319 | template<typename T> |
320 | class QLittleEndianStorageType { |
321 | public: |
322 | typedef T StorageType; |
323 | static constexpr T toSpecial(T source) { return qToLittleEndian(source); } |
324 | static constexpr T fromSpecial(T source) { return qFromLittleEndian(source); } |
325 | }; |
326 | |
327 | template<typename T> |
328 | class QBigEndianStorageType { |
329 | public: |
330 | typedef T StorageType; |
331 | static constexpr T toSpecial(T source) { return qToBigEndian(source); } |
332 | static constexpr T fromSpecial(T source) { return qFromBigEndian(source); } |
333 | }; |
334 | |
335 | #ifdef Q_CLANG_QDOC |
336 | template<typename T> |
337 | class QLEInteger { |
338 | public: |
339 | explicit constexpr QLEInteger(T i); |
340 | QLEInteger &operator =(T i); |
341 | operator T() const; |
342 | bool operator ==(QLEInteger i) const; |
343 | bool operator !=(QLEInteger i) const; |
344 | QLEInteger &operator +=(T i); |
345 | QLEInteger &operator -=(T i); |
346 | QLEInteger &operator *=(T i); |
347 | QLEInteger &operator >>=(T i); |
348 | QLEInteger &operator <<=(T i); |
349 | QLEInteger &operator /=(T i); |
350 | QLEInteger &operator %=(T i); |
351 | QLEInteger &operator |=(T i); |
352 | QLEInteger &operator &=(T i); |
353 | QLEInteger &operator ^=(T i); |
354 | QLEInteger &operator ++(); |
355 | QLEInteger &operator --(); |
356 | QLEInteger &operator ++(int); |
357 | QLEInteger &operator --(int); |
358 | |
359 | static constexpr QLEInteger max(); |
360 | static constexpr QLEInteger min(); |
361 | }; |
362 | |
363 | template<typename T> |
364 | class QBEInteger { |
365 | public: |
366 | explicit constexpr QBEInteger(T i); |
367 | QBEInteger &operator =(T i); |
368 | operator T() const; |
369 | bool operator ==(QBEInteger i) const; |
370 | bool operator !=(QBEInteger i) const; |
371 | QBEInteger &operator +=(T i); |
372 | QBEInteger &operator -=(T i); |
373 | QBEInteger &operator *=(T i); |
374 | QBEInteger &operator >>=(T i); |
375 | QBEInteger &operator <<=(T i); |
376 | QBEInteger &operator /=(T i); |
377 | QBEInteger &operator %=(T i); |
378 | QBEInteger &operator |=(T i); |
379 | QBEInteger &operator &=(T i); |
380 | QBEInteger &operator ^=(T i); |
381 | QBEInteger &operator ++(); |
382 | QBEInteger &operator --(); |
383 | QBEInteger &operator ++(int); |
384 | QBEInteger &operator --(int); |
385 | |
386 | static constexpr QBEInteger max(); |
387 | static constexpr QBEInteger min(); |
388 | }; |
389 | #else |
390 | |
391 | template<typename T> |
392 | using QLEInteger = QSpecialInteger<QLittleEndianStorageType<T>>; |
393 | |
394 | template<typename T> |
395 | using QBEInteger = QSpecialInteger<QBigEndianStorageType<T>>; |
396 | #endif |
397 | template <typename T> |
398 | class QTypeInfo<QLEInteger<T> > |
399 | : public QTypeInfoMerger<QLEInteger<T>, T> {}; |
400 | |
401 | template <typename T> |
402 | class QTypeInfo<QBEInteger<T> > |
403 | : public QTypeInfoMerger<QBEInteger<T>, T> {}; |
404 | |
405 | typedef QLEInteger<qint16> qint16_le; |
406 | typedef QLEInteger<qint32> qint32_le; |
407 | typedef QLEInteger<qint64> qint64_le; |
408 | typedef QLEInteger<quint16> quint16_le; |
409 | typedef QLEInteger<quint32> quint32_le; |
410 | typedef QLEInteger<quint64> quint64_le; |
411 | |
412 | typedef QBEInteger<qint16> qint16_be; |
413 | typedef QBEInteger<qint32> qint32_be; |
414 | typedef QBEInteger<qint64> qint64_be; |
415 | typedef QBEInteger<quint16> quint16_be; |
416 | typedef QBEInteger<quint32> quint32_be; |
417 | typedef QBEInteger<quint64> quint64_be; |
418 | |
419 | QT_END_NAMESPACE |
420 | |
421 | #endif // QENDIAN_H |
422 | |