Add qbswap for a memory region
The compiler was generating some vectorized code for qresource.cpp but it wasn't very efficient. So improve upon it and make use in other places where we read UTF-16BE strings. [ChangeLog][QtCore] Added an overload of q{To,From}{Big,Little}Endian that operates on a memory region. Change-Id: I6a540578e810472bb455fffd1531fa2f1d724dfc Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
parent
c053f9d154
commit
d0427759c6
@ -18,7 +18,7 @@ OBJS = \
|
||||
#qt code (please keep in order matching DEPEND_SRC)
|
||||
QOBJS = \
|
||||
qtextcodec.o qutfcodec.o \
|
||||
qglobal.o qlogging.o qmalloc.o qnumeric.o qoperatingsystemversion.o qrandom.o \
|
||||
qendian.o qglobal.o qlogging.o qmalloc.o qnumeric.o qoperatingsystemversion.o qrandom.o \
|
||||
qabstractfileengine.o qbuffer.o qdatastream.o qdebug.o \
|
||||
qdir.o qdiriterator.o \
|
||||
qfile.o qfiledevice.o qfileinfo.o qfilesystemengine.o \
|
||||
@ -68,6 +68,7 @@ DEPEND_SRC = \
|
||||
$(QMKGENSRC)/xmloutput.cpp \
|
||||
$(SOURCE_PATH)/src/corelib/codecs/qtextcodec.cpp \
|
||||
$(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp \
|
||||
$(SOURCE_PATH)/src/corelib/global/qendian.cpp \
|
||||
$(SOURCE_PATH)/src/corelib/global/qglobal.cpp \
|
||||
$(SOURCE_PATH)/src/corelib/global/qlibraryinfo.cpp \
|
||||
$(SOURCE_PATH)/src/corelib/global/qlogging.cpp \
|
||||
@ -295,6 +296,9 @@ qdebug.o: $(SOURCE_PATH)/src/corelib/io/qdebug.cpp
|
||||
qmalloc.o: $(SOURCE_PATH)/src/corelib/global/qmalloc.cpp
|
||||
$(CXX) -c -o $@ $(CXXFLAGS) $<
|
||||
|
||||
qendian.o: $(SOURCE_PATH)/src/corelib/global/qendian.cpp
|
||||
$(CXX) -c -o $@ $(CXXFLAGS) $<
|
||||
|
||||
qglobal.o: $(SOURCE_PATH)/src/corelib/global/qglobal.cpp
|
||||
$(CXX) -c -o $@ $(CXXFLAGS) $<
|
||||
|
||||
|
@ -83,6 +83,7 @@ QTOBJS= \
|
||||
qfsfileengine_win.obj \
|
||||
qsystemlibrary.obj \
|
||||
qfileinfo.obj \
|
||||
qendian.obj \
|
||||
qglobal.obj \
|
||||
qhash.obj \
|
||||
qiodevice.obj \
|
||||
|
@ -29,6 +29,7 @@ HEADERS += \
|
||||
|
||||
SOURCES += \
|
||||
global/archdetect.cpp \
|
||||
global/qendian.cpp \
|
||||
global/qglobal.cpp \
|
||||
global/qlibraryinfo.cpp \
|
||||
global/qmalloc.cpp \
|
||||
|
@ -1,11 +1,12 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2018 Intel Corporation.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the documentation of the Qt Toolkit.
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:FDL$
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
@ -14,17 +15,36 @@
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qendian.h"
|
||||
|
||||
#include "qalgorithms.h"
|
||||
#include <private/qsimd_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*!
|
||||
\headerfile <QtEndian>
|
||||
\title Endian Conversion Functions
|
||||
@ -89,6 +109,32 @@
|
||||
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> T qFromLittleEndian(const void *src)
|
||||
\since 4.3
|
||||
@ -122,6 +168,32 @@
|
||||
will return \a src with the byte order swapped; otherwise it will return \a src
|
||||
unmodified.
|
||||
*/
|
||||
/*!
|
||||
\fn template <typename T> 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 qFromLittleEndian()
|
||||
\sa qToBigEndian()
|
||||
\sa qToLittleEndian()
|
||||
*/
|
||||
/*!
|
||||
\fn template <typename T> void qToBigEndian(T src, void *dest)
|
||||
\since 4.3
|
||||
@ -152,6 +224,32 @@
|
||||
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
|
||||
@ -182,6 +280,32 @@
|
||||
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
|
||||
@ -552,3 +676,158 @@
|
||||
|
||||
\sa qint64
|
||||
*/
|
||||
|
||||
#if defined(__SSSE3__)
|
||||
using ShuffleMask = uchar[16];
|
||||
Q_DECL_ALIGN(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_t sseSwapLoop(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);
|
||||
}
|
||||
# else
|
||||
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);
|
||||
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);
|
||||
}
|
||||
# endif
|
||||
|
||||
if (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_t simdSwapLoop(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);
|
||||
|
||||
// epilogue
|
||||
for (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 nothing
|
||||
return bytes;
|
||||
}
|
||||
#elif defined(__SSE2__)
|
||||
template <typename T> static
|
||||
size_t simdSwapLoop(const uchar *, size_t, uchar *) noexcept
|
||||
{
|
||||
// no generic version: we can't do 32- and 64-bit swaps easily,
|
||||
// so we won't try
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// epilogue
|
||||
for (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 nothing
|
||||
return bytes;
|
||||
}
|
||||
#else
|
||||
template <typename T> static Q_ALWAYS_INLINE
|
||||
size_t simdSwapLoop(const uchar *, size_t, uchar *) noexcept
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T> static Q_ALWAYS_INLINE
|
||||
void *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);
|
||||
else
|
||||
Q_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
|
||||
|
@ -157,6 +157,14 @@ template <typename T> inline void qbswap(const T src, void *dest)
|
||||
qToUnaligned<T>(qbswap<T>(src), dest);
|
||||
}
|
||||
|
||||
template <int Size> void *qbswap(const void *source, qsizetype count, void *dest) noexcept;
|
||||
template<> inline void *qbswap<1>(const void *source, qsizetype count, void *dest) noexcept
|
||||
{
|
||||
return source != dest ? memcpy(dest, source, size_t(count)) : dest;
|
||||
}
|
||||
template<> Q_CORE_EXPORT void *qbswap<2>(const void *source, qsizetype count, void *dest) noexcept;
|
||||
template<> Q_CORE_EXPORT void *qbswap<4>(const void *source, qsizetype count, void *dest) noexcept;
|
||||
template<> Q_CORE_EXPORT void *qbswap<8>(const void *source, qsizetype count, void *dest) noexcept;
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
|
||||
@ -172,6 +180,15 @@ template <typename T> inline void qToBigEndian(T src, void *dest)
|
||||
{ qToUnaligned<T>(src, dest); }
|
||||
template <typename T> inline void qToLittleEndian(T src, void *dest)
|
||||
{ qbswap<T>(src, dest); }
|
||||
|
||||
template <typename T> inline void qToBigEndian(const void *source, qsizetype count, void *dest)
|
||||
{ if (source != dest) memcpy(dest, source, count * sizeof(T)); }
|
||||
template <typename T> inline void qToLittleEndian(const void *source, qsizetype count, void *dest)
|
||||
{ qbswap<sizeof(T)>(source, count, dest); }
|
||||
template <typename T> inline void qFromBigEndian(const void *source, qsizetype count, void *dest)
|
||||
{ if (source != dest) memcpy(dest, source, count * sizeof(T)); }
|
||||
template <typename T> inline void qFromLittleEndian(const void *source, qsizetype count, void *dest)
|
||||
{ qbswap<sizeof(T)>(source, count, dest); }
|
||||
#else // Q_LITTLE_ENDIAN
|
||||
|
||||
template <typename T> inline Q_DECL_CONSTEXPR T qToBigEndian(T source)
|
||||
@ -187,6 +204,14 @@ template <typename T> inline void qToBigEndian(T src, void *dest)
|
||||
template <typename T> inline void qToLittleEndian(T src, void *dest)
|
||||
{ qToUnaligned<T>(src, dest); }
|
||||
|
||||
template <typename T> inline void qToBigEndian(const void *source, qsizetype count, void *dest)
|
||||
{ qbswap<sizeof(T)>(source, count, dest); }
|
||||
template <typename T> inline void qToLittleEndian(const void *source, qsizetype count, void *dest)
|
||||
{ if (source != dest) memcpy(dest, source, count * sizeof(T)); }
|
||||
template <typename T> inline void qFromBigEndian(const void *source, qsizetype count, void *dest)
|
||||
{ qbswap<sizeof(T)>(source, count, dest); }
|
||||
template <typename T> inline void qFromLittleEndian(const void *source, qsizetype count, void *dest)
|
||||
{ if (source != dest) memcpy(dest, source, count * sizeof(T)); }
|
||||
#endif // Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
|
||||
|
||||
|
@ -52,7 +52,9 @@
|
||||
#include "qendian.h"
|
||||
#include <qshareddata.h>
|
||||
#include <qplatformdefs.h>
|
||||
#include <qendian.h>
|
||||
#include "private/qabstractfileengine_p.h"
|
||||
#include "private/qsimd_p.h"
|
||||
#include "private/qsystemerror_p.h"
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
@ -629,17 +631,13 @@ inline QString QResourceRoot::name(int node) const
|
||||
|
||||
QString ret;
|
||||
qint32 name_offset = qFromBigEndian<qint32>(tree + offset);
|
||||
const qint16 name_length = qFromBigEndian<qint16>(names + name_offset);
|
||||
quint16 name_length = qFromBigEndian<qint16>(names + name_offset);
|
||||
name_offset += 2;
|
||||
name_offset += 4; //jump past hash
|
||||
|
||||
ret.resize(name_length);
|
||||
QChar *strData = ret.data();
|
||||
for(int i = 0; i < name_length*2; i+=2) {
|
||||
QChar c(names[name_offset+i+1], names[name_offset+i]);
|
||||
*strData = c;
|
||||
++strData;
|
||||
}
|
||||
qFromBigEndian<ushort>(names + name_offset, name_length, strData);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "qcoreapplication.h"
|
||||
#include "qcoreapplication_p.h"
|
||||
#include "qdatastream.h"
|
||||
#include "qendian.h"
|
||||
#include "qfile.h"
|
||||
#include "qmap.h"
|
||||
#include "qalgorithms.h"
|
||||
@ -957,8 +958,8 @@ end:
|
||||
return QString();
|
||||
QString str = QString((const QChar *)tn, tn_length/2);
|
||||
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
|
||||
for (int i = 0; i < str.length(); ++i)
|
||||
str[i] = QChar((str.at(i).unicode() >> 8) + ((str.at(i).unicode() << 8) & 0xff00));
|
||||
QChar *data = str.data();
|
||||
qbswap<sizeof(QChar)>(data, str.length(), data);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
@ -9946,11 +9946,7 @@ QDataStream &operator<<(QDataStream &out, const QString &str)
|
||||
out.writeBytes(reinterpret_cast<const char *>(str.unicode()), sizeof(QChar) * str.length());
|
||||
} else {
|
||||
QVarLengthArray<ushort> buffer(str.length());
|
||||
const ushort *data = reinterpret_cast<const ushort *>(str.constData());
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
buffer[i] = qbswap(*data);
|
||||
++data;
|
||||
}
|
||||
qbswap<sizeof(ushort)>(str.constData(), str.length(), buffer.data());
|
||||
out.writeBytes(reinterpret_cast<const char *>(buffer.data()), sizeof(ushort) * buffer.size());
|
||||
}
|
||||
} else {
|
||||
@ -10007,10 +10003,7 @@ QDataStream &operator>>(QDataStream &in, QString &str)
|
||||
if ((in.byteOrder() == QDataStream::BigEndian)
|
||||
!= (QSysInfo::ByteOrder == QSysInfo::BigEndian)) {
|
||||
ushort *data = reinterpret_cast<ushort *>(str.data());
|
||||
while (len--) {
|
||||
*data = qbswap(*data);
|
||||
++data;
|
||||
}
|
||||
qbswap<sizeof(*data)>(data, len, data);
|
||||
}
|
||||
} else {
|
||||
str = QString(QLatin1String(""));
|
||||
|
@ -25,6 +25,7 @@ SOURCES += \
|
||||
../../corelib/codecs/qlatincodec.cpp \
|
||||
../../corelib/codecs/qtextcodec.cpp \
|
||||
../../corelib/codecs/qutfcodec.cpp \
|
||||
../../corelib/global/qendian.cpp \
|
||||
../../corelib/global/qglobal.cpp \
|
||||
../../corelib/global/qlogging.cpp \
|
||||
../../corelib/global/qmalloc.cpp \
|
||||
|
@ -39,9 +39,17 @@ class tst_QtEndian: public QObject
|
||||
private slots:
|
||||
void fromBigEndian();
|
||||
void fromLittleEndian();
|
||||
void fromBigEndianRegion_data();
|
||||
void fromBigEndianRegion();
|
||||
void fromLittleEndianRegion_data() { fromBigEndianRegion_data(); }
|
||||
void fromLittleEndianRegion();
|
||||
|
||||
void toBigEndian();
|
||||
void toLittleEndian();
|
||||
void toBigEndianRegion_data() { fromBigEndianRegion_data(); }
|
||||
void toBigEndianRegion();
|
||||
void toLittleEndianRegion_data() { fromBigEndianRegion_data(); }
|
||||
void toLittleEndianRegion();
|
||||
|
||||
void endianIntegers_data();
|
||||
void endianIntegers();
|
||||
@ -59,6 +67,12 @@ struct TestData
|
||||
quint8 reserved;
|
||||
};
|
||||
|
||||
template <typename T> T getData(const TestData &d);
|
||||
template <> quint8 getData(const TestData &d) { return d.data8; }
|
||||
template <> quint16 getData(const TestData &d) { return d.data16; }
|
||||
template <> quint32 getData(const TestData &d) { return d.data32; }
|
||||
template <> quint64 getData(const TestData &d) { return d.data64; }
|
||||
|
||||
union RawTestData
|
||||
{
|
||||
uchar rawData[sizeof(TestData)];
|
||||
@ -108,6 +122,106 @@ void tst_QtEndian::fromLittleEndian()
|
||||
|
||||
#undef ENDIAN_TEST
|
||||
|
||||
template <typename T>
|
||||
void transformRegion_template(T (*transformOne)(T), void (*transformRegion)(const void *, qsizetype, void *))
|
||||
{
|
||||
enum { Size = 64 };
|
||||
T source[Size];
|
||||
T dest[Size];
|
||||
T expected = transformOne(getData<T>(inNativeEndian));
|
||||
std::fill_n(source, +Size, getData<T>(inNativeEndian));
|
||||
memset(dest, 0, sizeof(dest));
|
||||
|
||||
auto checkBounds = [&](int from) {
|
||||
for ( ; from < Size; ++from)
|
||||
QCOMPARE(dest[from], 0);
|
||||
};
|
||||
|
||||
transformRegion(source, 1, dest);
|
||||
QCOMPARE(dest[0], expected);
|
||||
checkBounds(1);
|
||||
memset(dest, 0, sizeof(T));
|
||||
|
||||
transformRegion(source, 2, dest);
|
||||
QCOMPARE(dest[0], expected);
|
||||
QCOMPARE(dest[1], expected);
|
||||
checkBounds(2);
|
||||
memset(dest, 0, sizeof(T) * 2);
|
||||
|
||||
transformRegion(source, 3, dest);
|
||||
QCOMPARE(dest[0], expected);
|
||||
QCOMPARE(dest[1], expected);
|
||||
QCOMPARE(dest[2], expected);
|
||||
checkBounds(3);
|
||||
memset(dest, 0, sizeof(T) * 3);
|
||||
|
||||
transformRegion(source, 4, dest);
|
||||
QCOMPARE(dest[0], expected);
|
||||
QCOMPARE(dest[1], expected);
|
||||
QCOMPARE(dest[2], expected);
|
||||
QCOMPARE(dest[3], expected);
|
||||
checkBounds(4);
|
||||
memset(dest, 0, sizeof(T) * 4);
|
||||
|
||||
transformRegion(source, 8, dest);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
QCOMPARE(dest[i], expected);
|
||||
checkBounds(8);
|
||||
memset(dest, 0, sizeof(T) * 8);
|
||||
|
||||
transformRegion(source, 16, dest);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
QCOMPARE(dest[i], expected);
|
||||
checkBounds(16);
|
||||
memset(dest, 0, sizeof(T) * 16);
|
||||
|
||||
transformRegion(source, 32, dest);
|
||||
for (int i = 0; i < 32; ++i)
|
||||
QCOMPARE(dest[i], expected);
|
||||
checkBounds(32);
|
||||
memset(dest, 0, sizeof(T) * 32);
|
||||
|
||||
transformRegion(source, 64, dest);
|
||||
for (int i = 0; i < 64; ++i)
|
||||
QCOMPARE(dest[i], expected);
|
||||
|
||||
// check transforming in-place
|
||||
memcpy(dest, source, sizeof(dest));
|
||||
transformRegion(dest, 64, dest);
|
||||
for (int i = 0; i < 64; ++i)
|
||||
QCOMPARE(dest[i], expected);
|
||||
}
|
||||
|
||||
void tst_QtEndian::fromBigEndianRegion_data()
|
||||
{
|
||||
QTest::addColumn<int>("size");
|
||||
QTest::newRow("1") << 1;
|
||||
QTest::newRow("2") << 2;
|
||||
QTest::newRow("4") << 4;
|
||||
QTest::newRow("8") << 8;
|
||||
}
|
||||
|
||||
void tst_QtEndian::fromBigEndianRegion()
|
||||
{
|
||||
QFETCH(int, size);
|
||||
switch (size) {
|
||||
case 1: return transformRegion_template<quint8>(qFromBigEndian<quint8>, qFromBigEndian<quint8>);
|
||||
case 2: return transformRegion_template<quint16>(qFromBigEndian<quint16>, qFromBigEndian<quint16>);
|
||||
case 4: return transformRegion_template<quint32>(qFromBigEndian<quint32>, qFromBigEndian<quint32>);
|
||||
case 8: return transformRegion_template<quint64>(qFromBigEndian<quint64>, qFromBigEndian<quint64>);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QtEndian::fromLittleEndianRegion()
|
||||
{
|
||||
QFETCH(int, size);
|
||||
switch (size) {
|
||||
case 1: return transformRegion_template<quint8>(qFromLittleEndian<quint8>, qFromLittleEndian<quint8>);
|
||||
case 2: return transformRegion_template<quint16>(qFromLittleEndian<quint16>, qFromLittleEndian<quint16>);
|
||||
case 4: return transformRegion_template<quint32>(qFromLittleEndian<quint32>, qFromLittleEndian<quint32>);
|
||||
case 8: return transformRegion_template<quint64>(qFromLittleEndian<quint64>, qFromLittleEndian<quint64>);
|
||||
}
|
||||
}
|
||||
|
||||
#define ENDIAN_TEST(endian, type, size) \
|
||||
do { \
|
||||
@ -135,6 +249,28 @@ void tst_QtEndian::toLittleEndian()
|
||||
|
||||
#undef ENDIAN_TEST
|
||||
|
||||
void tst_QtEndian::toBigEndianRegion()
|
||||
{
|
||||
QFETCH(int, size);
|
||||
switch (size) {
|
||||
case 1: return transformRegion_template<quint8>(qToBigEndian<quint8>, qToBigEndian<quint8>);
|
||||
case 2: return transformRegion_template<quint16>(qToBigEndian<quint16>, qToBigEndian<quint16>);
|
||||
case 4: return transformRegion_template<quint32>(qToBigEndian<quint32>, qToBigEndian<quint32>);
|
||||
case 8: return transformRegion_template<quint64>(qToBigEndian<quint64>, qToBigEndian<quint64>);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QtEndian::toLittleEndianRegion()
|
||||
{
|
||||
QFETCH(int, size);
|
||||
switch (size) {
|
||||
case 1: return transformRegion_template<quint8>(qToLittleEndian<quint8>, qToLittleEndian<quint8>);
|
||||
case 2: return transformRegion_template<quint16>(qToLittleEndian<quint16>, qToLittleEndian<quint16>);
|
||||
case 4: return transformRegion_template<quint32>(qToLittleEndian<quint32>, qToLittleEndian<quint32>);
|
||||
case 8: return transformRegion_template<quint64>(qToLittleEndian<quint64>, qToLittleEndian<quint64>);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QtEndian::endianIntegers_data()
|
||||
{
|
||||
QTest::addColumn<int>("val");
|
||||
|
Loading…
x
Reference in New Issue
Block a user