1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // Copyright (C) 2018 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 | |
5 | #include "qendian.h" |
6 | |
7 | #include "qalgorithms.h" |
8 | #include <private/qsimd_p.h> |
9 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | /*! |
13 | \headerfile <QtEndian> |
14 | \inmodule QtCore |
15 | \title Endian Conversion Functions |
16 | \ingroup funclists |
17 | \brief The <QtEndian> header provides functions to convert between |
18 | little and big endian representations of numbers. |
19 | */ |
20 | |
21 | /*! |
22 | \fn template <typename T> T qFromUnaligned(const void *ptr) |
23 | \internal |
24 | \since 5.5 |
25 | |
26 | Loads a \c{T} from address \a ptr, which may be misaligned. |
27 | |
28 | Use of this function avoids the undefined behavior that the C++ standard |
29 | otherwise attributes to unaligned loads. |
30 | */ |
31 | |
32 | /*! |
33 | \fn template <typename T> void qToUnaligned(const T t, void *ptr) |
34 | \internal |
35 | \since 4.5 |
36 | |
37 | Stores \a t to address \a ptr, which may be misaligned. |
38 | |
39 | Use of this function avoids the undefined behavior that the C++ standard |
40 | otherwise attributes to unaligned stores. |
41 | */ |
42 | |
43 | |
44 | /*! |
45 | \fn template <typename T> T qFromBigEndian(const void *src) |
46 | \since 4.3 |
47 | \relates <QtEndian> |
48 | |
49 | Reads a big-endian number from memory location \a src and returns the number in the |
50 | host byte order representation. |
51 | On CPU architectures where the host byte order is little-endian (such as x86) this |
52 | will swap the byte order; otherwise it will just read from \a src. |
53 | |
54 | \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, |
55 | quint64, or qint64. Other types of integers, e.g., qlong, are not |
56 | applicable. |
57 | |
58 | \note Since Qt 5.7, the type of the \a src parameter is a void pointer. |
59 | |
60 | There are no data alignment constraints for \a src. |
61 | |
62 | \sa qFromLittleEndian() |
63 | \sa qToBigEndian() |
64 | \sa qToLittleEndian() |
65 | */ |
66 | /*! |
67 | \fn template <typename T> T qFromBigEndian(T src) |
68 | \since 4.3 |
69 | \relates <QtEndian> |
70 | \overload |
71 | |
72 | Converts \a src from big-endian byte order and returns the number in host byte order |
73 | representation of that number. |
74 | On CPU architectures where the host byte order is little-endian (such as x86) this |
75 | will return \a src with the byte order swapped; otherwise it will return \a src |
76 | unmodified. |
77 | */ |
78 | /*! |
79 | \fn template <typename T> T qFromBigEndian(const void *src, qsizetype count, void *dest) |
80 | \since 5.12 |
81 | \relates <QtEndian> |
82 | |
83 | Reads \a count big-endian numbers from memory location \a src and stores |
84 | them in the host byte order representation at \a dest. On CPU architectures |
85 | where the host byte order is little-endian (such as x86) this will swap the |
86 | byte order; otherwise it will just perform a \c memcpy from \a src to \a |
87 | dest. |
88 | |
89 | \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, |
90 | quint64, or qint64. Other types of integers, e.g., qlong, are not |
91 | applicable. |
92 | |
93 | There are no data alignment constraints for \a src. However, \a dest is |
94 | expected to be naturally aligned for type \c{T}. |
95 | |
96 | If \a src and \a dest can be the same pointer, this function will perform |
97 | an in-place swap (if necessary). If they are not the same, the memory |
98 | regions must not overlap. |
99 | |
100 | \sa qFromLittleEndian() |
101 | \sa qToBigEndian() |
102 | \sa qToLittleEndian() |
103 | */ |
104 | /*! |
105 | \fn template <typename T> inline T qFromLittleEndian(const void *src) |
106 | \since 4.3 |
107 | \relates <QtEndian> |
108 | |
109 | Reads a little-endian number from memory location \a src and returns the number in |
110 | the host byte order representation. |
111 | On CPU architectures where the host byte order is big-endian (such as PowerPC) this |
112 | will swap the byte order; otherwise it will just read from \a src. |
113 | |
114 | \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, |
115 | quint64, or qint64. Other types of integers, e.g., qlong, are not |
116 | applicable. |
117 | |
118 | \note Since Qt 5.7, the type of the \a src parameter is a void pointer. |
119 | |
120 | There are no data alignment constraints for \a src. |
121 | |
122 | \sa qFromBigEndian() |
123 | \sa qToBigEndian() |
124 | \sa qToLittleEndian() |
125 | */ |
126 | /*! |
127 | \fn template <typename T> inline T qFromLittleEndian(T src) |
128 | \since 4.3 |
129 | \relates <QtEndian> |
130 | \overload |
131 | |
132 | Converts \a src from little-endian byte order and returns the number in host byte |
133 | order representation of that number. |
134 | On CPU architectures where the host byte order is big-endian (such as PowerPC) this |
135 | will return \a src with the byte order swapped; otherwise it will return \a src |
136 | unmodified. |
137 | */ |
138 | /*! |
139 | \fn template <typename T> inline T qFromLittleEndian(const void *src, qsizetype count, void *dest) |
140 | \since 5.12 |
141 | \relates <QtEndian> |
142 | |
143 | Reads \a count little-endian numbers from memory location \a src and stores |
144 | them in the host byte order representation at \a dest. On CPU architectures |
145 | where the host byte order is big-endian (such as PowerPC) this will swap the |
146 | byte order; otherwise it will just perform a \c memcpy from \a src to \a |
147 | dest. |
148 | |
149 | \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, |
150 | quint64, or qint64. Other types of integers, e.g., qlong, are not |
151 | applicable. |
152 | |
153 | There are no data alignment constraints for \a src. However, \a dest is |
154 | expected to be naturally aligned for type \c{T}. |
155 | |
156 | If \a src and \a dest can be the same pointer, this function will perform |
157 | an in-place swap (if necessary). If they are not the same, the memory |
158 | regions must not overlap. |
159 | |
160 | \sa qToBigEndian() |
161 | \sa qToLittleEndian() |
162 | */ |
163 | /*! |
164 | \fn template <typename T> void qToBigEndian(T src, void *dest) |
165 | \since 4.3 |
166 | \relates <QtEndian> |
167 | |
168 | Writes the number \a src with template type \c{T} to the memory location at \a dest |
169 | in big-endian byte order. |
170 | |
171 | \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, |
172 | quint64, or qint64. Other types of integers, e.g., qlong, are not |
173 | applicable. |
174 | |
175 | There are no data alignment constraints for \a dest. |
176 | |
177 | \note Since Qt 5.7, the type of the \a dest parameter is a void pointer. |
178 | |
179 | \sa qFromBigEndian() |
180 | \sa qFromLittleEndian() |
181 | \sa qToLittleEndian() |
182 | */ |
183 | /*! |
184 | \fn template <typename T> T qToBigEndian(T src) |
185 | \since 4.3 |
186 | \relates <QtEndian> |
187 | \overload |
188 | |
189 | Converts \a src from host byte order and returns the number in big-endian byte order |
190 | representation of that number. |
191 | On CPU architectures where the host byte order is little-endian (such as x86) this |
192 | will return \a src with the byte order swapped; otherwise it will return \a src |
193 | unmodified. |
194 | */ |
195 | /*! |
196 | \fn template <typename T> T qToBigEndian(const void *src, qsizetype count, void *dest) |
197 | \since 5.12 |
198 | \relates <QtEndian> |
199 | |
200 | Reads \a count numbers from memory location \a src in the host byte order |
201 | and stores them in big-endian representation at \a dest. On CPU |
202 | architectures where the host byte order is little-endian (such as x86) this |
203 | will swap the byte order; otherwise it will just perform a \c memcpy from |
204 | \a src to \a dest. |
205 | |
206 | \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, |
207 | quint64, or qint64. Other types of integers, e.g., qlong, are not |
208 | applicable. |
209 | |
210 | There are no data alignment constraints for \a dest. However, \a src is |
211 | expected to be naturally aligned for type \c{T}. |
212 | |
213 | If \a src and \a dest can be the same pointer, this function will perform |
214 | an in-place swap (if necessary). If they are not the same, the memory |
215 | regions must not overlap. |
216 | |
217 | \sa qFromLittleEndian() |
218 | \sa qToBigEndian() |
219 | \sa qToLittleEndian() |
220 | */ |
221 | /*! |
222 | \fn template <typename T> void qToLittleEndian(T src, void *dest) |
223 | \since 4.3 |
224 | \relates <QtEndian> |
225 | |
226 | Writes the number \a src with template type \c{T} to the memory location at \a dest |
227 | in little-endian byte order. |
228 | |
229 | \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, |
230 | quint64, or qint64. Other types of integers, e.g., qlong, are not |
231 | applicable. |
232 | |
233 | There are no data alignment constraints for \a dest. |
234 | |
235 | \note Since Qt 5.7, the type of the \a dest parameter is a void pointer. |
236 | |
237 | \sa qFromBigEndian() |
238 | \sa qFromLittleEndian() |
239 | \sa qToBigEndian() |
240 | */ |
241 | /*! |
242 | \fn template <typename T> T qToLittleEndian(T src) |
243 | \since 4.3 |
244 | \relates <QtEndian> |
245 | \overload |
246 | |
247 | Converts \a src from host byte order and returns the number in little-endian byte |
248 | order representation of that number. |
249 | On CPU architectures where the host byte order is big-endian (such as PowerPC) this |
250 | will return \a src with the byte order swapped; otherwise it will return \a src |
251 | unmodified. |
252 | */ |
253 | /*! |
254 | \fn template <typename T> T qToLittleEndian(const void *src, qsizetype count, void *dest) |
255 | \since 5.12 |
256 | \relates <QtEndian> |
257 | |
258 | Reads \a count numbers from memory location \a src in the host byte order |
259 | and stores them in little-endian representation at \a dest. On CPU |
260 | architectures where the host byte order is big-endian (such as PowerPC) |
261 | this will swap the byte order; otherwise it will just perform a \c memcpy |
262 | from \a src to \a dest. |
263 | |
264 | \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, |
265 | quint64, or qint64. Other types of integers, e.g., qlong, are not |
266 | applicable. |
267 | |
268 | There are no data alignment constraints for \a dest. However, \a src is |
269 | expected to be naturally aligned for type \c{T}. |
270 | |
271 | If \a src and \a dest can be the same pointer, this function will perform |
272 | an in-place swap (if necessary). If they are not the same, the memory |
273 | regions must not overlap. |
274 | |
275 | \sa qFromLittleEndian() |
276 | \sa qToBigEndian() |
277 | \sa qToLittleEndian() |
278 | */ |
279 | |
280 | /*! |
281 | \class QLEInteger |
282 | \inmodule QtCore |
283 | \brief The QLEInteger class provides platform-independent little-endian integers. |
284 | \since 5.10 |
285 | |
286 | The template parameter \c T must be a C++ integer type: |
287 | \list |
288 | \li 8-bit: char, signed char, unsigned char, qint8, quint8 |
289 | \li 16-bit: short, unsigned short, qint16, quint16, char16_t |
290 | \li 32-bit: int, unsigned int, qint32, quint32, char32_t |
291 | \li 64-bit: long long, unsigned long long, qint64, quint64 |
292 | \li platform-specific size: long, unsigned long |
293 | \li pointer size: qintptr, quintptr, qptrdiff |
294 | \endlist |
295 | |
296 | \note Using this class may be slower than using native integers, so only use it when |
297 | an exact endianness is needed. |
298 | */ |
299 | |
300 | /*! \fn template <typename T> QLEInteger<T>::QLEInteger(T value) |
301 | |
302 | Constructs a QLEInteger with the given \a value. |
303 | */ |
304 | |
305 | /*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator=(T i) |
306 | |
307 | Assigns \a i to this QLEInteger and returns a reference to |
308 | this QLEInteger. |
309 | */ |
310 | |
311 | /*! |
312 | \fn template <typename T> QLEInteger<T>::operator T() const |
313 | |
314 | Returns the value of this QLEInteger as a native integer. |
315 | */ |
316 | |
317 | /*! |
318 | \fn template <typename T> bool QLEInteger<T>::operator==(QLEInteger other) const |
319 | |
320 | Returns \c true if the value of this QLEInteger is equal to the value of \a other. |
321 | */ |
322 | |
323 | /*! |
324 | \fn template <typename T> bool QLEInteger<T>::operator!=(QLEInteger other) const |
325 | |
326 | Returns \c true if the value of this QLEInteger is not equal to the value of \a other. |
327 | */ |
328 | |
329 | /*! |
330 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator+=(T i) |
331 | |
332 | Adds \a i to this QLEInteger and returns a reference to |
333 | this object. |
334 | */ |
335 | |
336 | /*! |
337 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator-=(T i) |
338 | |
339 | Subtracts \a i from this QLEInteger and returns a reference to |
340 | this object. |
341 | */ |
342 | |
343 | /*! |
344 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator*=(T i) |
345 | |
346 | Multiplies \a i with this QLEInteger and returns a reference to |
347 | this object. |
348 | */ |
349 | |
350 | /*! |
351 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator/=(T i) |
352 | |
353 | Divides this QLEInteger with \a i and returns a reference to |
354 | this object. |
355 | */ |
356 | |
357 | /*! |
358 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator%=(T i) |
359 | |
360 | Sets this QLEInteger to the remainder of a division by \a i and |
361 | returns a reference to this object. |
362 | */ |
363 | |
364 | /*! |
365 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator>>=(T i) |
366 | |
367 | Performs a left-shift by \a i on this QLEInteger and returns a |
368 | reference to this object. |
369 | */ |
370 | |
371 | /*! |
372 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator<<=(T i) |
373 | |
374 | Performs a right-shift by \a i on this QLEInteger and returns a |
375 | reference to this object. |
376 | */ |
377 | |
378 | /*! |
379 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator|=(T i) |
380 | |
381 | Performs a bitwise OR with \a i onto this QLEInteger and returns a reference to |
382 | this object. |
383 | */ |
384 | |
385 | /*! |
386 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator&=(T i) |
387 | |
388 | Performs a bitwise AND with \a i onto this QLEInteger and returns a reference to |
389 | this object. |
390 | */ |
391 | |
392 | /*! |
393 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator^=(T i) |
394 | |
395 | Performs a bitwise XOR with \a i onto this QLEInteger and returns a reference to |
396 | this object. |
397 | */ |
398 | |
399 | /*! |
400 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator++() |
401 | |
402 | Performs a prefix \c{++} (increment) on this QLEInteger and returns a reference to |
403 | this object. |
404 | */ |
405 | |
406 | /*! |
407 | \fn template <typename T> QLEInteger QLEInteger<T>::operator++(int) |
408 | |
409 | Performs a postfix \c{++} (increment) on this QLEInteger and returns a reference to |
410 | this object. |
411 | */ |
412 | |
413 | /*! |
414 | \fn template <typename T> QLEInteger &QLEInteger<T>::operator--() |
415 | |
416 | Performs a prefix \c{--} (decrement) on this QLEInteger and returns a reference to |
417 | this object. |
418 | */ |
419 | |
420 | /*! |
421 | \fn template <typename T> QLEInteger QLEInteger<T>::operator--(int) |
422 | |
423 | Performs a postfix \c{--} (decrement) on this QLEInteger and returns a reference to |
424 | this object. |
425 | */ |
426 | |
427 | /*! |
428 | \fn template <typename T> QLEInteger QLEInteger<T>::max() |
429 | |
430 | Returns the maximum (finite) value representable by the numeric type T. |
431 | */ |
432 | |
433 | /*! |
434 | \fn template <typename T> QLEInteger QLEInteger<T>::min() |
435 | |
436 | Returns the minimum (finite) value representable by the numeric type T. |
437 | */ |
438 | |
439 | /*! |
440 | \class QBEInteger |
441 | \inmodule QtCore |
442 | \brief The QBEInteger class provides platform-independent big-endian integers. |
443 | \since 5.10 |
444 | |
445 | The template parameter \c T must be a C++ integer type: |
446 | \list |
447 | \li 8-bit: char, signed char, unsigned char, qint8, quint8 |
448 | \li 16-bit: short, unsigned short, qint16, quint16, char16_t (C++11) |
449 | \li 32-bit: int, unsigned int, qint32, quint32, char32_t (C++11) |
450 | \li 64-bit: long long, unsigned long long, qint64, quint64 |
451 | \li platform-specific size: long, unsigned long |
452 | \li pointer size: qintptr, quintptr, qptrdiff |
453 | \endlist |
454 | |
455 | \note Using this class may be slower than using native integers, so only use it when |
456 | an exact endianness is needed. |
457 | */ |
458 | |
459 | /*! \fn template <typename T> QBEInteger<T>::QBEInteger(T value) |
460 | |
461 | Constructs a QBEInteger with the given \a value. |
462 | */ |
463 | |
464 | /*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator=(T i) |
465 | |
466 | Assigns \a i to this QBEInteger and returns a reference to |
467 | this QBEInteger. |
468 | */ |
469 | |
470 | /*! |
471 | \fn template <typename T> QBEInteger<T>::operator T() const |
472 | |
473 | Returns the value of this QBEInteger as a native integer. |
474 | */ |
475 | |
476 | /*! |
477 | \fn template <typename T> bool QBEInteger<T>::operator==(QBEInteger other) const |
478 | |
479 | Returns \c true if the value of this QBEInteger is equal to the value of \a other. |
480 | */ |
481 | |
482 | /*! |
483 | \fn template <typename T> bool QBEInteger<T>::operator!=(QBEInteger other) const |
484 | |
485 | Returns \c true if the value of this QBEInteger is not equal to the value of \a other. |
486 | */ |
487 | |
488 | /*! |
489 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator+=(T i) |
490 | |
491 | Adds \a i to this QBEInteger and returns a reference to |
492 | this object. |
493 | */ |
494 | |
495 | /*! |
496 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator-=(T i) |
497 | |
498 | Subtracts \a i from this QBEInteger and returns a reference to |
499 | this object. |
500 | */ |
501 | |
502 | /*! |
503 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator*=(T i) |
504 | |
505 | Multiplies \a i with this QBEInteger and returns a reference to |
506 | this object. |
507 | */ |
508 | |
509 | /*! |
510 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator/=(T i) |
511 | |
512 | Divides this QBEInteger with \a i and returns a reference to |
513 | this object. |
514 | */ |
515 | |
516 | /*! |
517 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator%=(T i) |
518 | |
519 | Sets this QBEInteger to the remainder of a division by \a i and |
520 | returns a reference to this object. |
521 | */ |
522 | |
523 | /*! |
524 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator>>=(T i) |
525 | |
526 | Performs a left-shift by \a i on this QBEInteger and returns a |
527 | reference to this object. |
528 | */ |
529 | |
530 | /*! |
531 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator<<=(T i) |
532 | |
533 | Performs a right-shift by \a i on this QBEInteger and returns a |
534 | reference to this object. |
535 | */ |
536 | |
537 | /*! |
538 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator|=(T i) |
539 | |
540 | Performs a bitwise OR with \a i onto this QBEInteger and returns a reference to |
541 | this object. |
542 | */ |
543 | |
544 | /*! |
545 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator&=(T i) |
546 | |
547 | Performs a bitwise AND with \a i onto this QBEInteger and returns a reference to |
548 | this object. |
549 | */ |
550 | |
551 | /*! |
552 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator^=(T i) |
553 | |
554 | Performs a bitwise XOR with \a i onto this QBEInteger and returns a reference to |
555 | this object. |
556 | */ |
557 | |
558 | /*! |
559 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator++() |
560 | |
561 | Performs a prefix \c{++} (increment) on this QBEInteger and returns a reference to |
562 | this object. |
563 | */ |
564 | |
565 | /*! |
566 | \fn template <typename T> QBEInteger QBEInteger<T>::operator++(int) |
567 | |
568 | Performs a postfix \c{++} (increment) on this QBEInteger and returns a reference to |
569 | this object. |
570 | */ |
571 | |
572 | /*! |
573 | \fn template <typename T> QBEInteger &QBEInteger<T>::operator--() |
574 | |
575 | Performs a prefix \c{--} (decrement) on this QBEInteger and returns a reference to |
576 | this object. |
577 | */ |
578 | |
579 | /*! |
580 | \fn template <typename T> QBEInteger QBEInteger<T>::operator--(int) |
581 | |
582 | Performs a postfix \c{--} (decrement) on this QBEInteger and returns a reference to |
583 | this object. |
584 | */ |
585 | |
586 | /*! |
587 | \fn template <typename T> QBEInteger QBEInteger<T>::max() |
588 | |
589 | Returns the maximum (finite) value representable by the numeric type T. |
590 | */ |
591 | |
592 | /*! |
593 | \fn template <typename T> QBEInteger QBEInteger<T>::min() |
594 | |
595 | Returns the minimum (finite) value representable by the numeric type T. |
596 | */ |
597 | |
598 | /*! |
599 | \typedef quint16_le |
600 | \relates <QtEndian> |
601 | \since 5.10 |
602 | |
603 | Typedef for QLEInteger<quint16>. This type is guaranteed to be stored in memory as |
604 | a 16-bit little-endian unsigned integer on all platforms supported by Qt. |
605 | |
606 | \sa quint16 |
607 | */ |
608 | |
609 | /*! |
610 | \typedef quint32_le |
611 | \relates <QtEndian> |
612 | \since 5.10 |
613 | |
614 | Typedef for QLEInteger<quint32>. This type is guaranteed to be stored in memory as |
615 | a 32-bit little-endian unsigned integer on all platforms supported by Qt. |
616 | |
617 | \sa quint32 |
618 | */ |
619 | |
620 | /*! |
621 | \typedef quint64_le |
622 | \relates <QtEndian> |
623 | \since 5.10 |
624 | |
625 | Typedef for QLEInteger<quint64>. This type is guaranteed to be stored in memory as |
626 | a 64-bit little-endian unsigned integer on all platforms supported by Qt. |
627 | |
628 | \sa quint64 |
629 | */ |
630 | |
631 | /*! |
632 | \typedef quint16_be |
633 | \relates <QtEndian> |
634 | \since 5.10 |
635 | |
636 | Typedef for QBEInteger<quint16>. This type is guaranteed to be stored in memory as |
637 | a 16-bit big-endian unsigned integer on all platforms supported by Qt. |
638 | |
639 | \sa quint16 |
640 | */ |
641 | |
642 | /*! |
643 | \typedef quint32_be |
644 | \relates <QtEndian> |
645 | \since 5.10 |
646 | |
647 | Typedef for QBEInteger<quint32>. This type is guaranteed to be stored in memory as |
648 | a 32-bit big-endian unsigned integer on all platforms supported by Qt. |
649 | |
650 | \sa quint32 |
651 | */ |
652 | |
653 | /*! |
654 | \typedef quint64_be |
655 | \relates <QtEndian> |
656 | \since 5.10 |
657 | |
658 | Typedef for QBEInteger<quint64>. This type is guaranteed to be stored in memory as |
659 | a 64-bit big-endian unsigned integer on all platforms supported by Qt. |
660 | |
661 | \sa quint64 |
662 | */ |
663 | |
664 | /*! |
665 | \typedef qint16_le |
666 | \relates <QtEndian> |
667 | \since 5.10 |
668 | |
669 | Typedef for QLEInteger<qint16>. This type is guaranteed to be stored in memory as |
670 | a 16-bit little-endian signed integer on all platforms supported by Qt. |
671 | |
672 | \sa qint16 |
673 | */ |
674 | |
675 | /*! |
676 | \typedef qint32_le |
677 | \relates <QtEndian> |
678 | \since 5.10 |
679 | |
680 | Typedef for QLEInteger<qint32>. This type is guaranteed to be stored in memory as |
681 | a 32-bit little-endian signed integer on all platforms supported by Qt. |
682 | |
683 | \sa qint32 |
684 | */ |
685 | |
686 | /*! |
687 | \typedef qint64_le |
688 | \relates <QtEndian> |
689 | \since 5.10 |
690 | |
691 | Typedef for QLEInteger<qint64>. This type is guaranteed to be stored in memory as |
692 | a 64-bit little-endian signed integer on all platforms supported by Qt. |
693 | |
694 | \sa qint64 |
695 | */ |
696 | |
697 | /*! |
698 | \typedef qint16_be |
699 | \relates <QtEndian> |
700 | \since 5.10 |
701 | |
702 | Typedef for QBEInteger<qint16>. This type is guaranteed to be stored in memory as |
703 | a 16-bit big-endian signed integer on all platforms supported by Qt. |
704 | |
705 | \sa qint16 |
706 | */ |
707 | |
708 | /*! |
709 | \typedef qint32_be |
710 | \relates <QtEndian> |
711 | \since 5.10 |
712 | |
713 | Typedef for QBEInteger<qint32>. This type is guaranteed to be stored in memory as |
714 | a 32-bit big-endian signed integer on all platforms supported by Qt. |
715 | |
716 | \sa qint32 |
717 | */ |
718 | |
719 | /*! |
720 | \typedef qint64_be |
721 | \relates <QtEndian> |
722 | \since 5.10 |
723 | |
724 | Typedef for QBEInteger<qint64>. This type is guaranteed to be stored in memory as |
725 | a 64-bit big-endian signed integer on all platforms supported by Qt. |
726 | |
727 | \sa qint64 |
728 | */ |
729 | |
730 | #if defined(__SSSE3__) |
731 | using ShuffleMask = uchar[16]; |
732 | alignas(16) static const ShuffleMask shuffleMasks[3] = { |
733 | // 16-bit |
734 | {1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14}, |
735 | // 32-bit |
736 | {3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12}, |
737 | // 64-bit |
738 | {7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8} |
739 | }; |
740 | |
741 | static size_t sseSwapLoop(const uchar *src, size_t bytes, uchar *dst, |
742 | const __m128i *shuffleMaskPtr) noexcept |
743 | { |
744 | size_t i = 0; |
745 | const __m128i shuffleMask = _mm_load_si128(shuffleMaskPtr); |
746 | |
747 | # ifdef __AVX2__ |
748 | const __m256i shuffleMask256 = _mm256_inserti128_si256(_mm256_castsi128_si256(shuffleMask), shuffleMask, 1); |
749 | for ( ; i + sizeof(__m256i) <= bytes; i += sizeof(__m256i)) { |
750 | __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src + i)); |
751 | data = _mm256_shuffle_epi8(data, shuffleMask256); |
752 | _mm256_storeu_si256(reinterpret_cast<__m256i *>(dst + i), data); |
753 | } |
754 | # else |
755 | for ( ; i + 2 * sizeof(__m128i) <= bytes; i += 2 * sizeof(__m128i)) { |
756 | __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i)); |
757 | __m128i data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i) + 1); |
758 | data1 = _mm_shuffle_epi8(data1, shuffleMask); |
759 | data2 = _mm_shuffle_epi8(data2, shuffleMask); |
760 | _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data1); |
761 | _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i) + 1, data2); |
762 | } |
763 | # endif |
764 | |
765 | if (i + sizeof(__m128i) <= bytes) { |
766 | __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i)); |
767 | data = _mm_shuffle_epi8(data, shuffleMask); |
768 | _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data); |
769 | i += sizeof(__m128i); |
770 | } |
771 | |
772 | return i; |
773 | } |
774 | |
775 | template <typename T> static Q_ALWAYS_INLINE |
776 | size_t simdSwapLoop(const uchar *src, size_t bytes, uchar *dst) noexcept |
777 | { |
778 | auto shuffleMaskPtr = reinterpret_cast<const __m128i *>(shuffleMasks[0]); |
779 | shuffleMaskPtr += qCountTrailingZeroBits(sizeof(T)) - 1; |
780 | size_t i = sseSwapLoop(src, bytes, dst, shuffleMaskPtr); |
781 | |
782 | // epilogue |
783 | for (size_t _i = 0; i < bytes && _i < sizeof(__m128i); i += sizeof(T), _i += sizeof(T)) |
784 | qbswap(qFromUnaligned<T>(src + i), dst + i); |
785 | |
786 | // return the total, so the bswapLoop below does nothing |
787 | return bytes; |
788 | } |
789 | #elif defined(__SSE2__) |
790 | template <typename T> static |
791 | size_t simdSwapLoop(const uchar *, size_t, uchar *) noexcept |
792 | { |
793 | // no generic version: we can't do 32- and 64-bit swaps easily, |
794 | // so we won't try |
795 | return 0; |
796 | } |
797 | |
798 | template <> size_t simdSwapLoop<quint16>(const uchar *src, size_t bytes, uchar *dst) noexcept |
799 | { |
800 | auto swapEndian = [](__m128i &data) { |
801 | __m128i lows = _mm_srli_epi16(a: data, count: 8); |
802 | __m128i highs = _mm_slli_epi16(a: data, count: 8); |
803 | data = _mm_xor_si128(a: lows, b: highs); |
804 | }; |
805 | |
806 | size_t i = 0; |
807 | for ( ; i + 2 * sizeof(__m128i) <= bytes; i += 2 * sizeof(__m128i)) { |
808 | __m128i data1 = _mm_loadu_si128(p: reinterpret_cast<const __m128i *>(src + i)); |
809 | __m128i data2 = _mm_loadu_si128(p: reinterpret_cast<const __m128i *>(src + i) + 1); |
810 | swapEndian(data1); |
811 | swapEndian(data2); |
812 | _mm_storeu_si128(p: reinterpret_cast<__m128i *>(dst + i), b: data1); |
813 | _mm_storeu_si128(p: reinterpret_cast<__m128i *>(dst + i) + 1, b: data2); |
814 | } |
815 | |
816 | if (i + sizeof(__m128i) <= bytes) { |
817 | __m128i data = _mm_loadu_si128(p: reinterpret_cast<const __m128i *>(src + i)); |
818 | swapEndian(data); |
819 | _mm_storeu_si128(p: reinterpret_cast<__m128i *>(dst + i), b: data); |
820 | i += sizeof(__m128i); |
821 | } |
822 | |
823 | // epilogue |
824 | for (size_t _i = 0 ; i < bytes && _i < sizeof(__m128i); i += sizeof(quint16), _i += sizeof(quint16)) |
825 | qbswap(src: qFromUnaligned<quint16>(src: src + i), dest: dst + i); |
826 | |
827 | // return the total, so the bswapLoop below does nothing |
828 | return bytes; |
829 | } |
830 | #else |
831 | template <typename T> static Q_ALWAYS_INLINE |
832 | size_t simdSwapLoop(const uchar *, size_t, uchar *) noexcept |
833 | { |
834 | return 0; |
835 | } |
836 | #endif |
837 | |
838 | template <typename T> static Q_ALWAYS_INLINE |
839 | void *bswapLoop(const uchar *src, size_t n, uchar *dst) noexcept |
840 | { |
841 | // Buffers cannot partially overlap: either they're identical or totally |
842 | // disjoint (note: they can be adjacent). |
843 | if (src != dst) { |
844 | quintptr s = quintptr(src); |
845 | quintptr d = quintptr(dst); |
846 | if (s < d) |
847 | Q_ASSERT(s + n <= d); |
848 | else |
849 | Q_ASSERT(d + n <= s); |
850 | } |
851 | |
852 | size_t i = simdSwapLoop<T>(src, n, dst); |
853 | |
854 | for (; i < n; i += sizeof(T)) |
855 | qbswap(qFromUnaligned<T>(src + i), dst + i); |
856 | return dst + i; |
857 | } |
858 | |
859 | template<> |
860 | void *qbswap<2>(const void *source, qsizetype n, void *dest) noexcept |
861 | { |
862 | const uchar *src = reinterpret_cast<const uchar *>(source); |
863 | uchar *dst = reinterpret_cast<uchar *>(dest); |
864 | |
865 | return bswapLoop<quint16>(src, n: n << 1, dst); |
866 | } |
867 | |
868 | template<> |
869 | void *qbswap<4>(const void *source, qsizetype n, void *dest) noexcept |
870 | { |
871 | const uchar *src = reinterpret_cast<const uchar *>(source); |
872 | uchar *dst = reinterpret_cast<uchar *>(dest); |
873 | |
874 | return bswapLoop<quint32>(src, n: n << 2, dst); |
875 | } |
876 | |
877 | template<> |
878 | void *qbswap<8>(const void *source, qsizetype n, void *dest) noexcept |
879 | { |
880 | const uchar *src = reinterpret_cast<const uchar *>(source); |
881 | uchar *dst = reinterpret_cast<uchar *>(dest); |
882 | |
883 | return bswapLoop<quint64>(src, n: n << 3, dst); |
884 | } |
885 | |
886 | QT_END_NAMESPACE |
887 | |