From f5c31262011f7fbcbff5ee91b0df22e4373dd2c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Wed, 14 May 2014 10:56:44 +0200 Subject: Add QString::splitRef functions. The functions can be used to optimize code that do not need to use the split results as QString directly. [ChangeLog][QtCore] QString can now split a string to a list of QStringRef. Change-Id: Ic2dc929e1fba82f9a060e37c51068a301cb5b866 Reviewed-by: Thiago Macieira Reviewed-by: Olivier Goffart --- src/corelib/tools/qstring.cpp | 69 ++++++++++++ src/corelib/tools/qstring.h | 6 + tests/auto/corelib/tools/qstring/tst_qstring.cpp | 138 ++++++++++++++++++++--- 3 files changed, 198 insertions(+), 15 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index e8eb04b598..fdde0955dd 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -6668,6 +6668,28 @@ QStringList QString::split(const QString &sep, SplitBehavior behavior, Qt::CaseS return splitString(*this, &QString::mid, sep, behavior, cs, sep.size()); } +/*! + Splits the string into substring references wherever \a sep occurs, and + returns the list of those strings. If \a sep does not match + anywhere in the string, splitRef() returns a single-element vector + containing this string reference. + + \a cs specifies whether \a sep should be matched case + sensitively or case insensitively. + + If \a behavior is QString::SkipEmptyParts, empty entries don't + appear in the result. By default, empty entries are kept. + + \note All references are valid as long this string is alive. Destroying this + string will cause all references be dangling pointers. + + \since 5.4 + \sa QStringRef split() +*/ +QVector QString::splitRef(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const +{ + return splitString >(*this, &QString::midRef, sep, behavior, cs, sep.size()); +} /*! \overload */ @@ -6676,6 +6698,15 @@ QStringList QString::split(QChar sep, SplitBehavior behavior, Qt::CaseSensitivit return splitString(*this, &QString::mid, sep, behavior, cs, 1); } +/*! + \overload + \since 5.4 +*/ +QVector QString::splitRef(QChar sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const +{ + return splitString >(*this, &QString::midRef, sep, behavior, cs, 1); +} + #ifndef QT_NO_REGEXP namespace { template @@ -6729,6 +6760,25 @@ QStringList QString::split(const QRegExp &rx, SplitBehavior behavior) const { return splitString(*this, &QString::mid, rx, behavior); } + +/*! + \overload + \since 5.4 + + Splits the string into substring references wherever the regular expression + \a rx matches, and returns the list of those strings. If \a rx + 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 be dangling pointers. + + \sa QStringRef split() +*/ +QVector QString::splitRef(const QRegExp &rx, SplitBehavior behavior) const +{ + return splitString >(*this, &QString::midRef, rx, behavior); +} #endif #ifndef QT_NO_REGULAREXPRESSION @@ -6793,6 +6843,25 @@ QStringList QString::split(const QRegularExpression &re, SplitBehavior behavior) { return splitString(*this, &QString::mid, re, behavior); } + +/*! + \overload + \since 5.4 + + Splits the string into substring references 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 be dangling pointers. + + \sa split() QStringRef +*/ +QVector QString::splitRef(const QRegularExpression &re, SplitBehavior behavior) const +{ + return splitString >(*this, &QString::midRef, re, behavior); +} #endif // QT_BOOTSTRAPPED #endif // QT_NO_REGULAREXPRESSION diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 3afd68af1f..21b64f5006 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -441,13 +441,19 @@ public: QStringList split(const QString &sep, SplitBehavior behavior = KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_REQUIRED_RESULT; + QVector splitRef(const QString &sep, SplitBehavior behavior = KeepEmptyParts, + Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_REQUIRED_RESULT; QStringList split(QChar sep, SplitBehavior behavior = KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_REQUIRED_RESULT; + QVector splitRef(QChar sep, SplitBehavior behavior = KeepEmptyParts, + Qt::CaseSensitivity cs = Qt::CaseSensitive) const Q_REQUIRED_RESULT; #ifndef QT_NO_REGEXP QStringList split(const QRegExp &sep, SplitBehavior behavior = KeepEmptyParts) const Q_REQUIRED_RESULT; + QVector splitRef(const QRegExp &sep, SplitBehavior behavior = KeepEmptyParts) const Q_REQUIRED_RESULT; #endif #ifndef QT_NO_REGULAREXPRESSION QStringList split(const QRegularExpression &sep, SplitBehavior behavior = KeepEmptyParts) const Q_REQUIRED_RESULT; + QVector splitRef(const QRegularExpression &sep, SplitBehavior behavior = KeepEmptyParts) const Q_REQUIRED_RESULT; #endif enum NormalizationForm { NormalizationForm_D, diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index 37cb3754d3..2b2b436015 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -76,6 +76,10 @@ class tst_QString : public QObject { Q_OBJECT + template + void split_regexp(const QString &string, const QString &pattern, QStringList result); + template + void split(const QString &string, const QString &separator, QStringList result); public: tst_QString(); public slots: @@ -221,6 +225,14 @@ private slots: void split(); void split_regexp_data(); void split_regexp(); + void split_regularexpression_data(); + void split_regularexpression(); + void splitRef_data(); + void splitRef(); + void splitRef_regexp_data(); + void splitRef_regexp(); + void splitRef_regularexpression_data(); + void splitRef_regularexpression(); void fromUtf16_data(); void fromUtf16(); void fromUtf16_char16_data(); @@ -4989,16 +5001,49 @@ void tst_QString::split_data() QTest::newRow("sep-empty") << "abc" << "" << (QStringList() << "" << "a" << "b" << "c" << ""); } -void tst_QString::split() +template struct StringSplitWrapper; +template<> struct StringSplitWrapper { - QFETCH(QString, str); - QFETCH(QString, sep); - QFETCH(QStringList, result); + 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 QRegExp &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts) const { return string.split(sep, behavior); } + QStringList split(const QRegularExpression &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts) const { return string.split(sep, behavior); } +}; + +template<> struct StringSplitWrapper +{ + const QString &string; + QVector split(const QString &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.splitRef(sep, behavior, cs); } + QVector split(QChar sep, QString::SplitBehavior behavior = QString::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return string.splitRef(sep, behavior, cs); } + QVector split(const QRegExp &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts) const { return string.splitRef(sep, behavior); } + QVector split(const QRegularExpression &sep, QString::SplitBehavior behavior = QString::KeepEmptyParts) const { return string.splitRef(sep, behavior); } +}; +static bool operator ==(const QStringList &left, const QVector &right) +{ + if (left.size() != right.size()) + return false; + + QStringList::const_iterator iLeft = left.constBegin(); + QVector::const_iterator iRight = right.constBegin(); + for (; iLeft != left.end(); ++iLeft, ++iRight) { + if (*iLeft != *iRight) + return false; + } + return true; +} +static inline bool operator ==(const QVector &left, const QStringList &right) { return right == left; } + +template +void tst_QString::split(const QString &string, const QString &sep, QStringList result) +{ QRegExp rx = QRegExp(QRegExp::escape(sep)); QRegularExpression re(QRegularExpression::escape(sep)); - QStringList list; + List list; + StringSplitWrapper str = {string}; list = str.split(sep); QVERIFY(list == result); @@ -5035,6 +5080,27 @@ void tst_QString::split() } } +void tst_QString::split() +{ + QFETCH(QString, str); + QFETCH(QString, sep); + QFETCH(QStringList, result); + split(str, sep, result); +} + +void tst_QString::splitRef_data() +{ + split_data(); +} + +void tst_QString::splitRef() +{ + QFETCH(QString, str); + QFETCH(QString, sep); + QFETCH(QStringList, result); + split >(str, sep, result); +} + void tst_QString::split_regexp_data() { QTest::addColumn("string"); @@ -5054,24 +5120,66 @@ void tst_QString::split_regexp_data() << (QStringList() << "" << "Now" << ": " << "this" << " " << "sentence" << " " << "fragment" << "."); } +template +void tst_QString::split_regexp(const QString &_string, const QString &pattern, QStringList result) +{ + List list; + StringSplitWrapper string = {_string}; + + list = string.split(RegExp(pattern)); + QVERIFY(list == result); + + result.removeAll(QString()); + + list = string.split(RegExp(pattern), QString::SkipEmptyParts); + QVERIFY(list == result); +} + void tst_QString::split_regexp() { QFETCH(QString, string); QFETCH(QString, pattern); QFETCH(QStringList, result); + split_regexp(string, pattern, result); +} - QStringList list; - list = string.split(QRegExp(pattern)); - QCOMPARE(list, result); - list = string.split(QRegularExpression(pattern)); - QCOMPARE(list, result); +void tst_QString::split_regularexpression_data() +{ + split_regexp_data(); +} - result.removeAll(QString()); +void tst_QString::split_regularexpression() +{ + QFETCH(QString, string); + QFETCH(QString, pattern); + QFETCH(QStringList, result); + split_regexp(string, pattern, result); +} - list = string.split(QRegExp(pattern), QString::SkipEmptyParts); - QCOMPARE(list, result); - list = string.split(QRegularExpression(pattern), QString::SkipEmptyParts); - QCOMPARE(list, result); +void tst_QString::splitRef_regularexpression_data() +{ + split_regexp_data(); +} + +void tst_QString::splitRef_regularexpression() +{ + QFETCH(QString, string); + QFETCH(QString, pattern); + QFETCH(QStringList, result); + split_regexp, QRegularExpression>(string, pattern, result); +} + +void tst_QString::splitRef_regexp_data() +{ + split_regexp_data(); +} + +void tst_QString::splitRef_regexp() +{ + QFETCH(QString, string); + QFETCH(QString, pattern); + QFETCH(QStringList, result); + split_regexp, QRegExp>(string, pattern, result); } void tst_QString::fromUtf16_data() -- cgit v1.2.3