QVersionNumber: port fromString() to QAnyStringView

We can handle the UTF-8 case by reinterpreting it as Latin-1.

This way, the suffixIndex stays valid as a return value.

As a drive-by, optimize away toLatin1() calls by using a QVLA.
We really need a better way of converting UTF-16 -> L1 than
qt_to_latin1()...

[ChangeLog][QtCore][QVersionNumber] fromString() now takes
QAnyStringView (was: QString, QStringView, QLatin1String)
and a qsizetype pointer (was: int pointer).

Change-Id: I86abaadba2792658fbf93ccd1e0b86e3302c697c
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Marc Mutz 2022-01-15 23:48:52 +01:00
parent 1a440e557b
commit 9ffcab6562
6 changed files with 102 additions and 69 deletions

View File

@ -114,38 +114,30 @@ QByteArray QtPrivate::QByteArrayList_join(const QByteArrayList *that, const char
} }
#endif // QT_REMOVED_SINCE(6, 3) #endif // QT_REMOVED_SINCE(6, 3)
#if QT_REMOVED_SINCE(6, 4) #if QT_REMOVED_SINCE(6, 4)
#include "qversionnumber.h" #include "qversionnumber.h"
# if QT_POINTER_SIZE != 4 QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
QVersionNumber QVersionNumber::fromString(const QString &string, int *suffixIndex) QVersionNumber QVersionNumber::fromString(const QString &string, int *suffixIndex)
{ {
qsizetype si; return fromString(qToAnyStringViewIgnoringNull(string), suffixIndex);
QVersionNumber r = fromString(QLatin1String(string.toLatin1()), &si);
if (suffixIndex)
*suffixIndex = si;
return r;
} }
QVersionNumber QVersionNumber::fromString(QStringView string, int *suffixIndex) QVersionNumber QVersionNumber::fromString(QStringView string, int *suffixIndex)
{ {
qsizetype si; return fromString(QAnyStringView{string}, suffixIndex);
QVersionNumber r = fromString(QLatin1String(string.toLatin1()), &si);
if (suffixIndex)
*suffixIndex = si;
return r;
} }
QVersionNumber QVersionNumber::fromString(QLatin1String string, int *suffixIndex) QVersionNumber QVersionNumber::fromString(QLatin1String string, int *suffixIndex)
{ {
qsizetype si; return fromString(QAnyStringView{string}, suffixIndex);
QVersionNumber r = fromString(string, &si);
if (suffixIndex)
*suffixIndex = si;
return r;
} }
# endif // QT_POINTER_SIZE != 4
QT_WARNING_POP
// #include <qotherheader.h> // #include <qotherheader.h>
// // implement removed functions from qotherheader.h // // implement removed functions from qotherheader.h

View File

@ -90,7 +90,7 @@ void QObject::parse()
{ {
//! [3] //! [3]
QString string("5.4.0-alpha"); QString string("5.4.0-alpha");
int suffixIndex; qsizetype suffixIndex;
QVersionNumber version = QVersionNumber::fromString(string, &suffixIndex); QVersionNumber version = QVersionNumber::fromString(string, &suffixIndex);
// version is 5.4.0 // version is 5.4.0
// suffixIndex is 5 // suffixIndex is 5
@ -98,7 +98,7 @@ void QObject::parse()
//! [3-latin1-1] //! [3-latin1-1]
QLatin1String string("5.4.0-alpha"); QLatin1String string("5.4.0-alpha");
int suffixIndex; qsizetype suffixIndex;
auto version = QVersionNumber::fromString(string, &suffixIndex); auto version = QVersionNumber::fromString(string, &suffixIndex);
// version is 5.4.0 // version is 5.4.0
// suffixIndex is 5 // suffixIndex is 5

View File

@ -995,7 +995,7 @@ static void qt_to_latin1_internal(uchar *dst, const char16_t *src, qsizetype len
#endif #endif
} }
static void qt_to_latin1(uchar *dst, const char16_t *src, qsizetype length) void qt_to_latin1(uchar *dst, const char16_t *src, qsizetype length)
{ {
qt_to_latin1_internal<true>(dst, src, length); qt_to_latin1_internal<true>(dst, src, length);
} }

View File

@ -400,48 +400,9 @@ QString QVersionNumber::toString() const
return version; return version;
} }
#if QT_STRINGVIEW_LEVEL < 2
/*! /*!
Constructs a QVersionNumber from a specially formatted \a string of \fn QVersionNumber QVersionNumber::fromString(QAnyStringView string, qsizetype *suffixIndex)
non-negative decimal numbers delimited by a period (\c{.}). \since 6.4
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.
\snippet qversionnumber/main.cpp 3
\sa isNull()
*/
QVersionNumber QVersionNumber::fromString(const QString &string, qsizetype *suffixIndex)
{
return fromString(QLatin1String(string.toLatin1()), suffixIndex);
}
#endif
/*!
\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.
\snippet qversionnumber/main.cpp 3
\sa isNull()
*/
QVersionNumber QVersionNumber::fromString(QStringView string, qsizetype *suffixIndex)
{
return fromString(QLatin1String(string.toLatin1()), suffixIndex);
}
/*!
\since 5.10
\overload
Constructs a QVersionNumber from a specially formatted \a string of Constructs a QVersionNumber from a specially formatted \a string of
non-negative decimal numbers delimited by '.'. non-negative decimal numbers delimited by '.'.
@ -452,9 +413,13 @@ QVersionNumber QVersionNumber::fromString(QStringView string, qsizetype *suffixI
\snippet qversionnumber/main.cpp 3-latin1-1 \snippet qversionnumber/main.cpp 3-latin1-1
\note In versions prior to Qt 6.4, this function was overloaded for QString,
QLatin1String and QStringView instead, and \a suffixIndex was an \c{int*}.
\sa isNull() \sa isNull()
*/ */
QVersionNumber QVersionNumber::fromString(QLatin1String string, qsizetype *suffixIndex)
static QVersionNumber from_string(QLatin1String string, qsizetype *suffixIndex)
{ {
QList<int> seg; QList<int> seg;
@ -479,6 +444,27 @@ QVersionNumber QVersionNumber::fromString(QLatin1String string, qsizetype *suffi
return QVersionNumber(std::move(seg)); return QVersionNumber(std::move(seg));
} }
static QVersionNumber from_string(q_no_char8_t::QUtf8StringView string, qsizetype *suffixIndex)
{
return from_string(QLatin1String(string.data(), string.size()), suffixIndex);
}
// in qstring.cpp
extern void qt_to_latin1(uchar *dst, const char16_t *uc, qsizetype len);
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(QLatin1String(copy.data(), copy.size()), suffixIndex);
}
QVersionNumber QVersionNumber::fromString(QAnyStringView string, qsizetype *suffixIndex)
{
return string.visit([=] (auto string) { return from_string(string, suffixIndex); });
}
void QVersionNumber::SegmentStorage::setVector(int len, int maj, int min, int mic) void QVersionNumber::SegmentStorage::setVector(int len, int maj, int min, int mic)
{ {
pointer_segments = new QList<int>; pointer_segments = new QList<int>;

View File

@ -275,13 +275,28 @@ public:
[[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2); [[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2);
[[nodiscard]] Q_CORE_EXPORT QString toString() const; [[nodiscard]] Q_CORE_EXPORT QString toString() const;
#if QT_STRINGVIEW_LEVEL < 2 [[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QAnyStringView string, qsizetype *suffixIndex = nullptr);
[[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(const QString &string, qsizetype *suffixIndex = nullptr);
#endif
[[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QLatin1String string, qsizetype *suffixIndex = nullptr);
[[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QStringView string, qsizetype *suffixIndex = nullptr);
#if QT_REMOVED_SINCE(6, 4) && QT_POINTER_SIZE != 4 #if QT_DEPRECATED_SINCE(6, 4) && QT_POINTER_SIZE != 4
Q_WEAK_OVERLOAD
QT_DEPRECATED_VERSION_X_6_4("Use the 'qsizetype *suffixIndex' overload.")
[[nodiscard]] static QVersionNumber fromString(QAnyStringView string, int *suffixIndex)
{
QT_WARNING_PUSH
// fromString() writes to *n unconditionally, but GCC can't know that
QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
qsizetype n;
auto r = fromString(string, &n);
if (suffixIndex) {
Q_ASSERT(int(n) == n);
*suffixIndex = int(n);
}
return r;
QT_WARNING_POP
}
#endif
#if QT_REMOVED_SINCE(6, 4)
[[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(const QString &string, int *suffixIndex); [[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(const QString &string, int *suffixIndex);
[[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QLatin1String string, int *suffixIndex); [[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QLatin1String string, int *suffixIndex);
[[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QStringView string, int *suffixIndex); [[nodiscard]] Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QStringView string, int *suffixIndex);
@ -305,7 +320,6 @@ public:
[[nodiscard]] friend bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept [[nodiscard]] friend bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept
{ return compare(lhs, rhs) != 0; } { return compare(lhs, rhs) != 0; }
private: private:
#ifndef QT_NO_DATASTREAM #ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version); friend Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version);

View File

@ -73,6 +73,7 @@ private slots:
void assignment(); void assignment();
void fromString_data(); void fromString_data();
void fromString(); void fromString();
void fromString_extra();
void toString_data(); void toString_data();
void toString(); void toString();
void isNull_data(); void isNull_data();
@ -523,6 +524,46 @@ void tst_QVersionNumber::fromString()
QCOMPARE(QVersionNumber::fromString(QLatin1String(constructionString.toLatin1())), expectedVersion); QCOMPARE(QVersionNumber::fromString(QLatin1String(constructionString.toLatin1())), expectedVersion);
QCOMPARE(QVersionNumber::fromString(QLatin1String(constructionString.toLatin1()), &index), expectedVersion); QCOMPARE(QVersionNumber::fromString(QLatin1String(constructionString.toLatin1()), &index), expectedVersion);
QCOMPARE(index, suffixIndex); QCOMPARE(index, suffixIndex);
#if QT_DEPRECATED_SINCE(6, 4)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
// check deprecated `int *suffixIndex` overload, too
{
int i;
QCOMPARE(QVersionNumber::fromString(constructionString, &i), expectedVersion);
QCOMPARE(i, suffixIndex);
QCOMPARE(QVersionNumber::fromString(QStringView(constructionString), &i), expectedVersion);
QCOMPARE(i, suffixIndex);
QCOMPARE(QVersionNumber::fromString(QLatin1String(constructionString.toLatin1()), &i), expectedVersion);
QCOMPARE(i, suffixIndex);
}
QT_WARNING_POP
#endif
}
void tst_QVersionNumber::fromString_extra()
{
// check the overloaded fromString() functions aren't ambiguous
// when passing explicit nullptr:
{
auto v = QVersionNumber::fromString("1.2.3-rc1", nullptr);
QCOMPARE(v, QVersionNumber({1, 2, 3}));
}
{
auto v = QVersionNumber::fromString("1.2.3-rc1", 0);
QCOMPARE(v, QVersionNumber({1, 2, 3}));
}
// check the UTF16->L1 conversion isn't doing something weird
{
qsizetype i = -1;
auto v = QVersionNumber::fromString(u"1.0ı", &i); // LATIN SMALL LETTER DOTLESS I
QCOMPARE(v, QVersionNumber(1, 0));
QCOMPARE(i, 3);
}
} }
void tst_QVersionNumber::toString_data() void tst_QVersionNumber::toString_data()