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
58QT_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
66template <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
79template <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*/
98template <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.
102template <> 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
115template <> 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
124template <> inline Q_DECL_CONSTEXPR quint16 qbswap<quint16>(quint16 source)
125{
126 return quint16( 0
127 | ((source & 0x00ff) << 8)
128 | ((source & 0xff00) >> 8) );
129}
130
131template <> inline Q_DECL_CONSTEXPR quint8 qbswap<quint8>(quint8 source)
132{
133 return source;
134}
135
136// signed specializations
137template <> inline Q_DECL_CONSTEXPR qint64 qbswap<qint64>(qint64 source)
138{
139 return qbswap<quint64>(quint64(source));
140}
141
142template <> inline Q_DECL_CONSTEXPR qint32 qbswap<qint32>(qint32 source)
143{
144 return qbswap<quint32>(quint32(source));
145}
146
147template <> inline Q_DECL_CONSTEXPR qint16 qbswap<qint16>(qint16 source)
148{
149 return qbswap<quint16>(quint16(source));
150}
151
152template <> inline Q_DECL_CONSTEXPR qint8 qbswap<qint8>(qint8 source)
153{
154 return source;
155}
156
157// floating specializations
158template<typename Float>
159Float 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
167inline qfloat16 qbswap(qfloat16 source)
168{
169 return qbswapFloatHelper(source);
170}
171
172inline float qbswap(float source)
173{
174 return qbswapFloatHelper(source);
175}
176
177inline 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*/
188template <typename T> inline void qbswap(const T src, void *dest)
189{
190 qToUnaligned<T>(qbswap(src), dest);
191}
192
193template <int Size> void *qbswap(const void *source, qsizetype count, void *dest) noexcept;
194template<> 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}
198template<> Q_CORE_EXPORT void *qbswap<2>(const void *source, qsizetype count, void *dest) noexcept;
199template<> Q_CORE_EXPORT void *qbswap<4>(const void *source, qsizetype count, void *dest) noexcept;
200template<> Q_CORE_EXPORT void *qbswap<8>(const void *source, qsizetype count, void *dest) noexcept;
201
202#if Q_BYTE_ORDER == Q_BIG_ENDIAN
203
204template <typename T> inline Q_DECL_CONSTEXPR T qToBigEndian(T source)
205{ return source; }
206template <typename T> inline Q_DECL_CONSTEXPR T qFromBigEndian(T source)
207{ return source; }
208template <typename T> inline Q_DECL_CONSTEXPR T qToLittleEndian(T source)
209{ return qbswap(source); }
210template <typename T> inline Q_DECL_CONSTEXPR T qFromLittleEndian(T source)
211{ return qbswap(source); }
212template <typename T> inline void qToBigEndian(T src, void *dest)
213{ qToUnaligned<T>(src, dest); }
214template <typename T> inline void qToLittleEndian(T src, void *dest)
215{ qbswap<T>(src, dest); }
216
217template <typename T> inline void qToBigEndian(const void *source, qsizetype count, void *dest)
218{ if (source != dest) memcpy(dest, source, count * sizeof(T)); }
219template <typename T> inline void qToLittleEndian(const void *source, qsizetype count, void *dest)
220{ qbswap<sizeof(T)>(source, count, dest); }
221template <typename T> inline void qFromBigEndian(const void *source, qsizetype count, void *dest)
222{ if (source != dest) memcpy(dest, source, count * sizeof(T)); }
223template <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
227template <typename T> inline Q_DECL_CONSTEXPR T qToBigEndian(T source)
228{ return qbswap(source); }
229template <typename T> inline Q_DECL_CONSTEXPR T qFromBigEndian(T source)
230{ return qbswap(source); }
231template <typename T> inline Q_DECL_CONSTEXPR T qToLittleEndian(T source)
232{ return source; }
233template <typename T> inline Q_DECL_CONSTEXPR T qFromLittleEndian(T source)
234{ return source; }
235template <typename T> inline void qToBigEndian(T src, void *dest)
236{ qbswap<T>(src, dest); }
237template <typename T> inline void qToLittleEndian(T src, void *dest)
238{ qToUnaligned<T>(src, dest); }
239
240template <typename T> inline void qToBigEndian(const void *source, qsizetype count, void *dest)
241{ qbswap<sizeof(T)>(source, count, dest); }
242template <typename T> inline void qToLittleEndian(const void *source, qsizetype count, void *dest)
243{ if (source != dest) memcpy(dest, source, count * sizeof(T)); }
244template <typename T> inline void qFromBigEndian(const void *source, qsizetype count, void *dest)
245{ qbswap<sizeof(T)>(source, count, dest); }
246template <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*/
256template <typename T> inline T qFromLittleEndian(const void *src)
257{
258 return qFromLittleEndian(qFromUnaligned<T>(src));
259}
260
261template <> inline quint8 qFromLittleEndian<quint8>(const void *src)
262{ return static_cast<const quint8 *>(src)[0]; }
263template <> 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*/
270template <class T> inline T qFromBigEndian(const void *src)
271{
272 return qFromBigEndian(qFromUnaligned<T>(src));
273}
274
275template <> inline quint8 qFromBigEndian<quint8>(const void *src)
276{ return static_cast<const quint8 *>(src)[0]; }
277template <> inline qint8 qFromBigEndian<qint8>(const void *src)
278{ return static_cast<const qint8 *>(src)[0]; }
279
280template<class S>
281class QSpecialInteger
282{
283 typedef typename S::StorageType T;
284 T val;
285public:
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
338template<typename T>
339class QLittleEndianStorageType {
340public:
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
346template<typename T>
347class QBigEndianStorageType {
348public:
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
355template<typename T>
356class QLEInteger {
357public:
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
382template<typename T>
383class QBEInteger {
384public:
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
410template<typename T>
411using QLEInteger = QSpecialInteger<QLittleEndianStorageType<T>>;
412
413template<typename T>
414using QBEInteger = QSpecialInteger<QBigEndianStorageType<T>>;
415#endif
416template <typename T>
417class QTypeInfo<QLEInteger<T> >
418 : public QTypeInfoMerger<QLEInteger<T>, T> {};
419
420template <typename T>
421class QTypeInfo<QBEInteger<T> >
422 : public QTypeInfoMerger<QBEInteger<T>, T> {};
423
424typedef QLEInteger<qint16> qint16_le;
425typedef QLEInteger<qint32> qint32_le;
426typedef QLEInteger<qint64> qint64_le;
427typedef QLEInteger<quint16> quint16_le;
428typedef QLEInteger<quint32> quint32_le;
429typedef QLEInteger<quint64> quint64_le;
430
431typedef QBEInteger<qint16> qint16_be;
432typedef QBEInteger<qint32> qint32_be;
433typedef QBEInteger<qint64> qint64_be;
434typedef QBEInteger<quint16> quint16_be;
435typedef QBEInteger<quint32> quint32_be;
436typedef QBEInteger<quint64> quint64_be;
437
438QT_END_NAMESPACE
439
440#endif // QENDIAN_H
441