From 2fefc8c63c1090925986e7650626a91af308d82e Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 25 Sep 2023 11:37:53 -0700 Subject: [PATCH] QString/QByteArray: add lvalue and rvalue overloads of left/mid/right MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/corelib/compat/removed_api.cpp | 70 ++++++ src/corelib/text/qbytearray.cpp | 49 +++-- src/corelib/text/qbytearray.h | 34 ++- src/corelib/text/qstring.cpp | 46 ++-- src/corelib/text/qstring.h | 34 ++- .../text/qbytearray/tst_qbytearray.cpp | 81 +++++++ .../auto/corelib/text/qstring/tst_qstring.cpp | 200 +++++++++++++++++- 7 files changed, 469 insertions(+), 45 deletions(-) diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp index 5c3a587f6e..6f0bb2bf10 100644 --- a/src/corelib/compat/removed_api.cpp +++ b/src/corelib/compat/removed_api.cpp @@ -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 diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index 1821dd2c26..1f496bd404 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -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()); } diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index b5278dbba9..1f3316eed6 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -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 & diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index b5b9af55e2..50bb047253 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -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()); } diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 411430a189..6ec7baf404 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -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 & diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp index ec418edcdc..4b3efc8f20 100644 --- a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp +++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp @@ -145,6 +145,15 @@ static const QByteArray::DataPointer staticNotNullTerminated = { 4 }; +template 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 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() diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index 49c923eb61..94b84ffc4b 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -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()