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