diff options
Diffstat (limited to 'src/corelib/tools/qversionnumber.cpp')
-rw-r--r-- | src/corelib/tools/qversionnumber.cpp | 452 |
1 files changed, 146 insertions, 306 deletions
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp index 05c38c350f..af95875b44 100644 --- a/src/corelib/tools/qversionnumber.cpp +++ b/src/corelib/tools/qversionnumber.cpp @@ -1,43 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2016 Intel Corporation. +// Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include <QtCore/qversionnumber.h> #include <QtCore/qhash.h> @@ -57,6 +21,8 @@ QT_BEGIN_NAMESPACE +QT_IMPL_METATYPE_EXTERN(QVersionNumber) + /*! \class QVersionNumber \inmodule QtCore @@ -64,6 +30,7 @@ QT_BEGIN_NAMESPACE \brief The QVersionNumber class contains a version number with an arbitrary number of segments. + \compares strong \snippet qversionnumber/main.cpp 0 */ @@ -105,18 +72,23 @@ QT_BEGIN_NAMESPACE \fn QVersionNumber::QVersionNumber(QList<int> &&seg) Move-constructs a version number from the list of numbers contained in \a seg. - - This constructor is only enabled if the compiler supports C++11 move semantics. */ /*! \fn QVersionNumber::QVersionNumber(std::initializer_list<int> args) - Construct a version number from the std::initializer_list specified by + Constructs a version number from the std::initializer_list specified by \a args. +*/ + +/*! + \fn QVersionNumber::QVersionNumber(QSpan<const int> args) + \since 6.8 + + Constructs a version number from the span specified by \a args. - This constructor is only enabled if the compiler supports C++11 initializer - lists. + \note In Qt versions prior to 6.8, QVersionNumber could only be constructed + from QList, QVarLenthArray or std::initializer_list. */ /*! @@ -168,7 +140,7 @@ QT_BEGIN_NAMESPACE */ /*! - \fn const QList<int>& QVersionNumber::segments() const + \fn QList<int> QVersionNumber::segments() const Returns all of the numerical segments. @@ -181,22 +153,22 @@ QList<int> QVersionNumber::segments() const QList<int> result; result.resize(segmentCount()); - for (int i = 0; i < segmentCount(); ++i) + for (qsizetype i = 0; i < segmentCount(); ++i) result[i] = segmentAt(i); return result; } /*! - \fn int QVersionNumber::segmentAt(int index) const + \fn int QVersionNumber::segmentAt(qsizetype index) const - Returns the segement value at \a index. If the index does not exist, + Returns the segment value at \a index. If the index does not exist, returns 0. \sa segments(), segmentCount() */ /*! - \fn int QVersionNumber::segmentCount() const + \fn qsizetype QVersionNumber::segmentCount() const Returns the number of integers stored in segments(). @@ -204,6 +176,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. @@ -215,7 +236,7 @@ QList<int> QVersionNumber::segments() const */ QVersionNumber QVersionNumber::normalized() const { - int i; + qsizetype i; for (i = m_segments.size(); i; --i) if (m_segments.at(i - 1) != 0) break; @@ -239,7 +260,7 @@ bool QVersionNumber::isPrefixOf(const QVersionNumber &other) const noexcept { if (segmentCount() > other.segmentCount()) return false; - for (int i = 0; i < segmentCount(); ++i) { + for (qsizetype i = 0; i < segmentCount(); ++i) { if (segmentAt(i) != other.segmentAt(i)) return false; } @@ -261,7 +282,7 @@ bool QVersionNumber::isPrefixOf(const QVersionNumber &other) const noexcept */ int QVersionNumber::compare(const QVersionNumber &v1, const QVersionNumber &v2) noexcept { - int commonlen; + qsizetype commonlen; if (Q_LIKELY(!v1.m_segments.isUsingPointer() && !v2.m_segments.isUsingPointer())) { // we can't use memcmp because it interprets the data as unsigned bytes @@ -269,12 +290,12 @@ int QVersionNumber::compare(const QVersionNumber &v1, const QVersionNumber &v2) const qint8 *ptr2 = v2.m_segments.inline_segments + InlineSegmentStartIdx; commonlen = qMin(v1.m_segments.size(), v2.m_segments.size()); - for (int i = 0; i < commonlen; ++i) + for (qsizetype i = 0; i < commonlen; ++i) if (int x = ptr1[i] - ptr2[i]) return x; } else { commonlen = qMin(v1.segmentCount(), v2.segmentCount()); - for (int i = 0; i < commonlen; ++i) { + for (qsizetype i = 0; i < commonlen; ++i) { if (v1.segmentAt(i) != v2.segmentAt(i)) return v1.segmentAt(i) - v2.segmentAt(i); } @@ -311,8 +332,8 @@ int QVersionNumber::compare(const QVersionNumber &v1, const QVersionNumber &v2) QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2) { - int commonlen = qMin(v1.segmentCount(), v2.segmentCount()); - int i; + qsizetype commonlen = qMin(v1.segmentCount(), v2.segmentCount()); + qsizetype i; for (i = 0; i < commonlen; ++i) { if (v1.segmentAt(i) != v2.segmentAt(i)) break; @@ -391,17 +412,19 @@ QString QVersionNumber::toString() const QString version; version.reserve(qMax(segmentCount() * 2 - 1, 0)); bool first = true; - for (int i = 0; i < segmentCount(); ++i) { + for (qsizetype i = 0; i < segmentCount(); ++i) { if (!first) - version += QLatin1Char('.'); + version += u'.'; version += QString::number(segmentAt(i)); first = false; } return version; } -#if QT_STRINGVIEW_LEVEL < 2 /*! + \fn QVersionNumber QVersionNumber::fromString(QAnyStringView string, qsizetype *suffixIndex) + \since 6.4 + Constructs a QVersionNumber from a specially formatted \a string of non-negative decimal numbers delimited by a period (\c{.}). @@ -409,74 +432,86 @@ QString QVersionNumber::toString() const is considered to be the suffix string. The start index of that string will be stored in \a suffixIndex if it is not null. - \snippet qversionnumber/main.cpp 3 + \snippet qversionnumber/main.cpp 3-latin1-1 + + \note In versions prior to Qt 6.4, this function was overloaded for QString, + QLatin1StringView and QStringView instead, and \a suffixIndex was an \c{int*}. \sa isNull() */ -QVersionNumber QVersionNumber::fromString(const QString &string, int *suffixIndex) + +static QVersionNumber from_string(QLatin1StringView string, qsizetype *suffixIndex) { - return fromString(QLatin1String(string.toLatin1()), suffixIndex); -} -#endif + // 32 should be more than enough, and, crucially, it means we're allocating + // not more (and often less) often when compared with direct QList usage + // for all possible segment counts (under the constraint that we don't want + // to keep more capacity around for the lifetime of the resulting + // QVersionNumber than required), esp. in the common case where the inline + // storage can be used. + QVarLengthArray<int, 32> seg; -/*! - \since 5.10 - \overload + const char *start = string.begin(); + const char *lastGoodEnd = start; + const char *endOfString = string.end(); - Constructs a QVersionNumber from a specially formatted \a string of - non-negative decimal numbers delimited by '.'. + do { + // parsing as unsigned so a minus sign is rejected + auto [value, used] = qstrntoull(start, endOfString - start, 10); + if (used <= 0 || value > qulonglong(std::numeric_limits<int>::max())) + break; + seg.append(int(value)); + start += used + 1; + lastGoodEnd = start - 1; + } while (start < endOfString && *lastGoodEnd == '.'); - Once the numerical segments have been parsed, the remainder of the string - is considered to be the suffix string. The start index of that string will be - stored in \a suffixIndex if it is not null. + if (suffixIndex) + *suffixIndex = lastGoodEnd - string.begin(); - \snippet qversionnumber/main.cpp 3 + return QVersionNumber(seg); +} - \sa isNull() -*/ -QVersionNumber QVersionNumber::fromString(QStringView string, int *suffixIndex) +static QVersionNumber from_string(q_no_char8_t::QUtf8StringView string, qsizetype *suffixIndex) { - return fromString(QLatin1String(string.toLatin1()), suffixIndex); + return from_string(QLatin1StringView(string.data(), string.size()), suffixIndex); } -/*! - \since 5.10 - \overload - - Constructs a QVersionNumber from a specially formatted \a string of - non-negative decimal numbers delimited by '.'. - - Once the numerical segments have been parsed, the remainder of the string - is considered to be the suffix string. The start index of that string will be - stored in \a suffixIndex if it is not null. +// in qstring.cpp +extern void qt_to_latin1(uchar *dst, const char16_t *uc, qsizetype len); - \snippet qversionnumber/main.cpp 3-latin1-1 +static QVersionNumber from_string(QStringView string, qsizetype *suffixIndex) +{ + QVarLengthArray<char> copy; + copy.resize(string.size()); + qt_to_latin1(reinterpret_cast<uchar*>(copy.data()), string.utf16(), string.size()); + return from_string(QLatin1StringView(copy.data(), copy.size()), suffixIndex); +} - \sa isNull() -*/ -QVersionNumber QVersionNumber::fromString(QLatin1String string, int *suffixIndex) +QVersionNumber QVersionNumber::fromString(QAnyStringView string, qsizetype *suffixIndex) { - QList<int> seg; + return string.visit([=] (auto string) { return from_string(string, suffixIndex); }); +} - const char *start = string.begin(); - const char *end = start; - const char *lastGoodEnd = start; - const char *endOfString = string.end(); +void QVersionNumber::SegmentStorage::setListData(const QList<int> &seg) +{ + pointer_segments = new QList<int>(seg); +} - do { - bool ok = false; - const qulonglong value = qstrtoull(start, &end, 10, &ok); - if (!ok || value > qulonglong(std::numeric_limits<int>::max())) - break; - seg.append(int(value)); - start = end + 1; - lastGoodEnd = end; - } while (start < endOfString && (end < endOfString && *end == '.')); +void QVersionNumber::SegmentStorage::setListData(QList<int> &&seg) +{ + pointer_segments = new QList<int>(std::move(seg)); +} - if (suffixIndex) - *suffixIndex = int(lastGoodEnd - string.begin()); +void QVersionNumber::SegmentStorage::setListData(const int *first, const int *last) +{ + pointer_segments = new QList<int>(first, last); +} - return QVersionNumber(std::move(seg)); +void QVersionNumber::SegmentStorage::resize(qsizetype len) +{ + if (isUsingPointer()) + pointer_segments->resize(len); + else + setInlineSize(len); } void QVersionNumber::SegmentStorage::setVector(int len, int maj, int min, int mic) @@ -529,13 +564,13 @@ QDataStream& operator>>(QDataStream &in, QVersionNumber &version) QDebug operator<<(QDebug debug, const QVersionNumber &version) { QDebugStateSaver saver(debug); - debug.noquote() << version.toString(); + debug.nospace().noquote(); + debug << "QVersionNumber(" << version.toString() << ")"; return debug; } #endif /*! - \fn size_t qHash(const QVersionNumber &key, size_t seed) \relates QHash \since 5.6 @@ -550,199 +585,4 @@ size_t qHash(const QVersionNumber &key, size_t seed) return seed; } -/*! - \class QTypeRevision - \inmodule QtCore - \since 6.0 - \brief The QTypeRevision class contains a lightweight representation of - a version number with two 8-bit segments, major and minor, either - of which can be unknown. - - Use this class to describe revisions of a type. Compatible revisions can be - expressed as increments of the minor version. Breaking changes can be - expressed as increments of the major version. The return values of - \l QMetaMethod::revision() and \l QMetaProperty::revision() can be passed to - \l QTypeRevision::fromEncodedVersion(). The resulting major and minor versions - specify in which Qt versions the properties and methods were added. - - \sa QMetaMethod::revision(), QMetaProperty::revision() -*/ - -/*! - \fn template<typename Integer> static bool QTypeRevision::isValidSegment(Integer segment) - - Returns true if the given number can be used as either major or minor - version in a QTypeRevision. The valid range for \a segment is \c {>= 0} and \c {< 255}. -*/ - -/*! - \fn QTypeRevision::QTypeRevision() - - Produces an invalid revision. - - \sa isValid() -*/ - -/*! - \fn template <typename Major, typename Minor> static QTypeRevision QTypeRevision::fromVersion(Major majorVersion, Minor minorVersion) - - Produces a QTypeRevision from the given \a majorVersion and \a minorVersion, - both of which need to be a valid segments. - - \sa isValidSegment() -*/ - -/*! - \fn template <typename Major> static QTypeRevision QTypeRevision::fromMajorVersion(Major majorVersion) - - Produces a QTypeRevision from the given \a majorVersion with an invalid minor - version. \a majorVersion needs to be a valid segment. - - \sa isValidSegment() -*/ - -/*! - \fn template <typename Minor> static QTypeRevision QTypeRevision::fromMinorVersion(Minor minorVersion) - - Produces a QTypeRevision from the given \a minorVersion with an invalid major - version. \a minorVersion needs to be a valid segment. - - \sa isValidSegment() -*/ - -/*! - \fn template <typename Integer> static QTypeRevision QTypeRevision::fromEncodedVersion(Integer value) - - Produces a QTypeRevision from the given \a value. \a value encodes both the - minor and major versions in the least significant and second least - significant byte, respectively. - - \a value must not have any bits outside the least significant two bytes set. - \c Integer needs to be at least 16 bits wide, and must not have a sign bit - in the least significant 16 bits. - - \sa toEncodedVersion() -*/ - -/*! - \fn static QTypeRevision QTypeRevision::zero() - - Produces a QTypeRevision with major and minor version \c{0}. -*/ - -/*! - \fn bool QTypeRevision::hasMajorVersion() const - - Returns true if the major version is known, otherwise false. - - \sa majorVersion(), hasMinorVersion() -*/ - -/*! - \fn quint8 QTypeRevision::majorVersion() const - - Returns the major version encoded in the revision. - - \sa hasMajorVersion(), minorVersion() -*/ - -/*! - \fn bool QTypeRevision::hasMinorVersion() const - - Returns true if the minor version is known, otherwise false. - - \sa minorVersion(), hasMajorVersion() -*/ - -/*! - \fn quint8 QTypeRevision::minorVersion() const - - Returns the minor version encoded in the revision. - - \sa hasMinorVersion(), majorVersion() -*/ - -/*! - \fn bool QTypeRevision::isValid() const - - Returns true if the major version or the minor version is known, - otherwise false. - - \sa hasMajorVersion(), hasMinorVersion() -*/ - -/*! - \fn template<typename Integer> Integer QTypeRevision::toEncodedVersion() const - - Transforms the revision into an integer value, encoding the minor - version into the least significant byte, and the major version into - the second least significant byte. - - \c Integer needs to be at least 16 bits wide, and must not have a sign bit - in the least significant 16 bits. - - \sa fromEncodedVersion() -*/ - -#ifndef QT_NO_DATASTREAM -/*! - \fn QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision) - \relates QTypeRevision - \since 6.0 - - Writes the revision \a revision to stream \a out. - */ -QDataStream &operator<<(QDataStream &out, const QTypeRevision &revision) -{ - return out << revision.toEncodedVersion<quint16>(); -} - -/*! - \fn QDataStream& operator>>(QDataStream &in, QTypeRevision &revision) - \relates QTypeRevision - \since 6.0 - - Reads a revision from stream \a in and stores it in \a revision. - */ -QDataStream &operator>>(QDataStream &in, QTypeRevision &revision) -{ - quint16 value; - in >> value; - revision = QTypeRevision::fromEncodedVersion(value); - return in; -} -#endif - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug debug, const QTypeRevision &revision) -{ - QDebugStateSaver saver(debug); - if (revision.hasMajorVersion()) { - if (revision.hasMinorVersion()) - debug.nospace() << revision.majorVersion() << '.' << revision.minorVersion(); - else - debug.nospace().noquote() << revision.majorVersion() << ".x"; - } else { - if (revision.hasMinorVersion()) - debug << revision.minorVersion(); - else - debug.noquote() << "invalid"; - } - return debug; -} -#endif - -/*! - \fn size_t qHash(const QTypeRevision &key, size_t seed) - \relates QHash - \since 6.0 - - Returns the hash value for the \a key, using \a seed to seed the - calculation. -*/ -size_t qHash(const QTypeRevision &key, size_t seed) -{ - return qHash(key.toEncodedVersion<quint16>(), seed); -} - QT_END_NAMESPACE |