1 /****************************************************************************
2 **
3 ** Copyright (C) 2021 The Qt Company Ltd.
4 ** Copyright (C) 2021 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
qToUnaligned(const T src,void * dest)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
qFromUnaligned(const void * src)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>(quint64(source));
140 }
141
142 template <> inline Q_DECL_CONSTEXPR qint32 qbswap<qint32>(qint32 source)
143 {
144 return qbswap<quint32>(quint32(source));
145 }
146
147 template <> inline Q_DECL_CONSTEXPR qint16 qbswap<qint16>(qint16 source)
148 {
149 return qbswap<quint16>(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>
qbswapFloatHelper(Float source)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
qbswap(qfloat16 source)167 inline qfloat16 qbswap(qfloat16 source)
168 {
169 return qbswapFloatHelper(source);
170 }
171
qbswap(float source)172 inline float qbswap(float source)
173 {
174 return qbswapFloatHelper(source);
175 }
176
qbswap(double source)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 */
qbswap(const T src,void * dest)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, source, 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
qToBigEndian(T source)204 template <typename T> inline Q_DECL_CONSTEXPR T qToBigEndian(T source)
205 { return source; }
qFromBigEndian(T source)206 template <typename T> inline Q_DECL_CONSTEXPR T qFromBigEndian(T source)
207 { return source; }
qToLittleEndian(T source)208 template <typename T> inline Q_DECL_CONSTEXPR T qToLittleEndian(T source)
209 { return qbswap(source); }
qFromLittleEndian(T source)210 template <typename T> inline Q_DECL_CONSTEXPR T qFromLittleEndian(T source)
211 { return qbswap(source); }
qToBigEndian(T src,void * dest)212 template <typename T> inline void qToBigEndian(T src, void *dest)
213 { qToUnaligned<T>(src, dest); }
qToLittleEndian(T src,void * dest)214 template <typename T> inline void qToLittleEndian(T src, void *dest)
215 { qbswap<T>(src, dest); }
216
qToBigEndian(const void * source,qsizetype count,void * dest)217 template <typename T> inline void qToBigEndian(const void *source, qsizetype count, void *dest)
218 { if (source != dest) memcpy(dest, source, count * sizeof(T)); }
qToLittleEndian(const void * source,qsizetype count,void * dest)219 template <typename T> inline void qToLittleEndian(const void *source, qsizetype count, void *dest)
220 { qbswap<sizeof(T)>(source, count, dest); }
qFromBigEndian(const void * source,qsizetype count,void * 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)); }
qFromLittleEndian(const void * source,qsizetype count,void * dest)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
qToBigEndian(T source)227 template <typename T> inline Q_DECL_CONSTEXPR T qToBigEndian(T source)
228 { return qbswap(source); }
qFromBigEndian(T source)229 template <typename T> inline Q_DECL_CONSTEXPR T qFromBigEndian(T source)
230 { return qbswap(source); }
qToLittleEndian(T source)231 template <typename T> inline Q_DECL_CONSTEXPR T qToLittleEndian(T source)
232 { return source; }
qFromLittleEndian(T source)233 template <typename T> inline Q_DECL_CONSTEXPR T qFromLittleEndian(T source)
234 { return source; }
qToBigEndian(T src,void * dest)235 template <typename T> inline void qToBigEndian(T src, void *dest)
236 { qbswap<T>(src, dest); }
qToLittleEndian(T src,void * dest)237 template <typename T> inline void qToLittleEndian(T src, void *dest)
238 { qToUnaligned<T>(src, dest); }
239
qToBigEndian(const void * source,qsizetype count,void * dest)240 template <typename T> inline void qToBigEndian(const void *source, qsizetype count, void *dest)
241 { qbswap<sizeof(T)>(source, count, dest); }
qToLittleEndian(const void * source,qsizetype count,void * dest)242 template <typename T> inline void qToLittleEndian(const void *source, qsizetype count, void *dest)
243 { if (source != dest) memcpy(dest, source, count * sizeof(T)); }
qFromBigEndian(const void * source,qsizetype count,void * dest)244 template <typename T> inline void qFromBigEndian(const void *source, qsizetype count, void *dest)
245 { qbswap<sizeof(T)>(source, count, dest); }
qFromLittleEndian(const void * source,qsizetype count,void * dest)246 template <typename T> inline void qFromLittleEndian(const void *source, qsizetype count, void *dest)
247 { if (source != dest) memcpy(dest, source, 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 */
qFromLittleEndian(const void * src)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 */
qFromBigEndian(const void * src)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;
QSpecialInteger(T i)287 explicit Q_DECL_CONSTEXPR QSpecialInteger(T i) : val(S::toSpecial(i)) {}
288
289 QSpecialInteger &operator =(T i) { val = S::toSpecial(i); return *this; }
T()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
max()332 static Q_DECL_CONSTEXPR QSpecialInteger max()
333 { return QSpecialInteger(std::numeric_limits<T>::max()); }
min()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;
toSpecial(T source)342 static Q_DECL_CONSTEXPR T toSpecial(T source) { return qToLittleEndian(source); }
fromSpecial(T 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;
toSpecial(T source)350 static Q_DECL_CONSTEXPR T toSpecial(T source) { return qToBigEndian(source); }
fromSpecial(T 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