QString/QByteArray: add lvalue and rvalue overloads of left/mid/right

The first/last/sliced API may be what we suggest users use, but the vast
majority of the installed codebase uses left/mid/right because they've
been available since time immemorial.

An additional benefit of this is to make left() and right() available as
inline methods.

Change-Id: Ifeb6206a9fa04424964bfffd1788383817ed906c
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
bb10
Thiago Macieira 2023-09-25 11:37:53 -07:00
parent 1cce2cceff
commit 2fefc8c63c
7 changed files with 469 additions and 45 deletions

View File

@ -620,6 +620,44 @@ QStringView QXmlStreamAttributes::value(QLatin1StringView qualifiedName) const
#include "qbytearray.h"
QByteArray QByteArray::left(qsizetype len) const
{
if (len >= size())
return *this;
if (len < 0)
len = 0;
return QByteArray(data(), len);
}
QByteArray QByteArray::right(qsizetype len) const
{
if (len >= size())
return *this;
if (len < 0)
len = 0;
return QByteArray(end() - len, len);
}
QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
{
qsizetype p = pos;
qsizetype l = len;
using namespace QtPrivate;
switch (QContainerImplHelper::mid(size(), &p, &l)) {
case QContainerImplHelper::Null:
return QByteArray();
case QContainerImplHelper::Empty:
{
return QByteArray(DataPointer::fromRawData(&_empty, 0));
}
case QContainerImplHelper::Full:
return *this;
case QContainerImplHelper::Subset:
return QByteArray(d.data() + p, l);
}
Q_UNREACHABLE_RETURN(QByteArray());
}
#ifdef Q_CC_MSVC
// previously inline methods, only needed for MSVC compat
QByteArray QByteArray::first(qsizetype n) const
@ -744,6 +782,38 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
#include "qstring.h"
QString QString::left(qsizetype n) const
{
if (size_t(n) >= size_t(size()))
return *this;
return QString((const QChar*) d.data(), n);
}
QString QString::right(qsizetype n) const
{
if (size_t(n) >= size_t(size()))
return *this;
return QString(constData() + size() - n, n);
}
QString QString::mid(qsizetype position, qsizetype n) const
{
qsizetype p = position;
qsizetype l = n;
using namespace QtPrivate;
switch (QContainerImplHelper::mid(size(), &p, &l)) {
case QContainerImplHelper::Null:
return QString();
case QContainerImplHelper::Empty:
return QString(DataPointer::fromRawData(&_empty, 0));
case QContainerImplHelper::Full:
return *this;
case QContainerImplHelper::Subset:
return QString(constData() + p, l);
}
Q_UNREACHABLE_RETURN(QString());
}
#ifdef Q_CC_MSVC
// previously inline methods, only needed for MSVC compat
QString QString::first(qsizetype n) const

View File

@ -3022,6 +3022,9 @@ bool QByteArray::isLower() const
*/
/*!
\fn QByteArray QByteArray::left(qsizetype len) const &
\fn QByteArray QByteArray::left(qsizetype len) &&
Returns a byte array that contains the first \a len bytes of this byte
array.
@ -3036,16 +3039,10 @@ bool QByteArray::isLower() const
\sa first(), last(), startsWith(), chopped(), chop(), truncate()
*/
QByteArray QByteArray::left(qsizetype len) const
{
if (len >= size())
return *this;
if (len < 0)
len = 0;
return QByteArray(data(), len);
}
/*!
\fn QByteArray QByteArray::right(qsizetype len) const &
\fn QByteArray QByteArray::right(qsizetype len) &&
Returns a byte array that contains the last \a len bytes of this byte array.
If you know that \a len cannot be out of bounds, use last() instead in new
@ -3058,16 +3055,11 @@ QByteArray QByteArray::left(qsizetype len) const
\sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate()
*/
QByteArray QByteArray::right(qsizetype len) const
{
if (len >= size())
return *this;
if (len < 0)
len = 0;
return QByteArray(end() - len, len);
}
/*!
\fn QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const &
\fn QByteArray QByteArray::mid(qsizetype pos, qsizetype len) &&
Returns a byte array containing \a len bytes from this byte array,
starting at position \a pos.
@ -3081,7 +3073,7 @@ QByteArray QByteArray::right(qsizetype len) const
\sa first(), last(), sliced(), chopped(), chop(), truncate()
*/
QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const &
{
qsizetype p = pos;
qsizetype l = len;
@ -3096,7 +3088,26 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
case QContainerImplHelper::Full:
return *this;
case QContainerImplHelper::Subset:
return QByteArray(d.data() + p, l);
return sliced(p, l);
}
Q_UNREACHABLE_RETURN(QByteArray());
}
QByteArray QByteArray::mid(qsizetype pos, qsizetype len) &&
{
qsizetype p = pos;
qsizetype l = len;
using namespace QtPrivate;
switch (QContainerImplHelper::mid(size(), &p, &l)) {
case QContainerImplHelper::Null:
return QByteArray();
case QContainerImplHelper::Empty:
resize(0); // keep capacity if we've reserve()d
[[fallthrough]];
case QContainerImplHelper::Full:
return std::move(*this);
case QContainerImplHelper::Subset:
return std::move(*this).sliced(p, l);
}
Q_UNREACHABLE_RETURN(QByteArray());
}

View File

@ -151,17 +151,43 @@ public:
inline int compare(QByteArrayView a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
[[nodiscard]] QByteArray left(qsizetype len) const;
[[nodiscard]] QByteArray right(qsizetype len) const;
[[nodiscard]] QByteArray mid(qsizetype index, qsizetype len = -1) const;
#if QT_CORE_REMOVED_SINCE(6, 7)
QByteArray left(qsizetype len) const;
QByteArray right(qsizetype len) const;
QByteArray mid(qsizetype index, qsizetype len = -1) const;
QByteArray first(qsizetype n) const;
QByteArray last(qsizetype n) const;
QByteArray sliced(qsizetype pos) const;
QByteArray sliced(qsizetype pos, qsizetype n) const;
QByteArray chopped(qsizetype len) const;
#else
[[nodiscard]] QByteArray left(qsizetype n) const &
{
if (n >= size())
return *this;
return first(qMax(n, 0));
}
[[nodiscard]] QByteArray left(qsizetype n) &&
{
if (n >= size())
return std::move(*this);
return std::move(*this).first(qMax(n, 0));
}
[[nodiscard]] QByteArray right(qsizetype n) const &
{
if (n >= size())
return *this;
return last(qMax(n, 0));
}
[[nodiscard]] QByteArray right(qsizetype n) &&
{
if (n >= size())
return std::move(*this);
return std::move(*this).last(qMax(n, 0));
}
[[nodiscard]] QByteArray mid(qsizetype index, qsizetype len = -1) const &;
[[nodiscard]] QByteArray mid(qsizetype index, qsizetype len = -1) &&;
[[nodiscard]] QByteArray first(qsizetype n) const &
{ verify(0, n); return sliced(0, n); }
[[nodiscard]] QByteArray last(qsizetype n) const &

View File

@ -5149,6 +5149,9 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp
#endif // QT_CONFIG(regularexpression)
/*!
\fn QString QString::left(qsizetype n) const &
\fn QString QString::left(qsizetype n) &&
Returns a substring that contains the \a n leftmost characters
of the string.
@ -5160,14 +5163,11 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp
\sa first(), last(), startsWith(), chopped(), chop(), truncate()
*/
QString QString::left(qsizetype n) const
{
if (size_t(n) >= size_t(size()))
return *this;
return QString((const QChar*) d.data(), n);
}
/*!
\fn QString QString::right(qsizetype n) const &
\fn QString QString::right(qsizetype n) &&
Returns a substring that contains the \a n rightmost characters
of the string.
@ -5179,14 +5179,11 @@ QString QString::left(qsizetype n) const
\sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate()
*/
QString QString::right(qsizetype n) const
{
if (size_t(n) >= size_t(size()))
return *this;
return QString(constData() + size() - n, n);
}
/*!
\fn QString QString::mid(qsizetype position, qsizetype n) const &
\fn QString QString::mid(qsizetype position, qsizetype n) &&
Returns a string that contains \a n characters of this string,
starting at the specified \a position index.
@ -5199,11 +5196,9 @@ QString QString::right(qsizetype n) const
\a n is -1 (default), the function returns all characters that
are available from the specified \a position.
\sa first(), last(), sliced(), chopped(), chop(), truncate()
*/
QString QString::mid(qsizetype position, qsizetype n) const
QString QString::mid(qsizetype position, qsizetype n) const &
{
qsizetype p = position;
qsizetype l = n;
@ -5216,7 +5211,26 @@ QString QString::mid(qsizetype position, qsizetype n) const
case QContainerImplHelper::Full:
return *this;
case QContainerImplHelper::Subset:
return QString(constData() + p, l);
return sliced(p, l);
}
Q_UNREACHABLE_RETURN(QString());
}
QString QString::mid(qsizetype position, qsizetype n) &&
{
qsizetype p = position;
qsizetype l = n;
using namespace QtPrivate;
switch (QContainerImplHelper::mid(size(), &p, &l)) {
case QContainerImplHelper::Null:
return QString();
case QContainerImplHelper::Empty:
resize(0); // keep capacity if we've reserve()d
[[fallthrough]];
case QContainerImplHelper::Full:
return std::move(*this);
case QContainerImplHelper::Subset:
return std::move(*this).sliced(p, l);
}
Q_UNREACHABLE_RETURN(QString());
}

View File

@ -331,17 +331,45 @@ public:
#if QT_CONFIG(regularexpression)
[[nodiscard]] QString section(const QRegularExpression &re, qsizetype start, qsizetype end = -1, SectionFlags flags = SectionDefault) const;
#endif
[[nodiscard]] QString left(qsizetype n) const;
[[nodiscard]] QString right(qsizetype n) const;
[[nodiscard]] QString mid(qsizetype position, qsizetype n = -1) const;
#if QT_CORE_REMOVED_SINCE(6, 7)
QString left(qsizetype n) const;
QString right(qsizetype n) const;
QString mid(qsizetype position, qsizetype n = -1) const;
QString first(qsizetype n) const;
QString last(qsizetype n) const;
QString sliced(qsizetype pos) const;
QString sliced(qsizetype pos, qsizetype n) const;
QString chopped(qsizetype n) const;
#else
[[nodiscard]] QString left(qsizetype n) const &
{
if (size_t(n) >= size_t(size()))
return *this;
return first(n);
}
[[nodiscard]] QString left(qsizetype n) &&
{
if (size_t(n) >= size_t(size()))
return std::move(*this);
return std::move(*this).first(n);
}
[[nodiscard]] QString right(qsizetype n) const &
{
if (size_t(n) >= size_t(size()))
return *this;
return last(n);
}
[[nodiscard]] QString right(qsizetype n) &&
{
if (size_t(n) >= size_t(size()))
return std::move(*this);
return std::move(*this).last(n);
}
[[nodiscard]] QString mid(qsizetype position, qsizetype n = -1) const &;
[[nodiscard]] QString mid(qsizetype position, qsizetype n = -1) &&;
[[nodiscard]] QString first(qsizetype n) const &
{ verify(0, n); return sliced(0, n); }
[[nodiscard]] QString last(qsizetype n) const &

View File

@ -145,6 +145,15 @@ static const QByteArray::DataPointer staticNotNullTerminated = {
4
};
template <typename String> String detached(String s)
{
if (!s.isNull()) { // detaching loses nullness, but we need to preserve it
auto d = s.data();
Q_UNUSED(d);
}
return s;
}
template <class T> const T &verifyZeroTermination(const T &t) { return t; }
QByteArray verifyZeroTermination(const QByteArray &ba)
@ -2733,45 +2742,99 @@ void tst_QByteArray::simplified_data()
void tst_QByteArray::left()
{
QByteArray a;
QCOMPARE(QByteArray().left(0), QByteArray());
QCOMPARE(QByteArray().left(10), QByteArray());
QCOMPARE(a.left(0), QByteArray());
QCOMPARE(a.left(10), QByteArray());
QVERIFY(!a.isDetached());
QCOMPARE(QByteArray(a).left(0), QByteArray());
QCOMPARE(QByteArray(a).left(10), QByteArray());
QCOMPARE(detached(a).left(0), QByteArray());
QCOMPARE(detached(a).left(10), QByteArray());
a = QByteArray("abcdefgh");
const char *ptr = a.constData();
// lvalue
QCOMPARE(a.left(5), QByteArray("abcde"));
QCOMPARE(a.left(20), a);
QCOMPARE(a.left(-5), QByteArray());
// calling left() does not modify the source array
QCOMPARE(a.constData(), ptr);
// rvalue, not detached
QCOMPARE(QByteArray(a).left(5), QByteArray("abcde"));
QCOMPARE(QByteArray(a).left(20), a);
QCOMPARE(QByteArray(a).left(-5), QByteArray());
// calling left() does not modify the source array
QCOMPARE(a.constData(), ptr);
// rvalue, detached
QCOMPARE(detached(a).left(5), QByteArray("abcde"));
QCOMPARE(detached(a).left(20), a);
QCOMPARE(detached(a).left(-5), QByteArray());
// calling left() does not modify the source array
QCOMPARE(a.constData(), ptr);
}
void tst_QByteArray::right()
{
QByteArray a;
QCOMPARE(QByteArray().right(0), QByteArray());
QCOMPARE(QByteArray().right(10), QByteArray());
QCOMPARE(a.right(0), QByteArray());
QCOMPARE(a.right(10), QByteArray());
QVERIFY(!a.isDetached());
QCOMPARE(QByteArray(a).right(0), QByteArray());
QCOMPARE(QByteArray(a).right(10), QByteArray());
QCOMPARE(detached(a).right(0), QByteArray());
QCOMPARE(detached(a).right(10), QByteArray());
a = QByteArray("abcdefgh");
const char *ptr = a.constData();
// lvalue
QCOMPARE(a.right(5), QByteArray("defgh"));
QCOMPARE(a.right(20), a);
QCOMPARE(a.right(-5), QByteArray());
// calling right() does not modify the source array
QCOMPARE(a.constData(), ptr);
// rvalue, not detached
QCOMPARE(QByteArray(a).right(5), QByteArray("defgh"));
QCOMPARE(QByteArray(a).right(20), a);
QCOMPARE(QByteArray(a).right(-5), QByteArray());
// calling right() does not modify the source array
QCOMPARE(a.constData(), ptr);
// rvalue, detached
QCOMPARE(detached(a).right(5), QByteArray("defgh"));
QCOMPARE(detached(a).right(20), a);
QCOMPARE(detached(a).right(-5), QByteArray());
// calling right() does not modify the source array
QCOMPARE(a.constData(), ptr);
}
void tst_QByteArray::mid()
{
QByteArray a;
QCOMPARE(QByteArray().mid(0), QByteArray());
QCOMPARE(a.mid(0, 10), QByteArray());
QCOMPARE(a.mid(0), QByteArray());
QCOMPARE(a.mid(0, 10), QByteArray());
QCOMPARE(a.mid(10), QByteArray());
QVERIFY(!a.isDetached());
QCOMPARE(QByteArray(a).mid(0), QByteArray());
QCOMPARE(QByteArray(a).mid(0, 10), QByteArray());
QCOMPARE(QByteArray(a).mid(10), QByteArray());
QCOMPARE(detached(a).mid(0), QByteArray());
QCOMPARE(detached(a).mid(0, 10), QByteArray());
QCOMPARE(detached(a).mid(10), QByteArray());
a = QByteArray("abcdefgh");
const char *ptr = a.constData();
// lvalue
QCOMPARE(a.mid(2), QByteArray("cdefgh"));
QCOMPARE(a.mid(2, 3), QByteArray("cde"));
QCOMPARE(a.mid(20), QByteArray());
@ -2779,6 +2842,24 @@ void tst_QByteArray::mid()
QCOMPARE(a.mid(-5, 8), QByteArray("abc"));
// calling mid() does not modify the source array
QCOMPARE(a.constData(), ptr);
// rvalue, not detached
QCOMPARE(QByteArray(a).mid(2), QByteArray("cdefgh"));
QCOMPARE(QByteArray(a).mid(2, 3), QByteArray("cde"));
QCOMPARE(QByteArray(a).mid(20), QByteArray());
QCOMPARE(QByteArray(a).mid(-5), QByteArray("abcdefgh"));
QCOMPARE(QByteArray(a).mid(-5, 8), QByteArray("abc"));
// calling mid() does not modify the source array
QCOMPARE(a.constData(), ptr);
// rvalue, detached
QCOMPARE(detached(a).mid(2), QByteArray("cdefgh"));
QCOMPARE(detached(a).mid(2, 3), QByteArray("cde"));
QCOMPARE(detached(a).mid(20), QByteArray());
QCOMPARE(detached(a).mid(-5), QByteArray("abcdefgh"));
QCOMPARE(detached(a).mid(-5, 8), QByteArray("abc"));
// calling mid() does not modify the source array
QCOMPARE(a.constData(), ptr);
}
void tst_QByteArray::length()

View File

@ -2328,50 +2328,125 @@ void tst_QString::left()
{
QString a;
// lvalue
QVERIFY(a.left(0).isNull());
QVERIFY(a.left(5).isNull());
QVERIFY(a.left(-4).isNull());
QVERIFY(!a.isDetached());
// rvalue, not detached
QVERIFY(QString(a).left(0).isNull());
QVERIFY(QString(a).left(5).isNull());
QVERIFY(QString(a).left(-4).isNull());
QVERIFY(!QString(a).isDetached());
// rvalue, detached is not applicable
a = u"ABCDEFGHIEfGEFG"_s;
QCOMPARE(a.size(), 15);
// lvalue
QCOMPARE(a.left(3), QLatin1String("ABC"));
QVERIFY(!a.left(0).isNull());
QCOMPARE(a.left(0), QLatin1String(""));
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, not detached
QCOMPARE(QString(a).left(3), QLatin1String("ABC"));
QVERIFY(!QString(a).left(0).isNull());
QCOMPARE(QString(a).left(0), QLatin1String(""));
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, detached
QCOMPARE(detached(a).left(3), QLatin1String("ABC"));
QVERIFY(!detached(a).left(0).isNull());
QCOMPARE(detached(a).left(0), QLatin1String(""));
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
QString n;
QVERIFY(QString().left(3).isNull());
QVERIFY(QString().left(0).isNull());
QVERIFY(QString().left(0).isNull());
QVERIFY(n.left(3).isNull());
QVERIFY(n.left(0).isNull());
QVERIFY(n.left(0).isNull());
QString l = u"Left"_s;
// lvalue
QCOMPARE(l.left(-1), l);
QCOMPARE(l.left(100), l);
QCOMPARE(l, u"Left");
// rvalue, not detached
QCOMPARE(QString(l).left(-1), l);
QCOMPARE(QString(l).left(100), l);
QCOMPARE(l, u"Left");
// rvalue, detached
QCOMPARE(detached(l).left(-1), l);
QCOMPARE(detached(l).left(100), l);
QCOMPARE(l, u"Left");
}
void tst_QString::right()
{
QString a;
// lvalue
QVERIFY(a.right(0).isNull());
QVERIFY(a.right(5).isNull());
QVERIFY(a.right(-4).isNull());
QVERIFY(!a.isDetached());
// rvalue, not detached
QVERIFY(QString(a).right(0).isNull());
QVERIFY(QString(a).right(5).isNull());
QVERIFY(QString(a).right(-4).isNull());
QVERIFY(!QString(a).isDetached());
// rvalue, detached is not applicable
a = u"ABCDEFGHIEfGEFG"_s;
QCOMPARE(a.size(), 15);
// lvalue
QCOMPARE(a.right(3), QLatin1String("EFG"));
QCOMPARE(a.right(0), QLatin1String(""));
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, not detached
QCOMPARE(QString(a).right(3), QLatin1String("EFG"));
QCOMPARE(QString(a).right(0), QLatin1String(""));
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, detached
QCOMPARE(detached(a).right(3), QLatin1String("EFG"));
QCOMPARE(detached(a).right(0), QLatin1String(""));
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
QString n;
QVERIFY(QString().right(3).isNull());
QVERIFY(QString().right(0).isNull());
QVERIFY(n.right(3).isNull());
QVERIFY(n.right(0).isNull());
QString r = u"Right"_s;
// lvalue
QCOMPARE(r.right(-1), r);
QCOMPARE(r.right(100), r);
QCOMPARE(r, u"Right");
// rvalue, not detached
QCOMPARE(QString(r).right(-1), r);
QCOMPARE(QString(r).right(100), r);
QCOMPARE(r, u"Right");
// rvalue, detached
QCOMPARE(detached(r).right(-1), r);
QCOMPARE(detached(r).right(100), r);
QCOMPARE(r, u"Right");
}
void tst_QString::mid()
@ -2387,6 +2462,7 @@ void tst_QString::mid()
a = u"ABCDEFGHIEfGEFG"_s;
QCOMPARE(a.size(), 15);
// lvalue
QCOMPARE(a.mid(3,3), QLatin1String("DEF"));
QCOMPARE(a.mid(0,0), QLatin1String(""));
QVERIFY(!a.mid(15,0).isNull());
@ -2395,7 +2471,6 @@ void tst_QString::mid()
QVERIFY(a.mid(15,1).isEmpty());
QVERIFY(a.mid(9999).isNull());
QVERIFY(a.mid(9999,1).isNull());
QCOMPARE(a.mid(-1, 6), a.mid(0, 5));
QVERIFY(a.mid(-100, 6).isEmpty());
QVERIFY(a.mid(INT_MIN, 0).isEmpty());
@ -2414,12 +2489,65 @@ void tst_QString::mid()
QVERIFY(a.mid(20, INT_MAX).isNull());
QCOMPARE(a.mid(-1, -1), a);
// rvalue, not detached
QCOMPARE(QString(a).mid(3,3), QLatin1String("DEF"));
QCOMPARE(QString(a).mid(0,0), QLatin1String(""));
QVERIFY(!QString(a).mid(15,0).isNull());
QVERIFY(QString(a).mid(15,0).isEmpty());
QVERIFY(!QString(a).mid(15,1).isNull());
QVERIFY(QString(a).mid(15,1).isEmpty());
QVERIFY(QString(a).mid(9999).isNull());
QVERIFY(QString(a).mid(9999,1).isNull());
QCOMPARE(QString(a).mid(-1, 6), QString(a).mid(0, 5));
QVERIFY(QString(a).mid(-100, 6).isEmpty());
QVERIFY(QString(a).mid(INT_MIN, 0).isEmpty());
QCOMPARE(QString(a).mid(INT_MIN, -1), a);
QVERIFY(QString(a).mid(INT_MIN, INT_MAX).isNull());
QVERIFY(QString(a).mid(INT_MIN + 1, INT_MAX).isEmpty());
QCOMPARE(QString(a).mid(INT_MIN + 2, INT_MAX), a.left(1));
QCOMPARE(QString(a).mid(INT_MIN + a.size() + 1, INT_MAX), a);
QVERIFY(QString(a).mid(INT_MAX).isNull());
QVERIFY(QString(a).mid(INT_MAX, INT_MAX).isNull());
QCOMPARE(QString(a).mid(-5, INT_MAX), a);
QCOMPARE(QString(a).mid(-1, INT_MAX), a);
QCOMPARE(QString(a).mid(0, INT_MAX), a);
QCOMPARE(QString(a).mid(1, INT_MAX), u"BCDEFGHIEfGEFG");
QCOMPARE(QString(a).mid(5, INT_MAX), u"FGHIEfGEFG");
QVERIFY(QString(a).mid(20, INT_MAX).isNull());
QCOMPARE(QString(a).mid(-1, -1), a);
// rvalue, detached
QCOMPARE(detached(a).mid(3,3), QLatin1String("DEF"));
QCOMPARE(detached(a).mid(0,0), QLatin1String(""));
QVERIFY(!detached(a).mid(15,0).isNull());
QVERIFY(detached(a).mid(15,0).isEmpty());
QVERIFY(!detached(a).mid(15,1).isNull());
QVERIFY(detached(a).mid(15,1).isEmpty());
QVERIFY(detached(a).mid(9999).isNull());
QVERIFY(detached(a).mid(9999,1).isNull());
QCOMPARE(detached(a).mid(-1, 6), detached(a).mid(0, 5));
QVERIFY(detached(a).mid(-100, 6).isEmpty());
QVERIFY(detached(a).mid(INT_MIN, 0).isEmpty());
QCOMPARE(detached(a).mid(INT_MIN, -1), a);
QVERIFY(detached(a).mid(INT_MIN, INT_MAX).isNull());
QVERIFY(detached(a).mid(INT_MIN + 1, INT_MAX).isEmpty());
QCOMPARE(detached(a).mid(INT_MIN + 2, INT_MAX), a.left(1));
QCOMPARE(detached(a).mid(INT_MIN + a.size() + 1, INT_MAX), a);
QVERIFY(detached(a).mid(INT_MAX).isNull());
QVERIFY(detached(a).mid(INT_MAX, INT_MAX).isNull());
QCOMPARE(detached(a).mid(-5, INT_MAX), a);
QCOMPARE(detached(a).mid(-1, INT_MAX), a);
QCOMPARE(detached(a).mid(0, INT_MAX), a);
QCOMPARE(detached(a).mid(1, INT_MAX), u"BCDEFGHIEfGEFG");
QCOMPARE(detached(a).mid(5, INT_MAX), u"FGHIEfGEFG");
QVERIFY(detached(a).mid(20, INT_MAX).isNull());
QCOMPARE(detached(a).mid(-1, -1), a);
QString n;
QVERIFY(n.mid(3,3).isNull());
QVERIFY(n.mid(0,0).isNull());
QVERIFY(n.mid(9999,0).isNull());
QVERIFY(n.mid(9999,1).isNull());
QVERIFY(n.mid(-1, 6).isNull());
QVERIFY(n.mid(-100, 6).isNull());
QVERIFY(n.mid(INT_MIN, 0).isNull());
@ -2438,10 +2566,31 @@ void tst_QString::mid()
QVERIFY(n.mid(20, INT_MAX).isNull());
QVERIFY(n.mid(-1, -1).isNull());
QVERIFY(QString().mid(3,3).isNull());
QVERIFY(QString().mid(0,0).isNull());
QVERIFY(QString().mid(9999,0).isNull());
QVERIFY(QString().mid(9999,1).isNull());
QVERIFY(QString().mid(-1, 6).isNull());
QVERIFY(QString().mid(-100, 6).isNull());
QVERIFY(QString().mid(INT_MIN, 0).isNull());
QVERIFY(QString().mid(INT_MIN, -1).isNull());
QVERIFY(QString().mid(INT_MIN, INT_MAX).isNull());
QVERIFY(QString().mid(INT_MIN + 1, INT_MAX).isNull());
QVERIFY(QString().mid(INT_MIN + 2, INT_MAX).isNull());
QVERIFY(QString().mid(INT_MIN + QString().size() + 1, INT_MAX).isNull());
QVERIFY(QString().mid(INT_MAX).isNull());
QVERIFY(QString().mid(INT_MAX, INT_MAX).isNull());
QVERIFY(QString().mid(-5, INT_MAX).isNull());
QVERIFY(QString().mid(-1, INT_MAX).isNull());
QVERIFY(QString().mid(0, INT_MAX).isNull());
QVERIFY(QString().mid(1, INT_MAX).isNull());
QVERIFY(QString().mid(5, INT_MAX).isNull());
QVERIFY(QString().mid(20, INT_MAX).isNull());
QVERIFY(QString().mid(-1, -1).isNull());
QString x = u"Nine pineapples"_s;
QCOMPARE(x.mid(5, 4), u"pine");
QCOMPARE(x.mid(5), u"pineapples");
QCOMPARE(x.mid(-1, 6), x.mid(0, 5));
QVERIFY(x.mid(-100, 6).isEmpty());
QVERIFY(x.mid(INT_MIN, 0).isEmpty());
@ -2459,6 +2608,51 @@ void tst_QString::mid()
QCOMPARE(x.mid(5, INT_MAX), u"pineapples");
QVERIFY(x.mid(20, INT_MAX).isNull());
QCOMPARE(x.mid(-1, -1), x);
QCOMPARE(x, u"Nine pineapples");
// rvalue, not detached
QCOMPARE(QString(x).mid(5, 4), u"pine");
QCOMPARE(QString(x).mid(5), u"pineapples");
QCOMPARE(QString(x).mid(-1, 6), QString(x).mid(0, 5));
QVERIFY(QString(x).mid(-100, 6).isEmpty());
QVERIFY(QString(x).mid(INT_MIN, 0).isEmpty());
QCOMPARE(QString(x).mid(INT_MIN, -1), x);
QVERIFY(QString(x).mid(INT_MIN, INT_MAX).isNull());
QVERIFY(QString(x).mid(INT_MIN + 1, INT_MAX).isEmpty());
QCOMPARE(QString(x).mid(INT_MIN + 2, INT_MAX), x.left(1));
QCOMPARE(QString(x).mid(INT_MIN + x.size() + 1, INT_MAX), x);
QVERIFY(QString(x).mid(INT_MAX).isNull());
QVERIFY(QString(x).mid(INT_MAX, INT_MAX).isNull());
QCOMPARE(QString(x).mid(-5, INT_MAX), x);
QCOMPARE(QString(x).mid(-1, INT_MAX), x);
QCOMPARE(QString(x).mid(0, INT_MAX), x);
QCOMPARE(QString(x).mid(1, INT_MAX), u"ine pineapples");
QCOMPARE(QString(x).mid(5, INT_MAX), u"pineapples");
QVERIFY(QString(x).mid(20, INT_MAX).isNull());
QCOMPARE(QString(x).mid(-1, -1), x);
QCOMPARE(x, u"Nine pineapples");
// rvalue, detached
QCOMPARE(detached(x).mid(5, 4), u"pine");
QCOMPARE(detached(x).mid(5), u"pineapples");
QCOMPARE(detached(x).mid(-1, 6), detached(x).mid(0, 5));
QVERIFY(detached(x).mid(-100, 6).isEmpty());
QVERIFY(detached(x).mid(INT_MIN, 0).isEmpty());
QCOMPARE(detached(x).mid(INT_MIN, -1), x);
QVERIFY(detached(x).mid(INT_MIN, INT_MAX).isNull());
QVERIFY(detached(x).mid(INT_MIN + 1, INT_MAX).isEmpty());
QCOMPARE(detached(x).mid(INT_MIN + 2, INT_MAX), x.left(1));
QCOMPARE(detached(x).mid(INT_MIN + x.size() + 1, INT_MAX), x);
QVERIFY(detached(x).mid(INT_MAX).isNull());
QVERIFY(detached(x).mid(INT_MAX, INT_MAX).isNull());
QCOMPARE(detached(x).mid(-5, INT_MAX), x);
QCOMPARE(detached(x).mid(-1, INT_MAX), x);
QCOMPARE(detached(x).mid(0, INT_MAX), x);
QCOMPARE(detached(x).mid(1, INT_MAX), u"ine pineapples");
QCOMPARE(detached(x).mid(5, INT_MAX), u"pineapples");
QVERIFY(detached(x).mid(20, INT_MAX).isNull());
QCOMPARE(detached(x).mid(-1, -1), x);
QCOMPARE(x, u"Nine pineapples");
}
void tst_QString::leftJustified()