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.cpp
Go to the documentation of this file.
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
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 QLEInteger<T> stores an integer value in little-endian byte order, where
287 \a T specifies the underlying C++ integer type. The template parameter \a T
288 must be a C++ integer type:
289 \list
290 \li 8-bit: char, signed char, unsigned char, qint8, quint8
291 \li 16-bit: short, unsigned short, qint16, quint16, char16_t
292 \li 32-bit: int, unsigned int, qint32, quint32, char32_t
293 \li 64-bit: long long, unsigned long long, qint64, quint64
294 \li platform-specific size: long, unsigned long
295 \li pointer size: qintptr, quintptr, qptrdiff
296 \endlist
297
298 \note Using this class may be slower than using native integers, so only use it when
299 an exact endianness is needed.
300*/
301
302/*! \fn template <typename T> QLEInteger<T>::QLEInteger(T value)
303
304 Constructs a QLEInteger with the given \a value.
305*/
306
307/*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator=(T i)
308
309 Assigns \a i to this QLEInteger and returns a reference to
310 this QLEInteger.
311*/
312
313/*!
314 \fn template <typename T> QLEInteger<T>::operator T() const
315
316 Returns the value of this QLEInteger as a native integer.
317*/
318
319/*!
320 \fn template <typename T> bool QLEInteger<T>::operator==(QLEInteger other) const
321
322 Returns \c true if the value of this QLEInteger is equal to the value of \a other.
323*/
324
325/*!
326 \fn template <typename T> bool QLEInteger<T>::operator!=(QLEInteger other) const
327
328 Returns \c true if the value of this QLEInteger is not equal to the value of \a other.
329*/
330
331/*!
332 \fn template <typename T> QLEInteger &QLEInteger<T>::operator+=(T i)
333
334 Adds \a i to this QLEInteger and returns a reference to
335 this object.
336*/
337
338/*!
339 \fn template <typename T> QLEInteger &QLEInteger<T>::operator-=(T i)
340
341 Subtracts \a i from this QLEInteger and returns a reference to
342 this object.
343*/
344
345/*!
346 \fn template <typename T> QLEInteger &QLEInteger<T>::operator*=(T i)
347
348 Multiplies \a i with this QLEInteger and returns a reference to
349 this object.
350*/
351
352/*!
353 \fn template <typename T> QLEInteger &QLEInteger<T>::operator/=(T i)
354
355 Divides this QLEInteger with \a i and returns a reference to
356 this object.
357*/
358
359/*!
360 \fn template <typename T> QLEInteger &QLEInteger<T>::operator%=(T i)
361
362 Sets this QLEInteger to the remainder of a division by \a i and
363 returns a reference to this object.
364*/
365
366/*!
367 \fn template <typename T> QLEInteger &QLEInteger<T>::operator>>=(T i)
368
369 Performs a left-shift by \a i on this QLEInteger and returns a
370 reference to this object.
371*/
372
373/*!
374 \fn template <typename T> QLEInteger &QLEInteger<T>::operator<<=(T i)
375
376 Performs a right-shift by \a i on this QLEInteger and returns a
377 reference to this object.
378*/
379
380/*!
381 \fn template <typename T> QLEInteger &QLEInteger<T>::operator|=(T i)
382
383 Performs a bitwise OR with \a i onto this QLEInteger and returns a reference to
384 this object.
385*/
386
387/*!
388 \fn template <typename T> QLEInteger &QLEInteger<T>::operator&=(T i)
389
390 Performs a bitwise AND with \a i onto this QLEInteger and returns a reference to
391 this object.
392*/
393
394/*!
395 \fn template <typename T> QLEInteger &QLEInteger<T>::operator^=(T i)
396
397 Performs a bitwise XOR with \a i onto this QLEInteger and returns a reference to
398 this object.
399*/
400
401/*!
402 \fn template <typename T> QLEInteger &QLEInteger<T>::operator++()
403
404 Performs a prefix \c{++} (increment) on this QLEInteger and returns a reference to
405 this object.
406*/
407
408/*!
409 \fn template <typename T> QLEInteger QLEInteger<T>::operator++(int)
410
411 Performs a postfix \c{++} (increment) on this QLEInteger and returns a reference to
412 this object.
413*/
414
415/*!
416 \fn template <typename T> QLEInteger &QLEInteger<T>::operator--()
417
418 Performs a prefix \c{--} (decrement) on this QLEInteger and returns a reference to
419 this object.
420*/
421
422/*!
423 \fn template <typename T> QLEInteger QLEInteger<T>::operator--(int)
424
425 Performs a postfix \c{--} (decrement) on this QLEInteger and returns a reference to
426 this object.
427*/
428
429/*!
430 \fn template <typename T> QLEInteger QLEInteger<T>::max()
431
432 Returns the maximum (finite) value representable by the numeric type T.
433*/
434
435/*!
436 \fn template <typename T> QLEInteger QLEInteger<T>::min()
437
438 Returns the minimum (finite) value representable by the numeric type T.
439*/
440
441/*!
442 \class QBEInteger
443 \inmodule QtCore
444 \brief The QBEInteger class provides platform-independent big-endian integers.
445 \since 5.10
446
447 QBEInteger<T> stores an integer value in big-endian byte order, where
448 \a T specifies the underlying C++ integer type. The template parameter \a T
449 must be a C++ integer type:
450 \list
451 \li 8-bit: char, signed char, unsigned char, qint8, quint8
452 \li 16-bit: short, unsigned short, qint16, quint16, char16_t
453 \li 32-bit: int, unsigned int, qint32, quint32, char32_t
454 \li 64-bit: long long, unsigned long long, qint64, quint64
455 \li platform-specific size: long, unsigned long
456 \li pointer size: qintptr, quintptr, qptrdiff
457 \endlist
458
459 \note Using this class may be slower than using native integers, so only use it when
460 an exact endianness is needed.
461*/
462
463/*! \fn template <typename T> QBEInteger<T>::QBEInteger(T value)
464
465 Constructs a QBEInteger with the given \a value.
466*/
467
468/*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator=(T i)
469
470 Assigns \a i to this QBEInteger and returns a reference to
471 this QBEInteger.
472*/
473
474/*!
475 \fn template <typename T> QBEInteger<T>::operator T() const
476
477 Returns the value of this QBEInteger as a native integer.
478*/
479
480/*!
481 \fn template <typename T> bool QBEInteger<T>::operator==(QBEInteger other) const
482
483 Returns \c true if the value of this QBEInteger is equal to the value of \a other.
484*/
485
486/*!
487 \fn template <typename T> bool QBEInteger<T>::operator!=(QBEInteger other) const
488
489 Returns \c true if the value of this QBEInteger is not equal to the value of \a other.
490*/
491
492/*!
493 \fn template <typename T> QBEInteger &QBEInteger<T>::operator+=(T i)
494
495 Adds \a i to this QBEInteger and returns a reference to
496 this object.
497*/
498
499/*!
500 \fn template <typename T> QBEInteger &QBEInteger<T>::operator-=(T i)
501
502 Subtracts \a i from this QBEInteger and returns a reference to
503 this object.
504*/
505
506/*!
507 \fn template <typename T> QBEInteger &QBEInteger<T>::operator*=(T i)
508
509 Multiplies \a i with this QBEInteger and returns a reference to
510 this object.
511*/
512
513/*!
514 \fn template <typename T> QBEInteger &QBEInteger<T>::operator/=(T i)
515
516 Divides this QBEInteger with \a i and returns a reference to
517 this object.
518*/
519
520/*!
521 \fn template <typename T> QBEInteger &QBEInteger<T>::operator%=(T i)
522
523 Sets this QBEInteger to the remainder of a division by \a i and
524 returns a reference to this object.
525*/
526
527/*!
528 \fn template <typename T> QBEInteger &QBEInteger<T>::operator>>=(T i)
529
530 Performs a left-shift by \a i on this QBEInteger and returns a
531 reference to this object.
532*/
533
534/*!
535 \fn template <typename T> QBEInteger &QBEInteger<T>::operator<<=(T i)
536
537 Performs a right-shift by \a i on this QBEInteger and returns a
538 reference to this object.
539*/
540
541/*!
542 \fn template <typename T> QBEInteger &QBEInteger<T>::operator|=(T i)
543
544 Performs a bitwise OR with \a i onto this QBEInteger and returns a reference to
545 this object.
546*/
547
548/*!
549 \fn template <typename T> QBEInteger &QBEInteger<T>::operator&=(T i)
550
551 Performs a bitwise AND with \a i onto this QBEInteger and returns a reference to
552 this object.
553*/
554
555/*!
556 \fn template <typename T> QBEInteger &QBEInteger<T>::operator^=(T i)
557
558 Performs a bitwise XOR with \a i onto this QBEInteger and returns a reference to
559 this object.
560*/
561
562/*!
563 \fn template <typename T> QBEInteger &QBEInteger<T>::operator++()
564
565 Performs a prefix \c{++} (increment) on this QBEInteger and returns a reference to
566 this object.
567*/
568
569/*!
570 \fn template <typename T> QBEInteger QBEInteger<T>::operator++(int)
571
572 Performs a postfix \c{++} (increment) on this QBEInteger and returns a reference to
573 this object.
574*/
575
576/*!
577 \fn template <typename T> QBEInteger &QBEInteger<T>::operator--()
578
579 Performs a prefix \c{--} (decrement) on this QBEInteger and returns a reference to
580 this object.
581*/
582
583/*!
584 \fn template <typename T> QBEInteger QBEInteger<T>::operator--(int)
585
586 Performs a postfix \c{--} (decrement) on this QBEInteger and returns a reference to
587 this object.
588*/
589
590/*!
591 \fn template <typename T> QBEInteger QBEInteger<T>::max()
592
593 Returns the maximum (finite) value representable by the numeric type T.
594*/
595
596/*!
597 \fn template <typename T> QBEInteger QBEInteger<T>::min()
598
599 Returns the minimum (finite) value representable by the numeric type T.
600*/
601
602/*!
603 \typedef quint16_le
604 \relates <QtEndian>
605 \since 5.10
606
607 Typedef for QLEInteger<quint16>. This type is guaranteed to be stored in memory as
608 a 16-bit little-endian unsigned integer on all platforms supported by Qt.
609
610 \sa quint16
611*/
612
613/*!
614 \typedef quint32_le
615 \relates <QtEndian>
616 \since 5.10
617
618 Typedef for QLEInteger<quint32>. This type is guaranteed to be stored in memory as
619 a 32-bit little-endian unsigned integer on all platforms supported by Qt.
620
621 \sa quint32
622*/
623
624/*!
625 \typedef quint64_le
626 \relates <QtEndian>
627 \since 5.10
628
629 Typedef for QLEInteger<quint64>. This type is guaranteed to be stored in memory as
630 a 64-bit little-endian unsigned integer on all platforms supported by Qt.
631
632 \sa quint64
633*/
634
635/*!
636 \typedef quint16_be
637 \relates <QtEndian>
638 \since 5.10
639
640 Typedef for QBEInteger<quint16>. This type is guaranteed to be stored in memory as
641 a 16-bit big-endian unsigned integer on all platforms supported by Qt.
642
643 \sa quint16
644*/
645
646/*!
647 \typedef quint32_be
648 \relates <QtEndian>
649 \since 5.10
650
651 Typedef for QBEInteger<quint32>. This type is guaranteed to be stored in memory as
652 a 32-bit big-endian unsigned integer on all platforms supported by Qt.
653
654 \sa quint32
655*/
656
657/*!
658 \typedef quint64_be
659 \relates <QtEndian>
660 \since 5.10
661
662 Typedef for QBEInteger<quint64>. This type is guaranteed to be stored in memory as
663 a 64-bit big-endian unsigned integer on all platforms supported by Qt.
664
665 \sa quint64
666*/
667
668/*!
669 \typedef qint16_le
670 \relates <QtEndian>
671 \since 5.10
672
673 Typedef for QLEInteger<qint16>. This type is guaranteed to be stored in memory as
674 a 16-bit little-endian signed integer on all platforms supported by Qt.
675
676 \sa qint16
677*/
678
679/*!
680 \typedef qint32_le
681 \relates <QtEndian>
682 \since 5.10
683
684 Typedef for QLEInteger<qint32>. This type is guaranteed to be stored in memory as
685 a 32-bit little-endian signed integer on all platforms supported by Qt.
686
687 \sa qint32
688*/
689
690/*!
691 \typedef qint64_le
692 \relates <QtEndian>
693 \since 5.10
694
695 Typedef for QLEInteger<qint64>. This type is guaranteed to be stored in memory as
696 a 64-bit little-endian signed integer on all platforms supported by Qt.
697
698 \sa qint64
699*/
700
701/*!
702 \typedef qint16_be
703 \relates <QtEndian>
704 \since 5.10
705
706 Typedef for QBEInteger<qint16>. This type is guaranteed to be stored in memory as
707 a 16-bit big-endian signed integer on all platforms supported by Qt.
708
709 \sa qint16
710*/
711
712/*!
713 \typedef qint32_be
714 \relates <QtEndian>
715 \since 5.10
716
717 Typedef for QBEInteger<qint32>. This type is guaranteed to be stored in memory as
718 a 32-bit big-endian signed integer on all platforms supported by Qt.
719
720 \sa qint32
721*/
722
723/*!
724 \typedef qint64_be
725 \relates <QtEndian>
726 \since 5.10
727
728 Typedef for QBEInteger<qint64>. This type is guaranteed to be stored in memory as
729 a 64-bit big-endian signed integer on all platforms supported by Qt.
730
731 \sa qint64
732*/
733
734#if defined(__SSSE3__)
735using ShuffleMask = uchar[16];
736alignas(16) static const ShuffleMask shuffleMasks[3] = {
737 // 16-bit
738 {1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14},
739 // 32-bit
740 {3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12},
741 // 64-bit
742 {7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8}
743};
744
745static size_t sseSwapLoop(const uchar *src, size_t bytes, uchar *dst,
746 const __m128i *shuffleMaskPtr) noexcept
747{
748 size_t i = 0;
749 const __m128i shuffleMask = _mm_load_si128(shuffleMaskPtr);
750
751# ifdef __AVX2__
752 const __m256i shuffleMask256 = _mm256_inserti128_si256(_mm256_castsi128_si256(shuffleMask), shuffleMask, 1);
753 for ( ; i + sizeof(__m256i) <= bytes; i += sizeof(__m256i)) {
754 __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src + i));
755 data = _mm256_shuffle_epi8(data, shuffleMask256);
756 _mm256_storeu_si256(reinterpret_cast<__m256i *>(dst + i), data);
757 }
758# else
759 for ( ; i + 2 * sizeof(__m128i) <= bytes; i += 2 * sizeof(__m128i)) {
760 __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i));
761 __m128i data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i) + 1);
762 data1 = _mm_shuffle_epi8(data1, shuffleMask);
763 data2 = _mm_shuffle_epi8(data2, shuffleMask);
764 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data1);
765 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i) + 1, data2);
766 }
767# endif
768
769 if (i + sizeof(__m128i) <= bytes) {
770 __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i));
771 data = _mm_shuffle_epi8(data, shuffleMask);
772 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data);
773 i += sizeof(__m128i);
774 }
775
776 return i;
777}
778
779template <typename T> static Q_ALWAYS_INLINE
780size_t simdSwapLoop(const uchar *src, size_t bytes, uchar *dst) noexcept
781{
782 auto shuffleMaskPtr = reinterpret_cast<const __m128i *>(shuffleMasks[0]);
783 shuffleMaskPtr += qCountTrailingZeroBits(sizeof(T)) - 1;
784 size_t i = sseSwapLoop(src, bytes, dst, shuffleMaskPtr);
785
786 // epilogue
787 for (size_t _i = 0; i < bytes && _i < sizeof(__m128i); i += sizeof(T), _i += sizeof(T))
788 qbswap(qFromUnaligned<T>(src + i), dst + i);
789
790 // return the total, so the bswapLoop below does nothing
791 return bytes;
792}
793#elif defined(__SSE2__)
794template <typename T> static
795size_t simdSwapLoop(const uchar *, size_t, uchar *) noexcept
796{
797 // no generic version: we can't do 32- and 64-bit swaps easily,
798 // so we won't try
799 return 0;
800}
801
802template <> size_t simdSwapLoop<quint16>(const uchar *src, size_t bytes, uchar *dst) noexcept
803{
804 auto swapEndian = [](__m128i &data) {
805 __m128i lows = _mm_srli_epi16(data, 8);
806 __m128i highs = _mm_slli_epi16(data, 8);
807 data = _mm_xor_si128(lows, highs);
808 };
809
810 size_t i = 0;
811 for ( ; i + 2 * sizeof(__m128i) <= bytes; i += 2 * sizeof(__m128i)) {
812 __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i));
813 __m128i data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i) + 1);
814 swapEndian(data1);
815 swapEndian(data2);
816 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data1);
817 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i) + 1, data2);
818 }
819
820 if (i + sizeof(__m128i) <= bytes) {
821 __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i));
822 swapEndian(data);
823 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data);
824 i += sizeof(__m128i);
825 }
826
827 // epilogue
828 for (size_t _i = 0 ; i < bytes && _i < sizeof(__m128i); i += sizeof(quint16), _i += sizeof(quint16))
829 qbswap(qFromUnaligned<quint16>(src + i), dst + i);
830
831 // return the total, so the bswapLoop below does nothing
832 return bytes;
833}
834#else
835template <typename T> static Q_ALWAYS_INLINE
836size_t simdSwapLoop(const uchar *, size_t, uchar *) noexcept
837{
838 return 0;
839}
840#endif
841
842template <typename T> Q_ALWAYS_INLINE static
843void *bswapLoop(const uchar *src, size_t n, uchar *dst) noexcept
844{
845 // Buffers cannot partially overlap: either they're identical or totally
846 // disjoint (note: they can be adjacent).
847 if (src != dst) {
848 quintptr s = quintptr(src);
849 quintptr d = quintptr(dst);
850 if (s < d)
851 Q_ASSERT(s + n <= d);
852 else
853 Q_ASSERT(d + n <= s);
854 }
855
856 size_t i = simdSwapLoop<T>(src, n, dst);
857
858 for (; i < n; i += sizeof(T))
859 qbswap(qFromUnaligned<T>(src + i), dst + i);
860 return dst + i;
861}
862
863template<>
864void *qbswap<2>(const void *source, qsizetype n, void *dest) noexcept
865{
866 const uchar *src = reinterpret_cast<const uchar *>(source);
867 uchar *dst = reinterpret_cast<uchar *>(dest);
868
869 return bswapLoop<quint16>(src, n << 1, dst);
870}
871
872template<>
873void *qbswap<4>(const void *source, qsizetype n, void *dest) noexcept
874{
875 const uchar *src = reinterpret_cast<const uchar *>(source);
876 uchar *dst = reinterpret_cast<uchar *>(dest);
877
878 return bswapLoop<quint32>(src, n << 2, dst);
879}
880
881template<>
882void *qbswap<8>(const void *source, qsizetype n, void *dest) noexcept
883{
884 const uchar *src = reinterpret_cast<const uchar *>(source);
885 uchar *dst = reinterpret_cast<uchar *>(dest);
886
887 return bswapLoop<quint64>(src, n << 3, dst);
888}
889
890QT_END_NAMESPACE
Combined button and popup list for selecting options.
static Q_ALWAYS_INLINE void * bswapLoop(const uchar *src, size_t n, uchar *dst) noexcept
Definition qendian.cpp:843
void * qbswap< 2 >(const void *source, qsizetype n, void *dest) noexcept
Definition qendian.cpp:864