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