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