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>
bb10
Giuseppe D'Angelo 2018-12-04 01:18:46 +01:00
parent cc692bb58c
commit 7ee682a1dd
4 changed files with 151 additions and 0 deletions

View File

@ -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]
}
}

View File

@ -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

View File

@ -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

View File

@ -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;
}