Add QStringView::split() methods

Since QString::split() is not going away in Qt 6, we should aim
to provide API symmetry here, and ease porting existing code from
QString(Ref) to use QStringView.

This is easier than having to port everything to use tokenize() at
the same time. tokenize() will however lead to better performance
and thus should be preferred.

Change-Id: I1eb43300a90167c6e9389ab56f416f2bf7edf506
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
bb10
Lars Knoll 2020-05-22 16:47:19 +02:00
parent 4f1ebf666e
commit aac39167b7
3 changed files with 105 additions and 20 deletions

View File

@ -7197,7 +7197,7 @@ static ResultList splitString(const StringSource &source, QStringView sep,
extra = (sep.size() == 0 ? 1 : 0);
}
if (start != source.size() || behavior == Qt::KeepEmptyParts)
list.append(source.mid(start, -1));
list.append(source.mid(start));
return list;
}
@ -7381,10 +7381,37 @@ QVector<QStringRef> QStringRef::split(QChar sep, QString::SplitBehavior behavior
}
#endif
/*!
\fn QList<QStringView> QStringView::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
\fn QList<QStringView> QStringView::split(QStringView sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
Splits the string into substring references wherever \a sep occurs, and
returns the list of those strings.
See QString::split() for how \a sep, \a behavior and \a cs interact to form
the result.
\note All references are valid as long this string is alive. Destroying this
string will cause all references to be dangling pointers.
\since 6.0
*/
QList<QStringView> QStringView::split(QStringView sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
{
return splitString<QVector<QStringView>>(QStringView(*this), sep, behavior, cs);
}
QList<QStringView> QStringView::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
{
return split(QStringView(&sep, 1), behavior, cs);
}
#if QT_CONFIG(regularexpression)
namespace {
template<class ResultList, typename MidMethod>
static ResultList splitString(const QString &source, MidMethod mid, const QRegularExpression &re,
template<class ResultList, typename String>
static ResultList splitString(const String &source, const QRegularExpression &re,
Qt::SplitBehavior behavior)
{
ResultList list;
@ -7400,12 +7427,12 @@ static ResultList splitString(const QString &source, MidMethod mid, const QRegul
QRegularExpressionMatch match = iterator.next();
end = match.capturedStart();
if (start != end || behavior == Qt::KeepEmptyParts)
list.append((source.*mid)(start, end - start));
list.append(source.mid(start, end - start));
start = match.capturedEnd();
}
if (start != source.size() || behavior == Qt::KeepEmptyParts)
list.append((source.*mid)(start, -1));
list.append(source.mid(start));
return list;
}
@ -7440,7 +7467,7 @@ static ResultList splitString(const QString &source, MidMethod mid, const QRegul
*/
QStringList QString::split(const QRegularExpression &re, Qt::SplitBehavior behavior) const
{
return splitString<QStringList>(*this, &QString::mid, re, behavior);
return splitString<QStringList>(*this, re, behavior);
}
# if QT_DEPRECATED_SINCE(5, 15)
@ -7471,7 +7498,25 @@ QStringList QString::split(const QRegularExpression &re, SplitBehavior behavior)
*/
QVector<QStringRef> QString::splitRef(const QRegularExpression &re, Qt::SplitBehavior behavior) const
{
return splitString<QVector<QStringRef> >(*this, &QString::midRef, re, behavior);
return splitString<QVector<QStringRef> >(QStringRef(this), re, behavior);
}
/*!
\since 6.0
Splits the string into substring views wherever the regular expression
\a re matches, and returns the list of those strings. If \a re
does not match anywhere in the string, splitRef() returns a
single-element vector containing this string reference.
\note All references are valid as long this string is alive. Destroying this
string will cause all references to be dangling pointers.
\sa split() QStringRef
*/
QList<QStringView> QStringView::split(const QRegularExpression &re, Qt::SplitBehavior behavior) const
{
return splitString<QList<QStringView>>(*this, re, behavior);
}
# if QT_DEPRECATED_SINCE(5, 15)

View File

@ -73,6 +73,7 @@ QT_BEGIN_NAMESPACE
class QString;
class QStringRef;
class QStringView;
class QRegularExpression;
namespace QtPrivate {
template <typename Char>
@ -339,6 +340,21 @@ public:
Q_REQUIRED_RESULT inline int toWCharArray(wchar_t *array) const; // defined in qstring.h
Q_REQUIRED_RESULT Q_CORE_EXPORT
QList<QStringView> split(QStringView sep,
Qt::SplitBehavior behavior = Qt::KeepEmptyParts,
Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
Q_REQUIRED_RESULT Q_CORE_EXPORT
QList<QStringView> split(QChar sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts,
Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
#if QT_CONFIG(regularexpression)
Q_REQUIRED_RESULT Q_CORE_EXPORT
QList<QStringView> split(const QRegularExpression &sep,
Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const;
#endif
//
// STL compatibility API:
//

View File

@ -5685,19 +5685,41 @@ template<> struct StringSplitWrapper<QString>
{
const QString &string;
QStringList split(const QString &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.split(sep, behavior, cs); }
QStringList split(QChar sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.split(sep, behavior, cs); }
QStringList split(const QRegularExpression &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts) const { return string.split(sep, behavior); }
QStringList split(const QString &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.split(sep, behavior, cs); }
QStringList split(QChar sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.split(sep, behavior, cs); }
QStringList split(const QRegularExpression &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const { return string.split(sep, behavior); }
};
template<> struct StringSplitWrapper<QStringRef>
{
const QString &string;
QVector<QStringRef> split(const QString &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.splitRef(sep, behavior, cs); }
QVector<QStringRef> split(QChar sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.splitRef(sep, behavior, cs); }
QVector<QStringRef> split(const QRegularExpression &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts) const { return string.splitRef(sep, behavior); }
QVector<QStringRef> split(const QString &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.splitRef(sep, behavior, cs); }
QVector<QStringRef> split(QChar sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.splitRef(sep, behavior, cs); }
QVector<QStringRef> split(const QRegularExpression &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const { return string.splitRef(sep, behavior); }
};
template<> struct StringSplitWrapper<QStringView>
{
const QString &string;
QList<QStringView> split(const QString &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
{ return QStringView{string}.split(sep, behavior, cs); }
QList<QStringView> split(QChar sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
{ return QStringView{string}.split(sep, behavior, cs); }
QList<QStringView> split(const QRegularExpression &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const
{ return QStringView{string}.split(sep, behavior); }
};
static bool operator==(const QList<QStringView> &result, const QStringList &expected)
{
if (expected.size() != result.size())
return false;
for (int i = 0; i < expected.size(); ++i)
if (expected.at(i) != result.at(i))
return false;
return true;
}
static bool operator ==(const QStringList &left, const QVector<QStringRef> &right)
{
if (left.size() != right.size())
@ -5732,22 +5754,22 @@ void tst_QString::split(const QString &string, const QString &sep, QStringList r
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
list = str.split(sep, QString::KeepEmptyParts);
list = str.split(sep, Qt::KeepEmptyParts);
QVERIFY(list == result);
list = str.split(re, QString::KeepEmptyParts);
list = str.split(re, Qt::KeepEmptyParts);
QVERIFY(list == result);
if (sep.size() == 1) {
list = str.split(sep.at(0), QString::KeepEmptyParts);
list = str.split(sep.at(0), Qt::KeepEmptyParts);
QVERIFY(list == result);
}
result.removeAll("");
list = str.split(sep, QString::SkipEmptyParts);
list = str.split(sep, Qt::SkipEmptyParts);
QVERIFY(list == result);
list = str.split(re, QString::SkipEmptyParts);
list = str.split(re, Qt::SkipEmptyParts);
QVERIFY(list == result);
if (sep.size() == 1) {
list = str.split(sep.at(0), QString::SkipEmptyParts);
list = str.split(sep.at(0), Qt::SkipEmptyParts);
QVERIFY(list == result);
}
QT_WARNING_POP
@ -5759,6 +5781,7 @@ void tst_QString::split()
QFETCH(QString, sep);
QFETCH(QStringList, result);
split<QStringList>(str, sep, result);
split<QVector<QStringView>>(str, sep, result);
}
void tst_QString::splitRef_data()
@ -5804,7 +5827,7 @@ void tst_QString::split_regexp(const QString &_string, const QString &pattern, Q
result.removeAll(QString());
list = string.split(RegExp(pattern), QString::SkipEmptyParts);
list = string.split(RegExp(pattern), Qt::SkipEmptyParts);
QVERIFY(list == result);
}
@ -5814,6 +5837,7 @@ void tst_QString::split_regularexpression()
QFETCH(QString, pattern);
QFETCH(QStringList, result);
split_regexp<QStringList, QRegularExpression>(string, pattern, result);
split_regexp<QList<QStringView>, QRegularExpression>(string, pattern, result);
}
void tst_QString::splitRef_regularexpression_data()