diff options
author | Marc Mutz <marc.mutz@qt.io> | 2023-12-21 15:08:06 +0100 |
---|---|---|
committer | Marc Mutz <marc.mutz@qt.io> | 2024-01-31 20:18:48 +0000 |
commit | 2188ca2c5df6f21a953c002edbe5b2d2cc2c2d2c (patch) | |
tree | 1ec3381312df0790e8cb944199c29535e3c53574 | |
parent | 900d4bd29f30effbb5dbb0efa96886af03839a15 (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.cpp | 49 | ||||
-rw-r--r-- | src/corelib/tools/qversionnumber.h | 73 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp | 43 |
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(); |