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