Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qendian.h
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2021 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6#ifndef QENDIAN_H
7#define QENDIAN_H
8
9#if 0
10#pragma qt_class(QtEndian)
11#endif
12
13#include <QtCore/qfloat16.h>
14#include <QtCore/qglobal.h>
15
16#include <limits>
17
18// include stdlib.h and hope that it defines __GLIBC__ for glibc-based systems
19#include <stdlib.h>
20#include <string.h>
21
22#ifdef min // MSVC
23#undef min
24#undef max
25#endif
26
27QT_BEGIN_NAMESPACE
28
29/*
30 * ENDIAN FUNCTIONS
31*/
32
33// Used to implement a type-safe and alignment-safe copy operation
34// If you want to avoid the memcpy, you must write specializations for these functions
35template <typename T> Q_ALWAYS_INLINE void qToUnaligned(const T src, void *dest)
36{
37 // Using sizeof(T) inside memcpy function produces internal compiler error with
38 // MSVC2008/ARM in tst_endian -> use extra indirection to resolve size of T.
39 const size_t size = sizeof(T);
40#if __has_builtin(__builtin_memcpy)
41 __builtin_memcpy
42#else
43 memcpy
44#endif
45 (dest, &src, size);
46}
47
48template <typename T> Q_ALWAYS_INLINE T qFromUnaligned(const void *src)
49{
50 T dest;
51 const size_t size = sizeof(T);
52#if __has_builtin(__builtin_memcpy)
53 __builtin_memcpy
54#else
55 memcpy
56#endif
57 (&dest, src, size);
58 return dest;
59}
60
61// These definitions are written so that they are recognized by most compilers
62// as bswap and replaced with single instruction builtins if available.
63inline constexpr quint64 qbswap_helper(quint64 source)
64{
65 return 0
66 | ((source & Q_UINT64_C(0x00000000000000ff)) << 56)
67 | ((source & Q_UINT64_C(0x000000000000ff00)) << 40)
68 | ((source & Q_UINT64_C(0x0000000000ff0000)) << 24)
69 | ((source & Q_UINT64_C(0x00000000ff000000)) << 8)
70 | ((source & Q_UINT64_C(0x000000ff00000000)) >> 8)
71 | ((source & Q_UINT64_C(0x0000ff0000000000)) >> 24)
72 | ((source & Q_UINT64_C(0x00ff000000000000)) >> 40)
73 | ((source & Q_UINT64_C(0xff00000000000000)) >> 56);
74}
75
76inline constexpr quint32 qbswap_helper(quint32 source)
77{
78 return 0
79 | ((source & 0x000000ff) << 24)
80 | ((source & 0x0000ff00) << 8)
81 | ((source & 0x00ff0000) >> 8)
82 | ((source & 0xff000000) >> 24);
83}
84
85inline constexpr quint16 qbswap_helper(quint16 source)
86{
87 return quint16( 0
88 | ((source & 0x00ff) << 8)
89 | ((source & 0xff00) >> 8) );
90}
91
92inline constexpr quint8 qbswap_helper(quint8 source)
93{
94 return source;
95}
96
97/*
98 * T qbswap(T source).
99 * Changes the byte order of a value from big-endian to little-endian or vice versa.
100 * This function can be used if you are not concerned about alignment issues,
101 * and it is therefore a bit more convenient and in most cases more efficient.
102*/
103template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
104inline constexpr T qbswap(T source)
105{
106 return T(qbswap_helper(typename QIntegerForSizeof<T>::Unsigned(source)));
107}
108
109#ifdef QT_SUPPORTS_INT128
110// extra definitions for q(u)int128, in case std::is_integral_v<~~> == false
111inline constexpr quint128 qbswap(quint128 source)
112{
113 quint128 result = {};
114 result = qbswap_helper(quint64(source));
115 result <<= 64;
116 result |= qbswap_helper(quint64(source >> 64));
117 return result;
118}
119
120inline constexpr qint128 qbswap(qint128 source)
121{
122 return qint128(qbswap(quint128(source)));
123}
124#endif
125
126// floating specializations
127template<typename Float>
128Float qbswapFloatHelper(Float source)
129{
130 // memcpy call in qFromUnaligned is recognized by optimizer as a correct way of type prunning
131 auto temp = qFromUnaligned<typename QIntegerForSizeof<Float>::Unsigned>(&source);
132 temp = qbswap(temp);
133 return qFromUnaligned<Float>(&temp);
134}
135
136inline qfloat16 qbswap(qfloat16 source)
137{
138 return qbswapFloatHelper(source);
139}
140
141inline float qbswap(float source)
142{
143 return qbswapFloatHelper(source);
144}
145
146inline double qbswap(double source)
147{
148 return qbswapFloatHelper(source);
149}
150
151/*
152 * qbswap(const T src, const void *dest);
153 * Changes the byte order of \a src from big-endian to little-endian or vice versa
154 * and stores the result in \a dest.
155 * There is no alignment requirements for \a dest.
156*/
157template <typename T> inline void qbswap(const T src, void *dest)
158{
159 qToUnaligned<T>(qbswap(src), dest);
160}
161
162template <int Size> void *qbswap(const void *source, qsizetype count, void *dest) noexcept;
163template<> inline void *qbswap<1>(const void *source, qsizetype count, void *dest) noexcept
164{
165 return source != dest ? memcpy(dest, source, size_t(count)) : dest;
166}
167template<> Q_CORE_EXPORT void *qbswap<2>(const void *source, qsizetype count, void *dest) noexcept;
168template<> Q_CORE_EXPORT void *qbswap<4>(const void *source, qsizetype count, void *dest) noexcept;
169template<> Q_CORE_EXPORT void *qbswap<8>(const void *source, qsizetype count, void *dest) noexcept;
170
171#if Q_BYTE_ORDER == Q_BIG_ENDIAN
172
173template <typename T> inline constexpr T qToBigEndian(T source)
174{ return source; }
175template <typename T> inline constexpr T qFromBigEndian(T source)
176{ return source; }
177template <typename T> inline constexpr T qToLittleEndian(T source)
178{ return qbswap(source); }
179template <typename T> inline constexpr T qFromLittleEndian(T source)
180{ return qbswap(source); }
181template <typename T> inline void qToBigEndian(T src, void *dest)
182{ qToUnaligned<T>(src, dest); }
183template <typename T> inline void qToLittleEndian(T src, void *dest)
184{ qbswap<T>(src, dest); }
185
186template <typename T> inline void qToBigEndian(const void *source, qsizetype count, void *dest)
187{ if (source != dest) memcpy(dest, source, count * sizeof(T)); }
188template <typename T> inline void qToLittleEndian(const void *source, qsizetype count, void *dest)
189{ qbswap<sizeof(T)>(source, count, dest); }
190template <typename T> inline void qFromBigEndian(const void *source, qsizetype count, void *dest)
191{ if (source != dest) memcpy(dest, source, count * sizeof(T)); }
192template <typename T> inline void qFromLittleEndian(const void *source, qsizetype count, void *dest)
193{ qbswap<sizeof(T)>(source, count, dest); }
194#else // Q_LITTLE_ENDIAN
195
196template <typename T> inline constexpr T qToBigEndian(T source)
197{ return qbswap(source); }
198template <typename T> inline constexpr T qFromBigEndian(T source)
199{ return qbswap(source); }
200template <typename T> inline constexpr T qToLittleEndian(T source)
201{ return source; }
202template <typename T> inline constexpr T qFromLittleEndian(T source)
203{ return source; }
204template <typename T> inline void qToBigEndian(T src, void *dest)
205{ qbswap<T>(src, dest); }
206template <typename T> inline void qToLittleEndian(T src, void *dest)
207{ qToUnaligned<T>(src, dest); }
208
209template <typename T> inline void qToBigEndian(const void *source, qsizetype count, void *dest)
210{ qbswap<sizeof(T)>(source, count, dest); }
211template <typename T> inline void qToLittleEndian(const void *source, qsizetype count, void *dest)
212{ if (source != dest) memcpy(dest, source, count * sizeof(T)); }
213template <typename T> inline void qFromBigEndian(const void *source, qsizetype count, void *dest)
214{ qbswap<sizeof(T)>(source, count, dest); }
215template <typename T> inline void qFromLittleEndian(const void *source, qsizetype count, void *dest)
216{ if (source != dest) memcpy(dest, source, count * sizeof(T)); }
217#endif // Q_BYTE_ORDER == Q_BIG_ENDIAN
218
219
220/* T qFromLittleEndian(const void *src)
221 * This function will read a little-endian encoded value from \a src
222 * and return the value in host-endian encoding.
223 * There is no requirement that \a src must be aligned.
224*/
225template <typename T> inline T qFromLittleEndian(const void *src)
226{
227 return qFromLittleEndian(qFromUnaligned<T>(src));
228}
229
230template <> inline quint8 qFromLittleEndian<quint8>(const void *src)
231{ return static_cast<const quint8 *>(src)[0]; }
232template <> inline qint8 qFromLittleEndian<qint8>(const void *src)
233{ return static_cast<const qint8 *>(src)[0]; }
234
235/* This function will read a big-endian (also known as network order) encoded value from \a src
236 * and return the value in host-endian encoding.
237 * There is no requirement that \a src must be aligned.
238*/
239template <class T> inline T qFromBigEndian(const void *src)
240{
241 return qFromBigEndian(qFromUnaligned<T>(src));
242}
243
244template <> inline quint8 qFromBigEndian<quint8>(const void *src)
245{ return static_cast<const quint8 *>(src)[0]; }
246template <> inline qint8 qFromBigEndian<qint8>(const void *src)
247{ return static_cast<const qint8 *>(src)[0]; }
248
249template<class S>
251{
252 typedef typename S::StorageType T;
253 T val;
254public:
255 QSpecialInteger() = default;
256 explicit constexpr QSpecialInteger(T i) : val(S::toSpecial(i)) {}
257
258 QSpecialInteger &operator =(T i) { val = S::toSpecial(i); return *this; }
259 operator T() const { return S::fromSpecial(val); }
260
261 bool operator ==(QSpecialInteger<S> i) const { return val == i.val; }
262 bool operator !=(QSpecialInteger<S> i) const { return val != i.val; }
263
265 { return (*this = S::fromSpecial(val) + i); }
267 { return (*this = S::fromSpecial(val) - i); }
269 { return (*this = S::fromSpecial(val) * i); }
271 { return (*this = S::fromSpecial(val) >> i); }
272 QSpecialInteger &operator <<=(T i)
273 { return (*this = S::fromSpecial(val) << i); }
275 { return (*this = S::fromSpecial(val) / i); }
277 { return (*this = S::fromSpecial(val) % i); }
279 { return (*this = S::fromSpecial(val) | i); }
281 { return (*this = S::fromSpecial(val) & i); }
283 { return (*this = S::fromSpecial(val) ^ i); }
285 { return (*this = S::fromSpecial(val) + 1); }
287 { return (*this = S::fromSpecial(val) - 1); }
289 {
290 QSpecialInteger<S> pre = *this;
291 *this += 1;
292 return pre;
293 }
295 {
296 QSpecialInteger<S> pre = *this;
297 *this -= 1;
298 return pre;
299 }
300
301 static constexpr QSpecialInteger max()
302 { return QSpecialInteger((std::numeric_limits<T>::max)()); }
303 static constexpr QSpecialInteger min()
304 { return QSpecialInteger((std::numeric_limits<T>::min)()); }
305};
306
307template<typename T>
309public:
310 typedef T StorageType;
311 static constexpr T toSpecial(T source) { return qToLittleEndian(source); }
312 static constexpr T fromSpecial(T source) { return qFromLittleEndian(source); }
313};
314
315template<typename T>
317public:
318 typedef T StorageType;
319 static constexpr T toSpecial(T source) { return qToBigEndian(source); }
320 static constexpr T fromSpecial(T source) { return qFromBigEndian(source); }
321};
322
323#ifdef Q_QDOC
324template<typename T>
325class QLEInteger {
326public:
327 explicit constexpr QLEInteger(T i);
328 QLEInteger &operator =(T i);
329 operator T() const;
330 bool operator ==(QLEInteger i) const;
331 bool operator !=(QLEInteger i) const;
332 QLEInteger &operator +=(T i);
333 QLEInteger &operator -=(T i);
334 QLEInteger &operator *=(T i);
335 QLEInteger &operator >>=(T i);
336 QLEInteger &operator <<=(T i);
337 QLEInteger &operator /=(T i);
338 QLEInteger &operator %=(T i);
339 QLEInteger &operator |=(T i);
340 QLEInteger &operator &=(T i);
341 QLEInteger &operator ^=(T i);
342 QLEInteger &operator ++();
343 QLEInteger &operator --();
344 QLEInteger operator ++(int);
345 QLEInteger operator --(int);
346
347 static constexpr QLEInteger max();
348 static constexpr QLEInteger min();
349};
350
351template<typename T>
352class QBEInteger {
353public:
354 explicit constexpr QBEInteger(T i);
355 QBEInteger &operator =(T i);
356 operator T() const;
357 bool operator ==(QBEInteger i) const;
358 bool operator !=(QBEInteger i) const;
359 QBEInteger &operator +=(T i);
360 QBEInteger &operator -=(T i);
361 QBEInteger &operator *=(T i);
362 QBEInteger &operator >>=(T i);
363 QBEInteger &operator <<=(T i);
364 QBEInteger &operator /=(T i);
365 QBEInteger &operator %=(T i);
366 QBEInteger &operator |=(T i);
367 QBEInteger &operator &=(T i);
368 QBEInteger &operator ^=(T i);
369 QBEInteger &operator ++();
370 QBEInteger &operator --();
371 QBEInteger operator ++(int);
372 QBEInteger operator --(int);
373
374 static constexpr QBEInteger max();
375 static constexpr QBEInteger min();
376};
377#else
378
379template<typename T>
381
382template<typename T>
384#endif
385template <typename T>
387 : public QTypeInfoMerger<QLEInteger<T>, T> {};
388
389template <typename T>
390class QTypeInfo<QBEInteger<T> >
391 : public QTypeInfoMerger<QBEInteger<T>, T> {};
392
399
406
407QT_END_NAMESPACE
408
409#endif // QENDIAN_H
static constexpr T fromSpecial(T source)
Definition qendian.h:320
static constexpr T toSpecial(T source)
Definition qendian.h:319
static constexpr T fromSpecial(T source)
Definition qendian.h:312
static constexpr T toSpecial(T source)
Definition qendian.h:311
bool operator!=(QSpecialInteger< S > i) const
Definition qendian.h:262
static constexpr QSpecialInteger max()
Definition qendian.h:301
QSpecialInteger & operator>>=(T i)
Definition qendian.h:270
constexpr QSpecialInteger(T i)
Definition qendian.h:256
QSpecialInteger & operator++()
Definition qendian.h:284
bool operator==(QSpecialInteger< S > i) const
Definition qendian.h:261
QSpecialInteger & operator=(T i)
Definition qendian.h:258
operator T() const
Definition qendian.h:259
QSpecialInteger operator++(int)
Definition qendian.h:288
QSpecialInteger & operator&=(T i)
Definition qendian.h:280
QSpecialInteger & operator+=(T i)
Definition qendian.h:264
QSpecialInteger & operator|=(T i)
Definition qendian.h:278
QSpecialInteger & operator--()
Definition qendian.h:286
QSpecialInteger & operator*=(T i)
Definition qendian.h:268
QSpecialInteger operator--(int)
Definition qendian.h:294
QSpecialInteger & operator^=(T i)
Definition qendian.h:282
QSpecialInteger()=default
QSpecialInteger & operator%=(T i)
Definition qendian.h:276
QSpecialInteger & operator/=(T i)
Definition qendian.h:274
static constexpr QSpecialInteger min()
Definition qendian.h:303
QSpecialInteger & operator-=(T i)
Definition qendian.h:266
Combined button and popup list for selecting options.
#define __has_builtin(x)
static Q_ALWAYS_INLINE void * bswapLoop(const uchar *src, size_t n, uchar *dst) noexcept
Definition qendian.cpp:844
void * qbswap< 2 >(const void *source, qsizetype n, void *dest) noexcept
Definition qendian.cpp:865
QBEInteger< quint64 > quint64_be
Definition qendian.h:405
float qbswap(float source)
Definition qendian.h:141
void qToLittleEndian(T src, void *dest)
Definition qendian.h:183
void qToLittleEndian(const void *source, qsizetype count, void *dest)
Definition qendian.h:188
QLEInteger< qint64 > qint64_le
Definition qendian.h:395
void qToBigEndian(T src, void *dest)
Definition qendian.h:181
QBEInteger< qint32 > qint32_be
Definition qendian.h:401
QLEInteger< qint32 > qint32_le
Definition qendian.h:394
void qFromLittleEndian(const void *source, qsizetype count, void *dest)
Definition qendian.h:192
void qbswap(const T src, void *dest)
Definition qendian.h:157
QSpecialInteger< QLittleEndianStorageType< T > > QLEInteger
Constructs a QLEInteger with the given value.
Definition qendian.h:380
QBEInteger< qint64 > qint64_be
Definition qendian.h:402
QLEInteger< quint32 > quint32_le
Definition qendian.h:397
QLEInteger< quint64 > quint64_le
Definition qendian.h:398
QSpecialInteger< QBigEndianStorageType< T > > QBEInteger
Constructs a QBEInteger with the given value.
Definition qendian.h:383
constexpr quint64 qbswap_helper(quint64 source)
Definition qendian.h:63
qfloat16 qbswap(qfloat16 source)
Definition qendian.h:136
void * qbswap(const void *source, qsizetype count, void *dest) noexcept
QBEInteger< quint32 > quint32_be
Definition qendian.h:404
constexpr T qFromLittleEndian(T source)
Definition qendian.h:179
constexpr T qToBigEndian(T source)
Definition qendian.h:173
QLEInteger< quint16 > quint16_le
Definition qendian.h:396
T qFromLittleEndian(const void *src)
Definition qendian.h:225
QLEInteger< qint16 > qint16_le
Definition qendian.h:393
constexpr T qFromBigEndian(T source)
Definition qendian.h:175
QBEInteger< qint16 > qint16_be
Definition qendian.h:400
void qToBigEndian(const void *source, qsizetype count, void *dest)
Definition qendian.h:186
QBEInteger< quint16 > quint16_be
Definition qendian.h:403
T qFromBigEndian(const void *src)
Definition qendian.h:239
double qbswap(double source)
Definition qendian.h:146
void qFromBigEndian(const void *source, qsizetype count, void *dest)
Definition qendian.h:190
constexpr T qToLittleEndian(T source)
Definition qendian.h:177
Float qbswapFloatHelper(Float source)
Definition qendian.h:128