QVersionNumber: make iterable

Since QVersionNumber doesn't have an existing way to modify individual
segments, provide only const_iterator.

[ChangeLog][QtCore][QVersionNumber] Added (const) iterators over
segments (begin()/end(), incl. c- and r- variants).

Change-Id: Ia9af70c2a9c59f630123894ad2c9f38031ef5b8f
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Marc Mutz 2023-12-21 15:08:06 +01:00
parent 900d4bd29f
commit 2188ca2c5d
3 changed files with 165 additions and 0 deletions

View File

@ -171,6 +171,55 @@ QList<int> QVersionNumber::segments() const
\sa segments()
*/
/*!
\typedef QVersionNumber::const_iterator
\typedef QVersionNumber::const_reverse_iterator
\since 6.8
Typedefs for an opaque class that implements a (reverse) random-access
iterator over QVersionNumber segments.
\note QVersionNumber does not support modifying segments in-place, so
there is no mutable iterator.
*/
/*!
\typedef QVersionNumber::value_type
\typedef QVersionNumber::difference_type
\typedef QVersionNumber::size_type
\typedef QVersionNumber::reference
\typedef QVersionNumber::const_reference
\typedef QVersionNumber::pointer
\typedef QVersionNumber::const_pointer
\since 6.8
Provided for STL-compatibility.
\note QVersionNumber does not support modifying segments in-place, so
reference and const_reference, as well as pointer and const_pointer are
pairwise the same types.
*/
/*!
\fn QVersionNumber::begin() const
\fn QVersionNumber::end() const;
\fn QVersionNumber::rbegin() const
\fn QVersionNumber::rend() const;
\fn QVersionNumber::cbegin() const
\fn QVersionNumber::cend() const;
\fn QVersionNumber::crbegin() const
\fn QVersionNumber::crend() const;
\fn QVersionNumber::constBegin() const;
\fn QVersionNumber::constEnd() const;
\since 6.8
Returns a const_iterator or const_reverse_iterator, respectively, pointing
to the first or one past the last segment of this version number.
\note QVersionNumber does not support modifying segments in-place, so
there is no mutable iterator.
*/
/*!
\fn QVersionNumber QVersionNumber::normalized() const

View File

@ -6,6 +6,7 @@
#ifndef QVERSIONNUMBER_H
#define QVERSIONNUMBER_H
#include <QtCore/qcontainertools_impl.h>
#include <QtCore/qlist.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qnamespace.h>
@ -190,7 +191,66 @@ class QVersionNumber
Q_CORE_EXPORT void setVector(int len, int maj, int min, int mic);
} m_segments;
class It
{
const QVersionNumber *v;
qsizetype i;
friend class QVersionNumber;
explicit constexpr It(const QVersionNumber *vn, qsizetype idx) noexcept : v(vn), i(idx) {}
friend constexpr bool comparesEqual(const It &lhs, const It &rhs)
{ Q_ASSERT(lhs.v == rhs.v); return lhs.i == rhs.i; }
friend constexpr Qt::strong_ordering compareThreeWay(const It &lhs, const It &rhs)
{ Q_ASSERT(lhs.v == rhs.v); return Qt::compareThreeWay(lhs.i, rhs.i); }
Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(It)
public:
// Rule Of Zero applies
It() = default;
using iterator_category = std::random_access_iterator_tag;
using value_type = int;
using element_type = const int;
using difference_type = qptrdiff; // difference to container requirements
using size_type = qsizetype; // difference to container requirements
using reference = value_type; // difference to container requirements
using pointer = QtPrivate::ArrowProxy<reference>;
reference operator*() const { return v->segmentAt(i); }
pointer operator->() const { return {**this}; }
It &operator++() { ++i; return *this; }
It operator++(int) { auto copy = *this; ++*this; return copy; }
It &operator--() { --i; return *this; }
It operator--(int) { auto copy = *this; --*this; return copy; }
It &operator+=(difference_type n) { i += n; return *this; }
friend It operator+(It it, difference_type n) { it += n; return it; }
friend It operator+(difference_type n, It it) { return it + n; }
It &operator-=(difference_type n) { i -= n; return *this; }
friend It operator-(It it, difference_type n) { it -= n; return it; }
friend difference_type operator-(It lhs, It rhs)
{ Q_ASSERT(lhs.v == rhs.v); return lhs.i - rhs.i; }
reference operator[](difference_type n) const { return *(*this + n); }
};
public:
using const_iterator = It;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using value_type = It::value_type;
using difference_type = It::difference_type;
using size_type = It::size_type;
using reference = It::reference;
using const_reference = reference;
using pointer = It::pointer;
using const_pointer = pointer;
inline QVersionNumber() noexcept
: m_segments()
{}
@ -243,6 +303,19 @@ public:
[[nodiscard]] inline qsizetype segmentCount() const noexcept
{ return m_segments.size(); }
[[nodiscard]] const_iterator begin() const noexcept { return const_iterator{this, 0}; }
[[nodiscard]] const_iterator end() const noexcept { return begin() + segmentCount(); }
[[nodiscard]] const_iterator cbegin() const noexcept { return begin(); }
[[nodiscard]] const_iterator cend() const noexcept { return end(); }
[[nodiscard]] const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; }
[[nodiscard]] const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; }
[[nodiscard]] const_reverse_iterator crbegin() const noexcept { return rbegin(); }
[[nodiscard]] const_reverse_iterator crend() const noexcept { return rend(); }
[[nodiscard]] const_iterator constBegin() const noexcept { return begin(); }
[[nodiscard]] const_iterator constEnd() const noexcept { return end(); }
[[nodiscard]] Q_CORE_EXPORT bool isPrefixOf(const QVersionNumber &other) const noexcept;
[[nodiscard]] Q_CORE_EXPORT static int compare(const QVersionNumber &v1, const QVersionNumber &v2) noexcept;

View File

@ -53,6 +53,10 @@ private slots:
void toString();
void isNull_data();
void isNull();
void iterators_data();
void iterators();
void iteratorsAreDefaultConstructible();
void valueInitializedIteratorsCompareEqual();
void serialize_data();
void serialize();
void moveSemantics();
@ -575,6 +579,45 @@ void tst_QVersionNumber::isNull()
QCOMPARE(version.isNull(), isNull);
}
void tst_QVersionNumber::iterators_data()
{
singleInstanceData();
}
void tst_QVersionNumber::iterators()
{
QFETCH(const QList<int>, segments);
QFETCH(QVersionNumber, expectedVersion);
QVERIFY(std::equal(expectedVersion.begin(), expectedVersion.end(),
segments.begin(), segments.end()));
QVERIFY(std::equal(std::as_const(expectedVersion).begin(), std::as_const(expectedVersion).end(),
segments.begin(), segments.end()));
QVERIFY(std::equal(expectedVersion.cbegin(), expectedVersion.cend(),
segments.cbegin(), segments.cend()));
QVERIFY(std::equal(expectedVersion.rbegin(), expectedVersion.rend(),
segments.rbegin(), segments.rend()));
QVERIFY(std::equal(std::as_const(expectedVersion).rbegin(), std::as_const(expectedVersion).rend(),
segments.rbegin(), segments.rend()));
QVERIFY(std::equal(expectedVersion.crbegin(), expectedVersion.crend(),
segments.crbegin(), segments.crend()));
}
void tst_QVersionNumber::iteratorsAreDefaultConstructible()
{
static_assert(std::is_default_constructible_v<QVersionNumber::const_iterator>);
[[maybe_unused]] QVersionNumber::const_iterator ci;
[[maybe_unused]] QVersionNumber::const_reverse_iterator cri;
}
void tst_QVersionNumber::valueInitializedIteratorsCompareEqual()
{
QVersionNumber::const_iterator it = {}, jt = {};
QCOMPARE_EQ(it, jt);
QVersionNumber::const_reverse_iterator rit = {}, rjt = {};
QCOMPARE_EQ(rit, rjt);
}
void tst_QVersionNumber::serialize_data()
{
singleInstanceData();