From beaef85b8d5cb4b0153f87736c56ef25eeec13d4 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 6 Dec 2019 12:03:25 +0100 Subject: Add toInt() and friends to QStringView Make the API more symmetric with regards to both QString and QStringRef. Having this available helps making QStringView more of a drop-in replacement for QStringRef. QStringRef is planned to get removed in Qt 6. Change-Id: Ife036c0b55970078f42e1335442ff9ee5f4a2f0d Reviewed-by: Volker Hilsheimer --- src/corelib/text/qstring.cpp | 10 + src/corelib/text/qstring.h | 18 ++ src/corelib/text/qstringview.cpp | 219 +++++++++++++++++++++ src/corelib/text/qstringview.h | 11 ++ .../qstringapisymmetry/tst_qstringapisymmetry.cpp | 113 +++++++++++ 5 files changed, 371 insertions(+) diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index b1313f0d39..12759c4a5b 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -12127,4 +12127,14 @@ void QAbstractConcatenable::appendLatin1To(const char *a, int len, QChar *out) n qt_from_latin1(reinterpret_cast(out), a, uint(len)); } +double QStringView::toDouble(bool *ok) const +{ + return QLocaleData::c()->stringToDouble(*this, ok, QLocale::RejectGroupSeparator); +} + +float QStringView::toFloat(bool *ok) const +{ + return QLocaleData::convertDoubleToFloat(toDouble(ok), ok); +} + QT_END_NAMESPACE diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 54c286b945..45eb5f2474 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -1016,6 +1016,23 @@ public: QString QStringView::toString() const { return Q_ASSERT(size() == length()), QString(data(), length()); } +qint64 QStringView::toLongLong(bool *ok, int base) const +{ return QString::toIntegral_helper(*this, ok, base); } +quint64 QStringView::toULongLong(bool *ok, int base) const +{ return QString::toIntegral_helper(*this, ok, base); } +long QStringView::toLong(bool *ok, int base) const +{ return QString::toIntegral_helper(*this, ok, base); } +ulong QStringView::toULong(bool *ok, int base) const +{ return QString::toIntegral_helper(*this, ok, base); } +int QStringView::toInt(bool *ok, int base) const +{ return QString::toIntegral_helper(*this, ok, base); } +uint QStringView::toUInt(bool *ok, int base) const +{ return QString::toIntegral_helper(*this, ok, base); } +short QStringView::toShort(bool *ok, int base) const +{ return QString::toIntegral_helper(*this, ok, base); } +ushort QStringView::toUShort(bool *ok, int base) const +{ return QString::toIntegral_helper(*this, ok, base); } + // // QString inline members // @@ -1073,6 +1090,7 @@ inline QString QString::arg(short a, int fieldWidth, int base, QChar fillChar) c { return arg(qlonglong(a), fieldWidth, base, fillChar); } inline QString QString::arg(ushort a, int fieldWidth, int base, QChar fillChar) const { return arg(qulonglong(a), fieldWidth, base, fillChar); } + #if QT_STRINGVIEW_LEVEL < 2 inline QString QString::arg(const QString &a1, const QString &a2) const { return qToStringViewIgnoringNull(*this).arg(a1, a2); } diff --git a/src/corelib/text/qstringview.cpp b/src/corelib/text/qstringview.cpp index 16ccfa8352..8f87943204 100644 --- a/src/corelib/text/qstringview.cpp +++ b/src/corelib/text/qstringview.cpp @@ -39,6 +39,7 @@ #include "qstringview.h" #include "qstring.h" +#include "qlocale_p.h" QT_BEGIN_NAMESPACE @@ -912,4 +913,222 @@ QT_BEGIN_NAMESPACE \sa QString::toWCharArray() */ +/*! + \fn qint64 QStringView::toLongLong(bool *ok, int base) const + + Returns the string converted to a \c{long long} using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + If \a base is 0, the C language convention is used: If the string + begins with "0x", base 16 is used; if the string begins with "0", + base 8 is used; otherwise, base 10 is used. + + The string conversion will always happen in the 'C' locale. For locale + dependent conversion use QLocale::toLongLong() + + \sa QString::toLongLong() + + \since 6.0 +*/ + +/*! + \fn quint64 QStringView::toULongLong(bool *ok, int base) const + + Returns the string converted to an \c{unsigned long long} using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + If \a base is 0, the C language convention is used: If the string + begins with "0x", base 16 is used; if the string begins with "0", + base 8 is used; otherwise, base 10 is used. + + The string conversion will always happen in the 'C' locale. For locale + dependent conversion use QLocale::toULongLong() + + \sa QString::toULongLong() + + \since 6.0 +*/ + +/*! + \fn long QStringView::toLong(bool *ok, int base) const + + Returns the string converted to a \c long using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + If \a base is 0, the C language convention is used: If the string + begins with "0x", base 16 is used; if the string begins with "0", + base 8 is used; otherwise, base 10 is used. + + The string conversion will always happen in the 'C' locale. For locale + dependent conversion use QLocale::toLong() + + \sa QString::toLong() + + \since 6.0 +*/ + +/*! + \fn ulong QStringView::toULong(bool *ok, int base) const + + Returns the string converted to an \c{unsigned long} using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + If \a base is 0, the C language convention is used: If the string + begins with "0x", base 16 is used; if the string begins with "0", + base 8 is used; otherwise, base 10 is used. + + The string conversion will always happen in the 'C' locale. For locale + dependent conversion use QLocale::toULongLong() + + \sa QString::toULong() + + \since 6.0 +*/ + +/*! + \fn int QStringView::toInt(bool *ok, int base) const + + Returns the string converted to an \c int using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + If \a base is 0, the C language convention is used: If the string + begins with "0x", base 16 is used; if the string begins with "0", + base 8 is used; otherwise, base 10 is used. + + The string conversion will always happen in the 'C' locale. For locale + dependent conversion use QLocale::toInt() + + \sa QString::toInt() + + \since 6.0 +*/ + +/*! + \fn uint QStringView::toUInt(bool *ok, int base) const + + Returns the string converted to an \c{unsigned int} using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + If \a base is 0, the C language convention is used: If the string + begins with "0x", base 16 is used; if the string begins with "0", + base 8 is used; otherwise, base 10 is used. + + The string conversion will always happen in the 'C' locale. For locale + dependent conversion use QLocale::toUInt() + + \sa QString::toUInt() + + \since 6.0 +*/ + +/*! + \fn short QStringView::toShort(bool *ok, int base) const + + Returns the string converted to a \c short using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + If \a base is 0, the C language convention is used: If the string + begins with "0x", base 16 is used; if the string begins with "0", + base 8 is used; otherwise, base 10 is used. + + The string conversion will always happen in the 'C' locale. For locale + dependent conversion use QLocale::toShort() + + \sa QString::toShort() + + \since 6.0 +*/ + +/*! + \fn ushort QStringView::toUShort(bool *ok, int base) const + + Returns the string converted to an \c{unsigned short} using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + Returns 0 if the conversion fails. + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + If \a base is 0, the C language convention is used: If the string + begins with "0x", base 16 is used; if the string begins with "0", + base 8 is used; otherwise, base 10 is used. + + The string conversion will always happen in the 'C' locale. For locale + dependent conversion use QLocale::toUShort() + + \sa QString::toUShort() + + \since 6.0 +*/ + +/*! + \fn double QStringView::toDouble(bool *ok) const + + Returns the string converted to a \c double value. + + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for other reasons (e.g. underflow). + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + The string conversion will always happen in the 'C' locale. For locale + dependent conversion use QLocale::toDouble() + + For historic reasons, this function does not handle + thousands group separators. If you need to convert such numbers, + use QLocale::toDouble(). + + \sa QString::toDouble() + + \since 6.0 +*/ + +/*! + \fn float QStringView::toFloat(bool *ok) const + + Returns the string converted to a \c float value. + + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for other reasons (e.g. underflow). + + If \a ok is not \nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + The string conversion will always happen in the 'C' locale. For locale + dependent conversion use QLocale::toFloat() + + \sa QString::toFloat() + + \since 6.0 +*/ + QT_END_NAMESPACE diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h index 0ae1772530..2b7863e156 100644 --- a/src/corelib/text/qstringview.h +++ b/src/corelib/text/qstringview.h @@ -320,6 +320,17 @@ public: Q_REQUIRED_RESULT bool isValidUtf16() const noexcept { return QtPrivate::isValidUtf16(*this); } + Q_REQUIRED_RESULT inline short toShort(bool *ok = nullptr, int base = 10) const; + Q_REQUIRED_RESULT inline ushort toUShort(bool *ok = nullptr, int base = 10) const; + Q_REQUIRED_RESULT inline int toInt(bool *ok = nullptr, int base = 10) const; + Q_REQUIRED_RESULT inline uint toUInt(bool *ok = nullptr, int base = 10) const; + Q_REQUIRED_RESULT inline long toLong(bool *ok = nullptr, int base = 10) const; + Q_REQUIRED_RESULT inline ulong toULong(bool *ok = nullptr, int base = 10) const; + Q_REQUIRED_RESULT inline qlonglong toLongLong(bool *ok = nullptr, int base = 10) const; + Q_REQUIRED_RESULT inline qulonglong toULongLong(bool *ok = nullptr, int base = 10) const; + Q_REQUIRED_RESULT Q_CORE_EXPORT float toFloat(bool *ok = nullptr) const; + Q_REQUIRED_RESULT Q_CORE_EXPORT double toDouble(bool *ok = nullptr) const; + Q_REQUIRED_RESULT inline int toWCharArray(wchar_t *array) const; // defined in qstring.h // diff --git a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp index ed01d46dcd..0fdad63b24 100644 --- a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp +++ b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp @@ -589,6 +589,20 @@ private Q_SLOTS: void trim_trimmed_QByteArray_data() { trimmed_data(); } void trim_trimmed_QByteArray() { trimmed_impl(); } +private: + void toNumber_data(); + template void toNumber_impl(); + +private Q_SLOTS: + void toNumber_QString_data() { toNumber_data(); } + void toNumber_QString() { toNumber_impl(); } + void toNumber_QStringRef_data() { toNumber_data(); } + void toNumber_QStringRef() { toNumber_impl(); } + void toNumber_QStringView_data() { toNumber_data(); } + void toNumber_QStringView() { toNumber_impl(); } + void toNumber_QByteArray_data() { toNumber_data(); } + void toNumber_QByteArray() { toNumber_impl(); } + // // UTF-16-only checks: // @@ -1600,6 +1614,105 @@ void tst_QStringApiSymmetry::trimmed_impl() } } +void tst_QStringApiSymmetry::toNumber_data() +{ + QTest::addColumn("data"); + QTest::addColumn("result"); + QTest::addColumn("ok"); + + QTest::addRow("0") << QString::fromUtf8("0") << qint64(0) << true; + QTest::addRow("a0") << QString::fromUtf8("a0") << qint64(0) << false; + QTest::addRow("10") << QString::fromUtf8("10") << qint64(10) << true; + QTest::addRow("-10") << QString::fromUtf8("-10") << qint64(-10) << true; + QTest::addRow("32767") << QString::fromUtf8("32767") << qint64(32767) << true; + QTest::addRow("32768") << QString::fromUtf8("32768") << qint64(32768) << true; + QTest::addRow("-32767") << QString::fromUtf8("-32767") << qint64(-32767) << true; + QTest::addRow("-32768") << QString::fromUtf8("-32768") << qint64(-32768) << true; + QTest::addRow("100x") << QString::fromUtf8("100x") << qint64(0) << false; + QTest::addRow("-100x") << QString::fromUtf8("-100x") << qint64(0) << false; +} + +template +bool inRange(qint64 n) +{ + bool checkMax = quint64(std::numeric_limits::max()) <= quint64(std::numeric_limits::max()); + if (checkMax && n > qint64(std::numeric_limits::max())) + return false; + return qint64(std::numeric_limits::min()) <= n; +} + +template +void tst_QStringApiSymmetry::toNumber_impl() +{ + QFETCH(const QString, data); + QFETCH(qint64, result); + QFETCH(bool, ok); + + const auto utf8 = data.toUtf8(); + const auto l1s = data.toLatin1(); + const auto l1 = l1s.isNull() ? QLatin1String() : QLatin1String(l1s); + + const auto ref = data.isNull() ? QStringRef() : QStringRef(&data); + const auto s = make(ref, l1, utf8); + + bool is_ok = false; + qint64 n = 0; + + n = s.toShort(&is_ok); + QCOMPARE(is_ok, ok && inRange(result)); + if (is_ok) + QCOMPARE(n, result); + + n = s.toUShort(&is_ok); + QCOMPARE(is_ok, ok && inRange(result)); + if (is_ok) + QCOMPARE(n, result); + + n = s.toInt(&is_ok); + QCOMPARE(is_ok, ok && inRange(result)); + if (is_ok) + QCOMPARE(n, result); + + n = s.toUInt(&is_ok); + QCOMPARE(is_ok, ok && inRange(result)); + if (is_ok) + QCOMPARE(n, result); + + n = s.toLong(&is_ok); + QCOMPARE(is_ok, ok && inRange(result)); + if (is_ok) + QCOMPARE(n, result); + + n = s.toULong(&is_ok); + QCOMPARE(is_ok, ok && inRange(result)); + if (is_ok) + QCOMPARE(n, result); + + n = s.toLongLong(&is_ok); + QCOMPARE(is_ok, ok && inRange(result)); + if (is_ok) + QCOMPARE(n, result); + + n = s.toULongLong(&is_ok); + QCOMPARE(is_ok, ok && inRange(result)); + if (is_ok) + QCOMPARE(n, result); + + if (qint64(float(n)) == n) { + float f = s.toFloat(&is_ok); + QCOMPARE(is_ok, ok); + if (is_ok) + QCOMPARE(qint64(f), result); + } + + if (qint64(double(n)) == n) { + double d = s.toDouble(&is_ok); + QCOMPARE(is_ok, ok); + if (is_ok) + QCOMPARE(qint64(d), result); + } +} + // // // UTF-16-only checks: -- cgit v1.2.3