summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2018-12-04 01:18:46 +0100
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2020-09-30 21:39:36 +0200
commit7ee682a1ddc259225618b57ff00f4c36ff5e724c (patch)
treea77abbd03cd81c6daaaa4a020065a1582a8604f9
parentcc692bb58c8a39f06eb30c04cfcb61fa466d18ae (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>
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_text_qregularexpression.cpp9
-rw-r--r--src/corelib/text/qregularexpression.cpp25
-rw-r--r--src/corelib/text/qregularexpression.h96
-rw-r--r--tests/auto/corelib/text/qregularexpression/tst_qregularexpression.cpp21
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;
}