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