Add the UTF16-to-Latin1 in-place converter

This is only possible for two important reasons:

1) QString and QByteArray d pointers are both done with QArrayData and
   that class does not care that the alignof(T) changes from 2 to 1,
   so we can give the pointer from QString to QByteArray
   (after adapting the allocated size, which is now double)

2) conversion from UTF16 to Latin1 always has fewer bytes (exactly half)

Change-Id: I17b2690c910f3de8db55156c6d6b5f55be06d827
Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
Thiago Macieira 2013-10-10 19:43:22 -07:00 committed by The Qt Project
parent 8892e3d0fc
commit ee7536876c
3 changed files with 40 additions and 1 deletions

View File

@ -4020,6 +4020,36 @@ QByteArray QString::toLatin1_helper(const QChar *data, int length)
return ba;
}
QByteArray QString::toLatin1_helper_inplace(QString &s)
{
if (!s.isDetached())
return s.toLatin1();
// We can return our own buffer to the caller.
// Conversion to Latin-1 always shrinks the buffer by half.
const ushort *data = reinterpret_cast<const ushort *>(s.constData());
uint length = s.size();
// Swap the d pointers.
// Kids, avert your eyes. Don't try this at home.
QArrayData *ba_d = s.d;
// multiply the allocated capacity by sizeof(ushort)
ba_d->alloc *= sizeof(ushort);
// reset ourselves to QString()
s.d = QString().d;
// do the in-place conversion
uchar *dst = reinterpret_cast<uchar *>(ba_d->data());
QT_PREPEND_NAMESPACE(toLatin1_helper)(dst, data, length);
dst[length] = '\0';
QByteArrayDataPtr badptr = { ba_d };
return QByteArray(badptr);
}
/*!
\fn QByteArray QString::toLatin1() const

View File

@ -481,7 +481,7 @@ public:
QByteArray toLatin1() const & Q_REQUIRED_RESULT
{ return toLatin1_helper(*this); }
QByteArray toLatin1() && Q_REQUIRED_RESULT
{ return toLatin1_helper(reinterpret_cast<const ushort *>(constData()), size()); }
{ return toLatin1_helper_inplace(*this); }
QByteArray toUtf8() const & Q_REQUIRED_RESULT
{ return toUtf8_helper(*this); }
QByteArray toUtf8() && Q_REQUIRED_RESULT
@ -751,6 +751,7 @@ private:
static QString fromLocal8Bit_helper(const char *, int size);
static QByteArray toLatin1_helper(const QString &);
static QByteArray toLatin1_helper(const QChar *data, int size);
static QByteArray toLatin1_helper_inplace(QString &);
static QByteArray toUtf8_helper(const QString &);
static QByteArray toLocal8Bit_helper(const QChar *data, int size);
static int toUcs4_helper(const ushort *uc, int length, uint *out);

View File

@ -3882,6 +3882,14 @@ void tst_QString::toLatin1Roundtrip()
// and back:
QCOMPARE(QString::fromLatin1(latin1, latin1.length()).length(), unicodedst.length());
QCOMPARE(QString::fromLatin1(latin1, latin1.length()), unicodedst);
// try the rvalue version of toLatin1()
QString s = unicodesrc;
QCOMPARE(qMove(s).toLatin1(), latin1);
// and verify that the moved-from object can still be used
s = "foo";
s.clear();
}
void tst_QString::stringRef_toLatin1Roundtrip_data()