summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@qt.io>2023-12-21 15:08:06 +0100
committerMarc Mutz <marc.mutz@qt.io>2024-01-31 20:18:48 +0000
commit2188ca2c5df6f21a953c002edbe5b2d2cc2c2d2c (patch)
tree1ec3381312df0790e8cb944199c29535e3c53574
parent900d4bd29f30effbb5dbb0efa96886af03839a15 (diff)
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>
-rw-r--r--src/corelib/tools/qversionnumber.cpp49
-rw-r--r--src/corelib/tools/qversionnumber.h73
-rw-r--r--tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp43
3 files changed, 165 insertions, 0 deletions
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp
index 1b53e4156c..84bce0cfd4 100644
--- a/src/corelib/tools/qversionnumber.cpp
+++ b/src/corelib/tools/qversionnumber.cpp
@@ -172,6 +172,55 @@ QList<int> QVersionNumber::segments() const
*/
/*!
+ \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
Returns an equivalent version number but with all trailing zeros removed.
diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h
index 2e9e15e1fa..551ce6f5b1 100644
--- a/src/corelib/tools/qversionnumber.h
+++ b/src/corelib/tools/qversionnumber.h
@@ -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;
diff --git a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
index 6b86d50f75..c929a1b8da 100644
--- a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
+++ b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
@@ -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();