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 <volker.hilsheimer@qt.io>
This commit is contained in:
Lars Knoll 2019-12-06 12:03:25 +01:00
parent bf03396ad8
commit beaef85b8d
5 changed files with 371 additions and 0 deletions

View File

@ -12127,4 +12127,14 @@ void QAbstractConcatenable::appendLatin1To(const char *a, int len, QChar *out) n
qt_from_latin1(reinterpret_cast<char16_t *>(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

View File

@ -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<qint64>(*this, ok, base); }
quint64 QStringView::toULongLong(bool *ok, int base) const
{ return QString::toIntegral_helper<quint64>(*this, ok, base); }
long QStringView::toLong(bool *ok, int base) const
{ return QString::toIntegral_helper<long>(*this, ok, base); }
ulong QStringView::toULong(bool *ok, int base) const
{ return QString::toIntegral_helper<ulong>(*this, ok, base); }
int QStringView::toInt(bool *ok, int base) const
{ return QString::toIntegral_helper<int>(*this, ok, base); }
uint QStringView::toUInt(bool *ok, int base) const
{ return QString::toIntegral_helper<uint>(*this, ok, base); }
short QStringView::toShort(bool *ok, int base) const
{ return QString::toIntegral_helper<short>(*this, ok, base); }
ushort QStringView::toUShort(bool *ok, int base) const
{ return QString::toIntegral_helper<ushort>(*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); }

View File

@ -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

View File

@ -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
//

View File

@ -589,6 +589,20 @@ private Q_SLOTS:
void trim_trimmed_QByteArray_data() { trimmed_data(); }
void trim_trimmed_QByteArray() { trimmed_impl<QByteArray>(); }
private:
void toNumber_data();
template <typename String> void toNumber_impl();
private Q_SLOTS:
void toNumber_QString_data() { toNumber_data(); }
void toNumber_QString() { toNumber_impl<QString>(); }
void toNumber_QStringRef_data() { toNumber_data(); }
void toNumber_QStringRef() { toNumber_impl<QStringRef>(); }
void toNumber_QStringView_data() { toNumber_data(); }
void toNumber_QStringView() { toNumber_impl<QStringView>(); }
void toNumber_QByteArray_data() { toNumber_data(); }
void toNumber_QByteArray() { toNumber_impl<QByteArray>(); }
//
// UTF-16-only checks:
//
@ -1600,6 +1614,105 @@ void tst_QStringApiSymmetry::trimmed_impl()
}
}
void tst_QStringApiSymmetry::toNumber_data()
{
QTest::addColumn<QString>("data");
QTest::addColumn<qint64>("result");
QTest::addColumn<bool>("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<typename T>
bool inRange(qint64 n)
{
bool checkMax = quint64(std::numeric_limits<T>::max()) <= quint64(std::numeric_limits<qint64>::max());
if (checkMax && n > qint64(std::numeric_limits<T>::max()))
return false;
return qint64(std::numeric_limits<T>::min()) <= n;
}
template<typename String>
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<String>(ref, l1, utf8);
bool is_ok = false;
qint64 n = 0;
n = s.toShort(&is_ok);
QCOMPARE(is_ok, ok && inRange<short>(result));
if (is_ok)
QCOMPARE(n, result);
n = s.toUShort(&is_ok);
QCOMPARE(is_ok, ok && inRange<ushort>(result));
if (is_ok)
QCOMPARE(n, result);
n = s.toInt(&is_ok);
QCOMPARE(is_ok, ok && inRange<int>(result));
if (is_ok)
QCOMPARE(n, result);
n = s.toUInt(&is_ok);
QCOMPARE(is_ok, ok && inRange<uint>(result));
if (is_ok)
QCOMPARE(n, result);
n = s.toLong(&is_ok);
QCOMPARE(is_ok, ok && inRange<long>(result));
if (is_ok)
QCOMPARE(n, result);
n = s.toULong(&is_ok);
QCOMPARE(is_ok, ok && inRange<ulong>(result));
if (is_ok)
QCOMPARE(n, result);
n = s.toLongLong(&is_ok);
QCOMPARE(is_ok, ok && inRange<qlonglong>(result));
if (is_ok)
QCOMPARE(n, result);
n = s.toULongLong(&is_ok);
QCOMPARE(is_ok, ok && inRange<qulonglong>(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: