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