123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886 | // Copyright (C) 2016 The Qt Company Ltd.// Copyright (C) 2018 Intel Corporation.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#include"qendian.h"#include"qalgorithms.h"#include <private/qsimd_p.h> QT_BEGIN_NAMESPACE /*! \headerfile <QtEndian> \inmodule QtCore \title Endian Conversion Functions \ingroup funclists \brief The <QtEndian> header provides functions to convert between little and big endian representations of numbers.*//*! \fn template <typename T> T qFromUnaligned(const void *ptr) \internal \since 5.5 Loads a \c{T} from address \a ptr, which may be misaligned. Use of this function avoids the undefined behavior that the C++ standard otherwise attributes to unaligned loads.*//*! \fn template <typename T> void qToUnaligned(const T t, void *ptr) \internal \since 4.5 Stores \a t to address \a ptr, which may be misaligned. Use of this function avoids the undefined behavior that the C++ standard otherwise attributes to unaligned stores.*//*! \fn template <typename T> T qFromBigEndian(const void *src) \since 4.3 \relates <QtEndian> Reads a big-endian number from memory location \a src and returns the number in the host byte order representation. On CPU architectures where the host byte order is little-endian (such as x86) this will swap the byte order; otherwise it will just read from \a src. \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, quint64, or qint64. Other types of integers, e.g., qlong, are not applicable. \note Since Qt 5.7, the type of the \a src parameter is a void pointer. There are no data alignment constraints for \a src. \sa qFromLittleEndian() \sa qToBigEndian() \sa qToLittleEndian()*//*! \fn template <typename T> T qFromBigEndian(T src) \since 4.3 \relates <QtEndian> \overload Converts \a src from big-endian byte order and returns the number in host byte order representation of that number. On CPU architectures where the host byte order is little-endian (such as x86) this will return \a src with the byte order swapped; otherwise it will return \a src unmodified.*//*! \fn template <typename T> T qFromBigEndian(const void *src, qsizetype count, void *dest) \since 5.12 \relates <QtEndian> Reads \a count big-endian numbers from memory location \a src and stores them in the host byte order representation at \a dest. On CPU architectures where the host byte order is little-endian (such as x86) this will swap the byte order; otherwise it will just perform a \c memcpy from \a src to \a dest. \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, quint64, or qint64. Other types of integers, e.g., qlong, are not applicable. There are no data alignment constraints for \a src. However, \a dest is expected to be naturally aligned for type \c{T}. If \a src and \a dest can be the same pointer, this function will perform an in-place swap (if necessary). If they are not the same, the memory regions must not overlap. \sa qFromLittleEndian() \sa qToBigEndian() \sa qToLittleEndian()*//*! \fn template <typename T> inline T qFromLittleEndian(const void *src) \since 4.3 \relates <QtEndian> Reads a little-endian number from memory location \a src and returns the number in the host byte order representation. On CPU architectures where the host byte order is big-endian (such as PowerPC) this will swap the byte order; otherwise it will just read from \a src. \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, quint64, or qint64. Other types of integers, e.g., qlong, are not applicable. \note Since Qt 5.7, the type of the \a src parameter is a void pointer. There are no data alignment constraints for \a src. \sa qFromBigEndian() \sa qToBigEndian() \sa qToLittleEndian()*//*! \fn template <typename T> inline T qFromLittleEndian(T src) \since 4.3 \relates <QtEndian> \overload Converts \a src from little-endian byte order and returns the number in host byte order representation of that number. On CPU architectures where the host byte order is big-endian (such as PowerPC) this will return \a src with the byte order swapped; otherwise it will return \a src unmodified.*//*! \fn template <typename T> inline T qFromLittleEndian(const void *src, qsizetype count, void *dest) \since 5.12 \relates <QtEndian> Reads \a count little-endian numbers from memory location \a src and stores them in the host byte order representation at \a dest. On CPU architectures where the host byte order is big-endian (such as PowerPC) this will swap the byte order; otherwise it will just perform a \c memcpy from \a src to \a dest. \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, quint64, or qint64. Other types of integers, e.g., qlong, are not applicable. There are no data alignment constraints for \a src. However, \a dest is expected to be naturally aligned for type \c{T}. If \a src and \a dest can be the same pointer, this function will perform an in-place swap (if necessary). If they are not the same, the memory regions must not overlap. \sa qToBigEndian() \sa qToLittleEndian()*//*! \fn template <typename T> void qToBigEndian(T src, void *dest) \since 4.3 \relates <QtEndian> Writes the number \a src with template type \c{T} to the memory location at \a dest in big-endian byte order. \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, quint64, or qint64. Other types of integers, e.g., qlong, are not applicable. There are no data alignment constraints for \a dest. \note Since Qt 5.7, the type of the \a dest parameter is a void pointer. \sa qFromBigEndian() \sa qFromLittleEndian() \sa qToLittleEndian()*//*! \fn template <typename T> T qToBigEndian(T src) \since 4.3 \relates <QtEndian> \overload Converts \a src from host byte order and returns the number in big-endian byte order representation of that number. On CPU architectures where the host byte order is little-endian (such as x86) this will return \a src with the byte order swapped; otherwise it will return \a src unmodified.*//*! \fn template <typename T> T qToBigEndian(const void *src, qsizetype count, void *dest) \since 5.12 \relates <QtEndian> Reads \a count numbers from memory location \a src in the host byte order and stores them in big-endian representation at \a dest. On CPU architectures where the host byte order is little-endian (such as x86) this will swap the byte order; otherwise it will just perform a \c memcpy from \a src to \a dest. \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, quint64, or qint64. Other types of integers, e.g., qlong, are not applicable. There are no data alignment constraints for \a dest. However, \a src is expected to be naturally aligned for type \c{T}. If \a src and \a dest can be the same pointer, this function will perform an in-place swap (if necessary). If they are not the same, the memory regions must not overlap. \sa qFromLittleEndian() \sa qToBigEndian() \sa qToLittleEndian()*//*! \fn template <typename T> void qToLittleEndian(T src, void *dest) \since 4.3 \relates <QtEndian> Writes the number \a src with template type \c{T} to the memory location at \a dest in little-endian byte order. \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, quint64, or qint64. Other types of integers, e.g., qlong, are not applicable. There are no data alignment constraints for \a dest. \note Since Qt 5.7, the type of the \a dest parameter is a void pointer. \sa qFromBigEndian() \sa qFromLittleEndian() \sa qToBigEndian()*//*! \fn template <typename T> T qToLittleEndian(T src) \since 4.3 \relates <QtEndian> \overload Converts \a src from host byte order and returns the number in little-endian byte order representation of that number. On CPU architectures where the host byte order is big-endian (such as PowerPC) this will return \a src with the byte order swapped; otherwise it will return \a src unmodified.*//*! \fn template <typename T> T qToLittleEndian(const void *src, qsizetype count, void *dest) \since 5.12 \relates <QtEndian> Reads \a count numbers from memory location \a src in the host byte order and stores them in little-endian representation at \a dest. On CPU architectures where the host byte order is big-endian (such as PowerPC) this will swap the byte order; otherwise it will just perform a \c memcpy from \a src to \a dest. \note Template type \c{T} can either be a quint16, qint16, quint32, qint32, quint64, or qint64. Other types of integers, e.g., qlong, are not applicable. There are no data alignment constraints for \a dest. However, \a src is expected to be naturally aligned for type \c{T}. If \a src and \a dest can be the same pointer, this function will perform an in-place swap (if necessary). If they are not the same, the memory regions must not overlap. \sa qFromLittleEndian() \sa qToBigEndian() \sa qToLittleEndian()*//*! \class QLEInteger \inmodule QtCore \brief The QLEInteger class provides platform-independent little-endian integers. \since 5.10 The template parameter \c T must be a C++ integer type: \list \li 8-bit: char, signed char, unsigned char, qint8, quint8 \li 16-bit: short, unsigned short, qint16, quint16, char16_t \li 32-bit: int, unsigned int, qint32, quint32, char32_t \li 64-bit: long long, unsigned long long, qint64, quint64 \li platform-specific size: long, unsigned long \li pointer size: qintptr, quintptr, qptrdiff \endlist \note Using this class may be slower than using native integers, so only use it when an exact endianness is needed.*//*! \fn template <typename T> QLEInteger<T>::QLEInteger(T value) Constructs a QLEInteger with the given \a value.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator=(T i) Assigns \a i to this QLEInteger and returns a reference to this QLEInteger.*//*! \fn template <typename T> QLEInteger<T>::operator T() const Returns the value of this QLEInteger as a native integer.*//*! \fn template <typename T> bool QLEInteger<T>::operator==(QLEInteger other) const Returns \c true if the value of this QLEInteger is equal to the value of \a other.*//*! \fn template <typename T> bool QLEInteger<T>::operator!=(QLEInteger other) const Returns \c true if the value of this QLEInteger is not equal to the value of \a other.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator+=(T i) Adds \a i to this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator-=(T i) Subtracts \a i from this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator*=(T i) Multiplies \a i with this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator/=(T i) Divides this QLEInteger with \a i and returns a reference to this object.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator%=(T i) Sets this QLEInteger to the remainder of a division by \a i and returns a reference to this object.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator>>=(T i) Performs a left-shift by \a i on this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator<<=(T i) Performs a right-shift by \a i on this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator|=(T i) Performs a bitwise OR with \a i onto this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator&=(T i) Performs a bitwise AND with \a i onto this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator^=(T i) Performs a bitwise XOR with \a i onto this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator++() Performs a prefix \c{++} (increment) on this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger QLEInteger<T>::operator++(int) Performs a postfix \c{++} (increment) on this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator--() Performs a prefix \c{--} (decrement) on this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger QLEInteger<T>::operator--(int) Performs a postfix \c{--} (decrement) on this QLEInteger and returns a reference to this object.*//*! \fn template <typename T> QLEInteger QLEInteger<T>::max() Returns the maximum (finite) value representable by the numeric type T.*//*! \fn template <typename T> QLEInteger QLEInteger<T>::min() Returns the minimum (finite) value representable by the numeric type T.*//*! \class QBEInteger \inmodule QtCore \brief The QBEInteger class provides platform-independent big-endian integers. \since 5.10 The template parameter \c T must be a C++ integer type: \list \li 8-bit: char, signed char, unsigned char, qint8, quint8 \li 16-bit: short, unsigned short, qint16, quint16, char16_t \li 32-bit: int, unsigned int, qint32, quint32, char32_t \li 64-bit: long long, unsigned long long, qint64, quint64 \li platform-specific size: long, unsigned long \li pointer size: qintptr, quintptr, qptrdiff \endlist \note Using this class may be slower than using native integers, so only use it when an exact endianness is needed.*//*! \fn template <typename T> QBEInteger<T>::QBEInteger(T value) Constructs a QBEInteger with the given \a value.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator=(T i) Assigns \a i to this QBEInteger and returns a reference to this QBEInteger.*//*! \fn template <typename T> QBEInteger<T>::operator T() const Returns the value of this QBEInteger as a native integer.*//*! \fn template <typename T> bool QBEInteger<T>::operator==(QBEInteger other) const Returns \c true if the value of this QBEInteger is equal to the value of \a other.*//*! \fn template <typename T> bool QBEInteger<T>::operator!=(QBEInteger other) const Returns \c true if the value of this QBEInteger is not equal to the value of \a other.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator+=(T i) Adds \a i to this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator-=(T i) Subtracts \a i from this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator*=(T i) Multiplies \a i with this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator/=(T i) Divides this QBEInteger with \a i and returns a reference to this object.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator%=(T i) Sets this QBEInteger to the remainder of a division by \a i and returns a reference to this object.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator>>=(T i) Performs a left-shift by \a i on this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator<<=(T i) Performs a right-shift by \a i on this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator|=(T i) Performs a bitwise OR with \a i onto this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator&=(T i) Performs a bitwise AND with \a i onto this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator^=(T i) Performs a bitwise XOR with \a i onto this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator++() Performs a prefix \c{++} (increment) on this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger QBEInteger<T>::operator++(int) Performs a postfix \c{++} (increment) on this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator--() Performs a prefix \c{--} (decrement) on this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger QBEInteger<T>::operator--(int) Performs a postfix \c{--} (decrement) on this QBEInteger and returns a reference to this object.*//*! \fn template <typename T> QBEInteger QBEInteger<T>::max() Returns the maximum (finite) value representable by the numeric type T.*//*! \fn template <typename T> QBEInteger QBEInteger<T>::min() Returns the minimum (finite) value representable by the numeric type T.*//*! \typedef quint16_le \relates <QtEndian> \since 5.10 Typedef for QLEInteger<quint16>. This type is guaranteed to be stored in memory as a 16-bit little-endian unsigned integer on all platforms supported by Qt. \sa quint16*//*! \typedef quint32_le \relates <QtEndian> \since 5.10 Typedef for QLEInteger<quint32>. This type is guaranteed to be stored in memory as a 32-bit little-endian unsigned integer on all platforms supported by Qt. \sa quint32*//*! \typedef quint64_le \relates <QtEndian> \since 5.10 Typedef for QLEInteger<quint64>. This type is guaranteed to be stored in memory as a 64-bit little-endian unsigned integer on all platforms supported by Qt. \sa quint64*//*! \typedef quint16_be \relates <QtEndian> \since 5.10 Typedef for QBEInteger<quint16>. This type is guaranteed to be stored in memory as a 16-bit big-endian unsigned integer on all platforms supported by Qt. \sa quint16*//*! \typedef quint32_be \relates <QtEndian> \since 5.10 Typedef for QBEInteger<quint32>. This type is guaranteed to be stored in memory as a 32-bit big-endian unsigned integer on all platforms supported by Qt. \sa quint32*//*! \typedef quint64_be \relates <QtEndian> \since 5.10 Typedef for QBEInteger<quint64>. This type is guaranteed to be stored in memory as a 64-bit big-endian unsigned integer on all platforms supported by Qt. \sa quint64*//*! \typedef qint16_le \relates <QtEndian> \since 5.10 Typedef for QLEInteger<qint16>. This type is guaranteed to be stored in memory as a 16-bit little-endian signed integer on all platforms supported by Qt. \sa qint16*//*! \typedef qint32_le \relates <QtEndian> \since 5.10 Typedef for QLEInteger<qint32>. This type is guaranteed to be stored in memory as a 32-bit little-endian signed integer on all platforms supported by Qt. \sa qint32*//*! \typedef qint64_le \relates <QtEndian> \since 5.10 Typedef for QLEInteger<qint64>. This type is guaranteed to be stored in memory as a 64-bit little-endian signed integer on all platforms supported by Qt. \sa qint64*//*! \typedef qint16_be \relates <QtEndian> \since 5.10 Typedef for QBEInteger<qint16>. This type is guaranteed to be stored in memory as a 16-bit big-endian signed integer on all platforms supported by Qt. \sa qint16*//*! \typedef qint32_be \relates <QtEndian> \since 5.10 Typedef for QBEInteger<qint32>. This type is guaranteed to be stored in memory as a 32-bit big-endian signed integer on all platforms supported by Qt. \sa qint32*//*! \typedef qint64_be \relates <QtEndian> \since 5.10 Typedef for QBEInteger<qint64>. This type is guaranteed to be stored in memory as a 64-bit big-endian signed integer on all platforms supported by Qt. \sa qint64*/#if defined(__SSSE3__)using ShuffleMask = uchar[16];alignas(16)static const ShuffleMask shuffleMasks[3] = {// 16-bit{1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14},// 32-bit{3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12},// 64-bit{7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8}};static size_tsseSwapLoop(const uchar *src,size_t bytes, uchar *dst,const __m128i *shuffleMaskPtr) noexcept {size_t i =0;const __m128i shuffleMask =_mm_load_si128(shuffleMaskPtr);# ifdef __AVX2__const __m256i shuffleMask256 =_mm256_inserti128_si256(_mm256_castsi128_si256(shuffleMask), shuffleMask,1);for( ; i +sizeof(__m256i) <= bytes; i +=sizeof(__m256i)) { __m256i data =_mm256_loadu_si256(reinterpret_cast<const __m256i *>(src + i)); data =_mm256_shuffle_epi8(data, shuffleMask256);_mm256_storeu_si256(reinterpret_cast<__m256i *>(dst + i), data);}# elsefor( ; i +2*sizeof(__m128i) <= bytes; i +=2*sizeof(__m128i)) { __m128i data1 =_mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i)); __m128i data2 =_mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i) +1); data1 =_mm_shuffle_epi8(data1, shuffleMask); data2 =_mm_shuffle_epi8(data2, shuffleMask);_mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data1);_mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i) +1, data2);}# endifif(i +sizeof(__m128i) <= bytes) { __m128i data =_mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i)); data =_mm_shuffle_epi8(data, shuffleMask);_mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data); i +=sizeof(__m128i);}return i;}template<typename T>static Q_ALWAYS_INLINE size_tsimdSwapLoop(const uchar *src,size_t bytes, uchar *dst) noexcept {auto shuffleMaskPtr =reinterpret_cast<const __m128i *>(shuffleMasks[0]); shuffleMaskPtr +=qCountTrailingZeroBits(sizeof(T)) -1;size_t i =sseSwapLoop(src, bytes, dst, shuffleMaskPtr);// epiloguefor(size_t _i =0; i < bytes && _i <sizeof(__m128i); i +=sizeof(T), _i +=sizeof(T))qbswap(qFromUnaligned<T>(src + i), dst + i);// return the total, so the bswapLoop below does nothingreturn bytes;}#elif defined(__SSE2__)template<typename T>staticsize_tsimdSwapLoop(const uchar *,size_t, uchar *) noexcept {// no generic version: we can't do 32- and 64-bit swaps easily,// so we won't tryreturn0;}template<>size_t simdSwapLoop<quint16>(const uchar *src,size_t bytes, uchar *dst) noexcept {auto swapEndian = [](__m128i &data) { __m128i lows =_mm_srli_epi16(data,8); __m128i highs =_mm_slli_epi16(data,8); data =_mm_xor_si128(lows, highs);};size_t i =0;for( ; i +2*sizeof(__m128i) <= bytes; i +=2*sizeof(__m128i)) { __m128i data1 =_mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i)); __m128i data2 =_mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i) +1);swapEndian(data1);swapEndian(data2);_mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data1);_mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i) +1, data2);}if(i +sizeof(__m128i) <= bytes) { __m128i data =_mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i));swapEndian(data);_mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data); i +=sizeof(__m128i);}// epiloguefor(size_t _i =0; i < bytes && _i <sizeof(__m128i); i +=sizeof(quint16), _i +=sizeof(quint16))qbswap(qFromUnaligned<quint16>(src + i), dst + i);// return the total, so the bswapLoop below does nothingreturn bytes;}#elsetemplate<typename T>static Q_ALWAYS_INLINE size_tsimdSwapLoop(const uchar *,size_t, uchar *) noexcept {return0;}#endiftemplate<typename T> Q_ALWAYS_INLINE staticvoid*bswapLoop(const uchar *src,size_t n, uchar *dst) noexcept {// Buffers cannot partially overlap: either they're identical or totally// disjoint (note: they can be adjacent).if(src != dst) { quintptr s =quintptr(src); quintptr d =quintptr(dst);if(s < d)Q_ASSERT(s + n <= d);elseQ_ASSERT(d + n <= s);}size_t i = simdSwapLoop<T>(src, n, dst);for(; i < n; i +=sizeof(T))qbswap(qFromUnaligned<T>(src + i), dst + i);return dst + i;}template<>void*qbswap<2>(const void*source, qsizetype n,void*dest) noexcept {const uchar *src =reinterpret_cast<const uchar *>(source); uchar *dst =reinterpret_cast<uchar *>(dest);return bswapLoop<quint16>(src, n <<1, dst);}template<>void*qbswap<4>(const void*source, qsizetype n,void*dest) noexcept {const uchar *src =reinterpret_cast<const uchar *>(source); uchar *dst =reinterpret_cast<uchar *>(dest);return bswapLoop<quint32>(src, n <<2, dst);}template<>void*qbswap<8>(const void*source, qsizetype n,void*dest) noexcept {const uchar *src =reinterpret_cast<const uchar *>(source); uchar *dst =reinterpret_cast<uchar *>(dest);return bswapLoop<quint64>(src, n <<3, dst);} QT_END_NAMESPACE
|