QString/QBA: add lvalue and rvalue overloads to first/last/sliced/chopped

Those ought to have been the original implementation, when they were
added in commit 38096a3d70, for Qt 6.0.

Because these classes are exported, we need to provide the previous only
implementations for MSVC. All other compilers would provide inline or
emit local, out-of-line copies.

Change-Id: Ifeb6206a9fa04424964bfffd178836a2ae56157d
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Thiago Macieira 2023-09-25 11:08:51 -07:00
parent 2fd0996324
commit f4101f9953
7 changed files with 223 additions and 20 deletions

View File

@ -618,6 +618,22 @@ QStringView QXmlStreamAttributes::value(QLatin1StringView qualifiedName) const
#if QT_CORE_REMOVED_SINCE(6, 7) #if QT_CORE_REMOVED_SINCE(6, 7)
#include "qbytearray.h"
#ifdef Q_CC_MSVC
// previously inline methods, only needed for MSVC compat
QByteArray QByteArray::first(qsizetype n) const
{ return sliced(0, n); }
QByteArray QByteArray::last(qsizetype n) const
{ return sliced(size() - n, n); }
QByteArray QByteArray::sliced(qsizetype pos) const
{ return sliced(pos, size() - pos); }
QByteArray QByteArray::sliced(qsizetype pos, qsizetype n) const
{ verify(pos, n); return QByteArray(d.data() + pos, n); }
QByteArray QByteArray::chopped(qsizetype n) const
{ return sliced(0, size() - n); }
#endif
#include "qdatetime.h" #include "qdatetime.h"
QDateTime::QDateTime(QDate date, QTime time, const QTimeZone &timeZone) QDateTime::QDateTime(QDate date, QTime time, const QTimeZone &timeZone)
@ -726,6 +742,22 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
return invokeMethodImpl(object, slot, type, 1, &ret, nullptr, nullptr); return invokeMethodImpl(object, slot, type, 1, &ret, nullptr, nullptr);
} }
#include "qstring.h"
#ifdef Q_CC_MSVC
// previously inline methods, only needed for MSVC compat
QString QString::first(qsizetype n) const
{ return sliced(0, n); }
QString QString::last(qsizetype n) const
{ return sliced(size() - n, n); }
QString QString::sliced(qsizetype pos) const
{ return sliced(pos, size() - pos); }
QString QString::sliced(qsizetype pos, qsizetype n) const
{ verify(pos, n); return QString(begin() + pos, n); }
QString QString::chopped(qsizetype n) const
{ return sliced(0, size() - n); }
#endif
#include "qurl.h" #include "qurl.h"
QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode mode) QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode mode)

View File

@ -3102,7 +3102,8 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
} }
/*! /*!
\fn QByteArray QByteArray::first(qsizetype n) const \fn QByteArray QByteArray::first(qsizetype n) const &
\fn QByteArray QByteArray::first(qsizetype n) &&
\since 6.0 \since 6.0
Returns the first \a n bytes of the byte array. Returns the first \a n bytes of the byte array.
@ -3116,7 +3117,8 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
*/ */
/*! /*!
\fn QByteArray QByteArray::last(qsizetype n) const \fn QByteArray QByteArray::last(qsizetype n) const &
\fn QByteArray QByteArray::last(qsizetype n) &&
\since 6.0 \since 6.0
Returns the last \a n bytes of the byte array. Returns the last \a n bytes of the byte array.
@ -3130,7 +3132,8 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
*/ */
/*! /*!
\fn QByteArray QByteArray::sliced(qsizetype pos, qsizetype n) const \fn QByteArray QByteArray::sliced(qsizetype pos, qsizetype n) const &
\fn QByteArray QByteArray::sliced(qsizetype pos, qsizetype n) &&
\since 6.0 \since 6.0
Returns a byte array containing the \a n bytes of this object starting Returns a byte array containing the \a n bytes of this object starting
@ -3144,9 +3147,18 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
\sa first(), last(), chopped(), chop(), truncate() \sa first(), last(), chopped(), chop(), truncate()
*/ */
QByteArray QByteArray::sliced_helper(QByteArray &a, qsizetype pos, qsizetype n)
{
if (n == 0)
return fromRawData(&_empty, 0);
DataPointer d = std::move(a.d).sliced(pos, n);
d.data()[n] = 0;
return QByteArray(std::move(d));
}
/*! /*!
\fn QByteArray QByteArray::sliced(qsizetype pos) const \fn QByteArray QByteArray::sliced(qsizetype pos) const &
\fn QByteArray QByteArray::sliced(qsizetype pos) &&
\since 6.0 \since 6.0
\overload \overload
@ -3159,7 +3171,8 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
*/ */
/*! /*!
\fn QByteArray QByteArray::chopped(qsizetype len) const \fn QByteArray QByteArray::chopped(qsizetype len) const &
\fn QByteArray QByteArray::chopped(qsizetype len) &&
\since 5.10 \since 5.10
Returns a byte array that contains the leftmost size() - \a len bytes of Returns a byte array that contains the leftmost size() - \a len bytes of

View File

@ -155,17 +155,40 @@ public:
[[nodiscard]] QByteArray right(qsizetype len) const; [[nodiscard]] QByteArray right(qsizetype len) const;
[[nodiscard]] QByteArray mid(qsizetype index, qsizetype len = -1) const; [[nodiscard]] QByteArray mid(qsizetype index, qsizetype len = -1) const;
[[nodiscard]] QByteArray first(qsizetype n) const #if QT_CORE_REMOVED_SINCE(6, 7)
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 first(qsizetype n) const &
{ verify(0, n); return sliced(0, n); } { verify(0, n); return sliced(0, n); }
[[nodiscard]] QByteArray last(qsizetype n) const [[nodiscard]] QByteArray last(qsizetype n) const &
{ verify(0, n); return sliced(size() - n, n); } { verify(0, n); return sliced(size() - n, n); }
[[nodiscard]] QByteArray sliced(qsizetype pos) const [[nodiscard]] QByteArray sliced(qsizetype pos) const &
{ verify(pos, 0); return QByteArray(data() + pos, size() - pos); } { verify(pos, 0); return QByteArray(data() + pos, size() - pos); }
[[nodiscard]] QByteArray sliced(qsizetype pos, qsizetype n) const [[nodiscard]] QByteArray sliced(qsizetype pos, qsizetype n) const &
{ verify(pos, n); return QByteArray(d.data() + pos, n); } { verify(pos, n); return QByteArray(d.data() + pos, n); }
[[nodiscard]] QByteArray chopped(qsizetype len) const [[nodiscard]] QByteArray chopped(qsizetype len) const &
{ verify(0, len); return sliced(0, size() - len); } { verify(0, len); return sliced(0, size() - len); }
[[nodiscard]] QByteArray first(qsizetype n) &&
{
verify(0, n);
resize(n); // may detach and allocate memory
return std::move(*this);
}
[[nodiscard]] QByteArray last(qsizetype n) &&
{ verify(0, n); return sliced_helper(*this, size() - n, n); }
[[nodiscard]] QByteArray sliced(qsizetype pos) &&
{ verify(pos, 0); return sliced_helper(*this, pos, size() - pos); }
[[nodiscard]] QByteArray sliced(qsizetype pos, qsizetype n) &&
{ verify(pos, n); return sliced_helper(*this, pos, n); }
[[nodiscard]] QByteArray chopped(qsizetype len) &&
{ verify(0, len); return std::move(*this).first(size() - len); }
#endif
bool startsWith(QByteArrayView bv) const bool startsWith(QByteArrayView bv) const
{ return QtPrivate::startsWith(qToByteArrayViewIgnoringNull(*this), bv); } { return QtPrivate::startsWith(qToByteArrayViewIgnoringNull(*this), bv); }
bool startsWith(char c) const { return size() > 0 && front() == c; } bool startsWith(char c) const { return size() > 0 && front() == c; }
@ -479,6 +502,7 @@ public:
QT_CORE_INLINE_SINCE(6, 4) QT_CORE_INLINE_SINCE(6, 4)
bool isNull() const noexcept; bool isNull() const noexcept;
inline const DataPointer &data_ptr() const { return d; }
inline DataPointer &data_ptr() { return d; } inline DataPointer &data_ptr() { return d; }
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
explicit inline QByteArray(const DataPointer &dd) : d(dd) {} explicit inline QByteArray(const DataPointer &dd) : d(dd) {}
@ -499,6 +523,7 @@ private:
Q_ASSERT(n <= d.size - pos); Q_ASSERT(n <= d.size - pos);
} }
static QByteArray sliced_helper(QByteArray &a, qsizetype pos, qsizetype n);
static QByteArray toLower_helper(const QByteArray &a); static QByteArray toLower_helper(const QByteArray &a);
static QByteArray toLower_helper(QByteArray &a); static QByteArray toLower_helper(QByteArray &a);
static QByteArray toUpper_helper(const QByteArray &a); static QByteArray toUpper_helper(const QByteArray &a);

View File

@ -5222,7 +5222,8 @@ QString QString::mid(qsizetype position, qsizetype n) const
} }
/*! /*!
\fn QString QString::first(qsizetype n) const \fn QString QString::first(qsizetype n) const &
\fn QString QString::first(qsizetype n) &&
\since 6.0 \since 6.0
Returns a string that contains the first \a n characters Returns a string that contains the first \a n characters
@ -5236,7 +5237,8 @@ QString QString::mid(qsizetype position, qsizetype n) const
*/ */
/*! /*!
\fn QString QString::last(qsizetype n) const \fn QString QString::last(qsizetype n) const &
\fn QString QString::last(qsizetype n) &&
\since 6.0 \since 6.0
Returns the string that contains the last \a n characters of this string. Returns the string that contains the last \a n characters of this string.
@ -5249,7 +5251,8 @@ QString QString::mid(qsizetype position, qsizetype n) const
*/ */
/*! /*!
\fn QString QString::sliced(qsizetype pos, qsizetype n) const \fn QString QString::sliced(qsizetype pos, qsizetype n) const &
\fn QString QString::sliced(qsizetype pos, qsizetype n) &&
\since 6.0 \since 6.0
Returns a string that contains \a n characters of this string, Returns a string that contains \a n characters of this string,
@ -5262,9 +5265,18 @@ QString QString::mid(qsizetype position, qsizetype n) const
\sa first(), last(), chopped(), chop(), truncate() \sa first(), last(), chopped(), chop(), truncate()
*/ */
QString QString::sliced_helper(QString &str, qsizetype pos, qsizetype n)
{
if (n == 0)
return QString(DataPointer::fromRawData(&_empty, 0));
DataPointer d = std::move(str.d).sliced(pos, n);
d.data()[n] = 0;
return QString(std::move(d));
}
/*! /*!
\fn QString QString::sliced(qsizetype pos) const \fn QString QString::sliced(qsizetype pos) const &
\fn QString QString::sliced(qsizetype pos) &&
\since 6.0 \since 6.0
\overload \overload
@ -5277,7 +5289,8 @@ QString QString::mid(qsizetype position, qsizetype n) const
*/ */
/*! /*!
\fn QString QString::chopped(qsizetype len) const \fn QString QString::chopped(qsizetype len) const &
\fn QString QString::chopped(qsizetype len) &&
\since 5.10 \since 5.10
Returns a string that contains the size() - \a len leftmost characters Returns a string that contains the size() - \a len leftmost characters

View File

@ -335,17 +335,39 @@ public:
[[nodiscard]] QString right(qsizetype n) const; [[nodiscard]] QString right(qsizetype n) const;
[[nodiscard]] QString mid(qsizetype position, qsizetype n = -1) const; [[nodiscard]] QString mid(qsizetype position, qsizetype n = -1) const;
[[nodiscard]] QString first(qsizetype n) const #if QT_CORE_REMOVED_SINCE(6, 7)
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 first(qsizetype n) const &
{ verify(0, n); return sliced(0, n); } { verify(0, n); return sliced(0, n); }
[[nodiscard]] QString last(qsizetype n) const [[nodiscard]] QString last(qsizetype n) const &
{ verify(0, n); return sliced(size() - n, n); } { verify(0, n); return sliced(size() - n, n); }
[[nodiscard]] QString sliced(qsizetype pos) const [[nodiscard]] QString sliced(qsizetype pos) const &
{ verify(pos, 0); return QString(data() + pos, size() - pos); } { verify(pos, 0); return QString(data() + pos, size() - pos); }
[[nodiscard]] QString sliced(qsizetype pos, qsizetype n) const [[nodiscard]] QString sliced(qsizetype pos, qsizetype n) const &
{ verify(pos, n); return QString(begin() + pos, n); } { verify(pos, n); return QString(begin() + pos, n); }
[[nodiscard]] QString chopped(qsizetype n) const [[nodiscard]] QString chopped(qsizetype n) const &
{ verify(0, n); return sliced(0, size() - n); } { verify(0, n); return sliced(0, size() - n); }
[[nodiscard]] QString first(qsizetype n) &&
{
verify(0, n);
resize(n); // may detach and allocate memory
return std::move(*this);
}
[[nodiscard]] QString last(qsizetype n) &&
{ verify(0, n); return sliced_helper(*this, size() - n, n); }
[[nodiscard]] QString sliced(qsizetype pos) &&
{ verify(pos, 0); return sliced_helper(*this, pos, size() - pos); }
[[nodiscard]] QString sliced(qsizetype pos, qsizetype n) &&
{ verify(pos, n); return sliced_helper(*this, pos, n); }
[[nodiscard]] QString chopped(qsizetype n) &&
{ verify(0, n); return std::move(*this).first(size() - n); }
#endif
bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
[[nodiscard]] bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept [[nodiscard]] bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::startsWith(*this, s, cs); } { return QtPrivate::startsWith(*this, s, cs); }
@ -951,6 +973,7 @@ private:
Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
static int localeAwareCompare_helper(const QChar *data1, qsizetype length1, static int localeAwareCompare_helper(const QChar *data1, qsizetype length1,
const QChar *data2, qsizetype length2); const QChar *data2, qsizetype length2);
static QString sliced_helper(QString &str, qsizetype pos, qsizetype n);
static QString toLower_helper(const QString &str); static QString toLower_helper(const QString &str);
static QString toLower_helper(QString &str); static QString toLower_helper(QString &str);
static QString toUpper_helper(const QString &str); static QString toUpper_helper(const QString &str);

View File

@ -413,6 +413,26 @@ public:
size = dst - begin(); size = dst - begin();
} }
QArrayDataPointer sliced(qsizetype pos, qsizetype n) const &
{
QArrayDataPointer result(n);
std::uninitialized_copy_n(begin() + pos, n, result.begin());
result.size = n;
return result;
}
QArrayDataPointer sliced(qsizetype pos, qsizetype n) &&
{
if (needsDetach())
return sliced(pos, n);
T *newBeginning = begin() + pos;
std::destroy(begin(), newBeginning);
std::destroy(newBeginning + n, end());
setBegin(newBeginning);
size = n;
return std::move(*this);
}
// forwards from QArrayData // forwards from QArrayData
qsizetype allocatedCapacity() noexcept { return d ? d->allocatedCapacity() : 0; } qsizetype allocatedCapacity() noexcept { return d ? d->allocatedCapacity() : 0; }
qsizetype constAllocatedCapacity() const noexcept { return d ? d->constAllocatedCapacity() : 0; } qsizetype constAllocatedCapacity() const noexcept { return d ? d->constAllocatedCapacity() : 0; }

View File

@ -44,6 +44,15 @@ using namespace Qt::StringLiterals;
namespace { namespace {
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;
}
// this wraps an argument to a QString function, as well as how to apply // this wraps an argument to a QString function, as well as how to apply
// the argument to a given QString member function. // the argument to a given QString member function.
template <typename T> template <typename T>
@ -697,6 +706,8 @@ private slots:
void rawData(); void rawData();
void clear(); void clear();
void first();
void last();
void sliced(); void sliced();
void chopped(); void chopped();
void removeIf(); void removeIf();
@ -8850,6 +8861,50 @@ void tst_QString::clear()
QVERIFY(s.isEmpty()); QVERIFY(s.isEmpty());
} }
void tst_QString::first()
{
QString a;
QVERIFY(a.first(0).isEmpty());
QVERIFY(!a.isDetached());
a = u"ABCDEFGHIEfGEFG"_s; // 15 chars
// lvalue
QCOMPARE(a.first(5), u"ABCDE");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, not detached
QCOMPARE(QString(a).first(5), u"ABCDE");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, detached
QCOMPARE(detached(a).first(5), u"ABCDE");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
}
void tst_QString::last()
{
QString a;
QVERIFY(a.last(0).isEmpty());
QVERIFY(!a.isDetached());
a = u"ABCDEFGHIEfGEFG"_s; // 15 chars
// lvalue
QCOMPARE(a.last(10), u"FGHIEfGEFG");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, not detached
QCOMPARE(QString(a).last(10), u"FGHIEfGEFG");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, detached
QCOMPARE(detached(a).last(10), u"FGHIEfGEFG");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
}
void tst_QString::sliced() void tst_QString::sliced()
{ {
QString a; QString a;
@ -8860,8 +8915,20 @@ void tst_QString::sliced()
a = u"ABCDEFGHIEfGEFG"_s; // 15 chars a = u"ABCDEFGHIEfGEFG"_s; // 15 chars
// lvalue
QCOMPARE(a.sliced(5), u"FGHIEfGEFG"); QCOMPARE(a.sliced(5), u"FGHIEfGEFG");
QCOMPARE(a.sliced(5, 3), u"FGH"); QCOMPARE(a.sliced(5, 3), u"FGH");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, not detached
QCOMPARE(QString(a).sliced(5), u"FGHIEfGEFG");
QCOMPARE(QString(a).sliced(5, 3), u"FGH");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, detached
QCOMPARE(detached(a).sliced(5), u"FGHIEfGEFG");
QCOMPARE(detached(a).sliced(5, 3), u"FGH");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
} }
void tst_QString::chopped() void tst_QString::chopped()
@ -8873,7 +8940,17 @@ void tst_QString::chopped()
a = u"ABCDEFGHIEfGEFG"_s; // 15 chars a = u"ABCDEFGHIEfGEFG"_s; // 15 chars
// lvalue
QCOMPARE(a.chopped(10), u"ABCDE"); QCOMPARE(a.chopped(10), u"ABCDE");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, not detached
QCOMPARE(QString(a).chopped(10), u"ABCDE");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
// rvalue, detached
QCOMPARE(detached(a).chopped(10), u"ABCDE");
QCOMPARE(a, u"ABCDEFGHIEfGEFG");
} }
void tst_QString::removeIf() void tst_QString::removeIf()