diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2018-12-04 01:18:46 +0100 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2020-09-30 21:39:36 +0200 |
commit | 7ee682a1ddc259225618b57ff00f4c36ff5e724c (patch) | |
tree | a77abbd03cd81c6daaaa4a020065a1582a8604f9 | |
parent | cc692bb58c8a39f06eb30c04cfcb61fa466d18ae (diff) |
QREMatchIterator: add support for range-based for
Add begin()/end() on QRegularExpressionMatchIterator, making
iterators over an iterator (like directory_iterator).
[ChangeLog][QtCore][QRegularExpression] The iterator object
(QRegularExpressionMatchIterator) returned by a global match
is now usable in a range-based for loop.
Change-Id: If3d31bd2e84e7d1fb626a0b3d2745914dff03e39
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
4 files changed, 151 insertions, 0 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_text_qregularexpression.cpp b/src/corelib/doc/snippets/code/src_corelib_text_qregularexpression.cpp index b451ed5253..c418a1f279 100644 --- a/src/corelib/doc/snippets/code/src_corelib_text_qregularexpression.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_text_qregularexpression.cpp @@ -355,4 +355,13 @@ QString wildcard = QRegularExpression::wildcardToRegularExpression("*.jpeg"); ("", "day", "month", "year", "", "name") //! [33] +{ +//! [34] +QRegularExpression re(R"(\w+)"); +QString subject("the quick fox"); +for (const QRegularExpressionMatch &match : re.globalMatch(subject)) { + // ... +} +//! [34] +} } diff --git a/src/corelib/text/qregularexpression.cpp b/src/corelib/text/qregularexpression.cpp index 943138f870..beba74021b 100644 --- a/src/corelib/text/qregularexpression.cpp +++ b/src/corelib/text/qregularexpression.cpp @@ -260,6 +260,12 @@ QT_BEGIN_NAMESPACE You can also use \l{QRegularExpressionMatchIterator::}{peekNext()} to get the next result without advancing the iterator. + It is also possible to simply use the result of + QRegularExpression::globalMatch in a range-based for loop, for instance + like this: + + \snippet code/src_corelib_text_qregularexpression.cpp 34 + It is possible to pass a starting offset and one or more match options to the globalMatch() function, exactly like normal matching with match(). @@ -535,6 +541,12 @@ QT_BEGIN_NAMESPACE Moreover, QRegularExpressionMatchIterator offers a peekNext() function to get the next result \e{without} advancing the iterator. + Starting with Qt 6.0, it is also possible to simply use the result of + QRegularExpression::globalMatch in a range-based for loop, for instance + like this: + + \snippet code/src_corelib_text_qregularexpression.cpp 34 + You can retrieve the QRegularExpression object the subject string was matched against by calling the regularExpression() function; the match type and the match options are available as well by calling @@ -2563,6 +2575,19 @@ QRegularExpression::MatchOptions QRegularExpressionMatchIterator::matchOptions() return d->matchOptions; } +/*! + \internal +*/ +QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator) +{ + return QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator(iterator); +} + +/*! + \fn QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel end(const QRegularExpressionMatchIterator &) + \internal +*/ + #ifndef QT_NO_DATASTREAM /*! \relates QRegularExpression diff --git a/src/corelib/text/qregularexpression.h b/src/corelib/text/qregularexpression.h index 22b63a2252..ee6c421399 100644 --- a/src/corelib/text/qregularexpression.h +++ b/src/corelib/text/qregularexpression.h @@ -47,6 +47,8 @@ #include <QtCore/qshareddata.h> #include <QtCore/qvariant.h> +#include <iterator> + QT_REQUIRE_CONFIG(regularexpression); QT_BEGIN_NAMESPACE @@ -266,6 +268,11 @@ Q_DECLARE_SHARED(QRegularExpressionMatch) Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QRegularExpressionMatch &match); #endif +namespace QtPrivate { +class QRegularExpressionMatchIteratorRangeBasedForIterator; +class QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel {}; +} + struct QRegularExpressionMatchIteratorPrivate; class Q_CORE_EXPORT QRegularExpressionMatchIterator @@ -291,11 +298,100 @@ public: private: friend class QRegularExpression; + friend Q_CORE_EXPORT QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator); + friend QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel end(const QRegularExpressionMatchIterator &) { return {}; } QRegularExpressionMatchIterator(QRegularExpressionMatchIteratorPrivate &dd); QSharedDataPointer<QRegularExpressionMatchIteratorPrivate> d; }; +namespace QtPrivate { + +// support for range-based for loop +class QRegularExpressionMatchIteratorRangeBasedForIterator +{ +public: + using value_type = QRegularExpressionMatch; + using difference_type = int; + using reference_type = const QRegularExpressionMatch &; + using pointer_type = const QRegularExpressionMatch *; + using iterator_category = std::forward_iterator_tag; + + QRegularExpressionMatchIteratorRangeBasedForIterator() + : m_atEnd(true) + { + } + + explicit QRegularExpressionMatchIteratorRangeBasedForIterator(const QRegularExpressionMatchIterator &iterator) + : m_matchIterator(iterator), + m_currentMatch(), + m_atEnd(false) + { + ++*this; + } + + const QRegularExpressionMatch &operator*() const + { + Q_ASSERT_X(!m_atEnd, Q_FUNC_INFO, "operator* called on an iterator already at the end"); + return m_currentMatch; + } + + QRegularExpressionMatchIteratorRangeBasedForIterator &operator++() + { + Q_ASSERT_X(!m_atEnd, Q_FUNC_INFO, "operator++ called on an iterator already at the end"); + if (m_matchIterator.hasNext()) { + m_currentMatch = m_matchIterator.next(); + } else { + m_currentMatch = QRegularExpressionMatch(); + m_atEnd = true; + } + + return *this; + } + + QRegularExpressionMatchIteratorRangeBasedForIterator operator++(int) + { + QRegularExpressionMatchIteratorRangeBasedForIterator i = *this; + ++*this; + return i; + } + +private: + // [input.iterators] imposes operator== on us. Unfortunately, it's not + // trivial to implement, so just do the bare minimum to satifisfy + // Cpp17EqualityComparable. + friend bool operator==(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs, + const QRegularExpressionMatchIteratorRangeBasedForIterator &rhs) noexcept + { + return (&lhs == &rhs); + } + + friend bool operator!=(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs, + const QRegularExpressionMatchIteratorRangeBasedForIterator &rhs) noexcept + { + return !(lhs == rhs); + } + + // This is what we really use in a range-based for. + friend bool operator==(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs, + QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel) noexcept + { + return lhs.m_atEnd; + } + + friend bool operator!=(const QRegularExpressionMatchIteratorRangeBasedForIterator &lhs, + QRegularExpressionMatchIteratorRangeBasedForIteratorSentinel) noexcept + { + return !lhs.m_atEnd; + } + + QRegularExpressionMatchIterator m_matchIterator; + QRegularExpressionMatch m_currentMatch; + bool m_atEnd; +}; + +} // namespace QtPrivate + Q_DECLARE_SHARED(QRegularExpressionMatchIterator) QT_END_NAMESPACE diff --git a/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp index a986223a87..dd96b158f4 100644 --- a/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp +++ b/tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp @@ -184,6 +184,27 @@ bool operator==(const QRegularExpressionMatchIterator &iterator, const QList<Mat if (i.hasNext()) return false; + i = iterator; + + int index = 0; + for (const QRegularExpressionMatch &match : i) { + if (match != expectedMatchList[index++]) + return false; + } + + if (index != expectedMatchList.size()) + return false; + + // do it again + index = 0; + for (const QRegularExpressionMatch &match : i) { + if (match != expectedMatchList[index++]) + return false; + } + + if (index != expectedMatchList.size()) + return false; + return true; } |