From 60dd5451a243253d9f810f9d3cddca4a152f82a7 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 25 Jun 2020 14:28:57 +0200 Subject: [PATCH] Port QLatin1String to qsizetype and add narrow-contract substring functions QLatin1String::mid() etc were changed from narrow to wide contract, but the narrow-contract replacements weren't added. This blocks using the narrow-contract functions in QStringTokenizer. As a drive-by, Q_REQUIRED_RESULT -> [[nodiscard]] and Q_DECL_CONSTEXPR -> constexpr. Also centralize most Q_ASSERT()s in a single function, verify(), in an attempt to reduce the amount of string data generated from the asserts in assertive builds. [ChangeLog][QtCore][QLatin1String] Added from(), sliced(), first(n), last(n) functions. [ChangeLog][QtCore][QLatin1String] size_type/size() is now qsizetype (was: int). This makes QLatin1String(ptr, 0) ambiguous now between the (ptr, ptr) and (ptr, qsizetype) constructors. Change-Id: Ie195f66ae1974eb0752c058aa9f3b0853ed92477 Reviewed-by: Lars Knoll Reviewed-by: Thiago Macieira --- src/corelib/text/qstring.cpp | 156 +++++++++++++----- src/corelib/text/qstring.h | 86 ++++++---- src/corelib/text/qstringbuilder.h | 2 +- .../text/qlatin1string/tst_qlatin1string.cpp | 2 +- .../tst_qstringapisymmetry.cpp | 6 + 5 files changed, 169 insertions(+), 83 deletions(-) diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 3e7e9df35c..879a7e5cd7 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -1275,7 +1275,7 @@ static int qt_compare_strings(QLatin1String lhs, QStringView rhs, Qt::CaseSensit static int qt_compare_strings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) noexcept { if (lhs.isEmpty()) - return lencmp(0, rhs.size()); + return lencmp(qsizetype(0), rhs.size()); if (cs == Qt::CaseInsensitive) return latin1nicmp(lhs.data(), lhs.size(), rhs.data(), rhs.size()); const auto l = std::min(lhs.size(), rhs.size()); @@ -8641,6 +8641,10 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) \since 5.10 Alias for \c{qsizetype}. Provided for compatibility with the STL. + + \note In version prior to Qt 6, this was an alias for \c{int}, + restricting the amount of data that could be held in a QLatin1String + on 64-bit architectures. */ /*! @@ -8708,7 +8712,7 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) \sa latin1() */ -/*! \fn QLatin1String::QLatin1String(const char *str, int size) +/*! \fn QLatin1String::QLatin1String(const char *str, qsizetype size) Constructs a QLatin1String object that stores \a str with \a size. @@ -8768,9 +8772,13 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) Returns the Latin-1 string stored in this object. */ -/*! \fn int QLatin1String::size() const +/*! \fn QLatin1String::size() const Returns the size of the Latin-1 string stored in this object. + + \note In version prior to Qt 6, this function returned \c{int}, + restricting the amount of data that could be held in a QLatin1String + on 64-bit architectures. */ /*! \fn bool QLatin1String::isNull() const @@ -8791,7 +8799,7 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) \sa isNull(), size() */ -/*! \fn QLatin1Char QLatin1String::at(int pos) const +/*! \fn QLatin1Char QLatin1String::at(qsizetype pos) const \since 5.8 Returns the character at position \a pos in this object. @@ -8802,7 +8810,7 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) \sa operator[]() */ -/*! \fn QLatin1Char QLatin1String::operator[](int pos) const +/*! \fn QLatin1Char QLatin1String::operator[](qsizetype pos) const \since 5.8 Returns the character at position \a pos in this object. @@ -8901,9 +8909,9 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) */ /*! - \fn int QLatin1String::indexOf(QStringView str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const - \fn int QLatin1String::indexOf(QLatin1String l1, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const - \fn int QLatin1String::indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \fn int QLatin1String::indexOf(QStringView str, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \fn int QLatin1String::indexOf(QLatin1String l1, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \fn int QLatin1String::indexOf(QChar c, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const \since 5.14 Returns the index position of the first occurrence of the string-view \a str, @@ -8935,9 +8943,9 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) */ /*! - \fn int QLatin1String::lastIndexOf(QStringView str, int from, Qt::CaseSensitivity cs) const - \fn int QLatin1String::lastIndexOf(QLatin1String l1, int from, Qt::CaseSensitivity cs) const - \fn int QLatin1String::lastIndexOf(QChar c, int from, Qt::CaseSensitivity cs) const + \fn int QLatin1String::lastIndexOf(QStringView str, qsizetype from, Qt::CaseSensitivity cs) const + \fn int QLatin1String::lastIndexOf(QLatin1String l1, qsizetype from, Qt::CaseSensitivity cs) const + \fn int QLatin1String::lastIndexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs) const \since 5.14 Returns the index position of the last occurrence of the string-view \a str, @@ -9043,47 +9051,105 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) \sa crbegin(), rend(), cend() */ -/*! \fn QLatin1String QLatin1String::mid(int start, int length) const +/*! + \fn QLatin1String::mid(qsizetype start, qsizetype length) const \since 5.8 Returns the substring of length \a length starting at position - \a start in this object. + \a start in this Latin-1 string. - Returns a null string if the \a start index exceeds the - length of the string. If there are less than \a length characters - available in the string starting at \a start, or if - \a length is negative (default), the function returns all characters - that are available from \a start. + \obsolete Use sliced() instead in new code. - \sa left(), right(), chopped(), chop(), truncate() -*/ + Returns an empty Latin-1 string if \a start exceeds the + length of this Latin-1 string. If there are less than \a length characters + available in this Latin-1 string starting at \a start, or if + \a length is negative (default), the function returns all characters that + are available from \a start. -/*! \fn QLatin1String QLatin1String::left(int length) const - \since 5.8 - - Returns the substring of length \a length starting at position - 0 in this object. - - The entire string is returned if \a length is greater than or equal - to size(), or less than zero. - - \sa mid(), right(), chopped(), chop(), truncate() -*/ - -/*! \fn QLatin1String QLatin1String::right(int length) const - \since 5.8 - - Returns the substring of length \a length starting at position - size() - \a length in this object. - - The entire string is returned if \a length is greater than or equal - to size(), or less than zero. - - \sa mid(), left(), chopped(), chop(), truncate() + \sa first(), last(), sliced(), chopped(), chop(), truncate() */ /*! - \fn QLatin1String QLatin1String::chopped(int length) const + \fn QLatin1String::left(qsizetype length) const + \since 5.8 + + \obsolete Use first() instead in new code. + + Returns the substring of length \a length starting at position + 0 in this Latin-1 string. + + The entire Latin-1 string is returned if \a length is greater than or equal + to size(), or less than zero. + + \sa first(), last(), sliced(), startsWith(), chopped(), chop(), truncate() +*/ + +/*! + \fn QLatin1String::right(qsizetype length) const + \since 5.8 + + \obsolete Use last() instead in new code. + + Returns the substring of length \a length starting at position + size() - \a length in this Latin-1 string. + + The entire Latin-1 string is returned if \a length is greater than or equal + to size(), or less than zero. + + \sa first(), last(), sliced(), endsWith(), chopped(), chop(), truncate() +*/ + +/*! + \fn QLatin1String::first(qsizetype n) const + \since 6.0 + + Returns a Latin-1 string that contains the first \a n characters + of this Latin-1 string. + + \note The behavior is undefined when \a n < 0 or \a n > size(). + + \sa last(), subString(), startsWith(), chopped(), chop(), truncate() +*/ + +/*! + \fn QLatin1String::last(qsizetype n) const + \since 6.0 + + Returns a Latin-1 string that contains the last \a n characters + of this Latin-1 string. + + \note The behavior is undefined when \a n < 0 or \a n > size(). + + \sa first(), subString(), endsWith(), chopped(), chop(), truncate() +*/ + +/*! + \fn QLatin1String::sliced(qsizetype pos, qsizetype n) const + \since 6.0 + + Returns a Latin-1 string that points to \a n characters of this + Latin-1 string, starting at position \a pos. + + \note The behavior is undefined when \a pos < 0, \a n < 0, + or \c{pos + n > size()}. + + \sa first(), last(), chopped(), chop(), truncate() +*/ + +/*! + \fn QLatin1String::sliced(qsizetype pos) const + \since 6.0 + + Returns a Latin-1 string starting at position \a pos in this + Latin-1 string, and extending to its end. + + \note The behavior is undefined when \a pos < 0 or \a pos > size(). + + \sa first(), last(), chopped(), chop(), truncate() +*/ + +/*! + \fn QLatin1String QLatin1String::chopped(qsizetype length) const \since 5.10 Returns the substring of length size() - \a length starting at the @@ -9097,7 +9163,7 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) */ /*! - \fn void QLatin1String::truncate(int length) + \fn void QLatin1String::truncate(qsizetype length) \since 5.10 Truncates this string to length \a length. @@ -9110,7 +9176,7 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) */ /*! - \fn void QLatin1String::chop(int length) + \fn void QLatin1String::chop(qsizetype length) \since 5.10 Truncates this string by \a length characters. diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index df1fb64f29..1e0d7f480a 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -85,16 +85,16 @@ class QLatin1String { public: constexpr inline QLatin1String() noexcept : m_size(0), m_data(nullptr) {} - constexpr inline explicit QLatin1String(const char *s) noexcept : m_size(s ? int(strlen(s)) : 0), m_data(s) {} + constexpr inline explicit QLatin1String(const char *s) noexcept : m_size(s ? qsizetype(strlen(s)) : 0), m_data(s) {} constexpr explicit QLatin1String(const char *f, const char *l) - : QLatin1String(f, int(l - f)) {} - constexpr inline explicit QLatin1String(const char *s, int sz) noexcept : m_size(sz), m_data(s) {} - inline explicit QLatin1String(const QByteArray &s) noexcept : m_size(int(qstrnlen(s.constData(), s.size()))), m_data(s.constData()) {} + : QLatin1String(f, qsizetype(l - f)) {} + constexpr inline explicit QLatin1String(const char *s, qsizetype sz) noexcept : m_size(sz), m_data(s) {} + explicit QLatin1String(const QByteArray &s) noexcept : m_size(qsizetype(qstrnlen(s.constData(), s.size()))), m_data(s.constData()) {} inline QString toString() const; constexpr const char *latin1() const noexcept { return m_data; } - constexpr int size() const noexcept { return m_size; } + constexpr qsizetype size() const noexcept { return m_size; } constexpr const char *data() const noexcept { return m_data; } constexpr bool isNull() const noexcept { return !data(); } @@ -103,9 +103,9 @@ public: template Q_REQUIRED_RESULT inline QString arg(Args &&...args) const; - constexpr QLatin1Char at(int i) const + [[nodiscard]] constexpr QLatin1Char at(qsizetype i) const { return Q_ASSERT(i >= 0), Q_ASSERT(i < size()), QLatin1Char(m_data[i]); } - constexpr QLatin1Char operator[](int i) const { return at(i); } + [[nodiscard]] constexpr QLatin1Char operator[](qsizetype i) const { return at(i); } Q_REQUIRED_RESULT constexpr QLatin1Char front() const { return at(0); } Q_REQUIRED_RESULT constexpr QLatin1Char back() const { return at(size() - 1); } @@ -137,12 +137,12 @@ public: Q_REQUIRED_RESULT inline bool endsWith(QChar c, Qt::CaseSensitivity cs) const noexcept { return QtPrivate::endsWith(*this, QStringView(&c, 1), cs); } - Q_REQUIRED_RESULT int indexOf(QStringView s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept - { return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsizetype - Q_REQUIRED_RESULT int indexOf(QLatin1String s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept - { return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsizetype - Q_REQUIRED_RESULT inline int indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept - { return int(QtPrivate::findString(*this, from, QStringView(&c, 1), cs)); } // ### Qt6: qsizetype + [[nodiscard]] qsizetype indexOf(QStringView s, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return QtPrivate::findString(*this, from, s, cs); } + [[nodiscard]] qsizetype indexOf(QLatin1String s, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return QtPrivate::findString(*this, from, s, cs); } + [[nodiscard]] qsizetype indexOf(QChar c, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return QtPrivate::findString(*this, from, QStringView(&c, 1), cs); } Q_REQUIRED_RESULT bool contains(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return indexOf(s, 0, cs) != -1; } @@ -151,20 +151,20 @@ public: Q_REQUIRED_RESULT inline bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return indexOf(QStringView(&c, 1), 0, cs) != -1; } - Q_REQUIRED_RESULT int lastIndexOf(QStringView s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept - { return int(QtPrivate::lastIndexOf(*this, from, s, cs)); } // ### Qt6: qsizetype - Q_REQUIRED_RESULT int lastIndexOf(QLatin1String s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept - { return int(QtPrivate::lastIndexOf(*this, from, s, cs)); } // ### Qt6: qsizetype - Q_REQUIRED_RESULT inline int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept - { return int(QtPrivate::lastIndexOf(*this, from, QStringView(&c, 1), cs)); } // ### Qt6: qsizetype + [[nodiscard]] qsizetype lastIndexOf(QStringView s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return QtPrivate::lastIndexOf(*this, from, s, cs); } + [[nodiscard]] qsizetype lastIndexOf(QLatin1String s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return QtPrivate::lastIndexOf(*this, from, s, cs); } + [[nodiscard]] qsizetype lastIndexOf(QChar c, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept + { return QtPrivate::lastIndexOf(*this, from, QStringView(&c, 1), cs); } using value_type = const char; using reference = value_type&; using const_reference = reference; using iterator = value_type*; using const_iterator = iterator; - using difference_type = int; // violates Container concept requirements - using size_type = int; // violates Container concept requirements + using difference_type = qsizetype; // violates Container concept requirements + using size_type = qsizetype; // violates Container concept requirements constexpr const_iterator begin() const noexcept { return data(); } constexpr const_iterator cbegin() const noexcept { return data(); } @@ -179,33 +179,40 @@ public: const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } - constexpr QLatin1String mid(int pos, int n = -1) const + [[nodiscard]] constexpr QLatin1String mid(qsizetype pos, qsizetype n = -1) const { - qsizetype p = pos; - qsizetype l = n; using namespace QtPrivate; - auto result = QContainerImplHelper::mid(size(), &p, &l); - return result == QContainerImplHelper::Null ? QLatin1String() : QLatin1String(m_data + p, l); + auto result = QContainerImplHelper::mid(size(), &pos, &n); + return result == QContainerImplHelper::Null ? QLatin1String() : QLatin1String(m_data + pos, n); } - constexpr QLatin1String left(int n) const + [[nodiscard]] constexpr QLatin1String left(qsizetype n) const { if (size_t(n) >= size_t(size())) n = size(); return QLatin1String(m_data, n); } - constexpr QLatin1String right(int n) const + [[nodiscard]] constexpr QLatin1String right(qsizetype n) const { if (size_t(n) >= size_t(size())) n = size(); return QLatin1String(m_data + m_size - n, n); } - Q_REQUIRED_RESULT constexpr QLatin1String chopped(int n) const - { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QLatin1String(m_data, m_size - n); } - constexpr void chop(int n) - { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size -= n; } - constexpr void truncate(int n) - { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size = n; } + [[nodiscard]] constexpr QLatin1String sliced(qsizetype pos) const + { verify(pos); return QLatin1String(m_data + pos, m_size - pos); } + [[nodiscard]] constexpr QLatin1String sliced(qsizetype pos, qsizetype n) const + { verify(pos, n); return QLatin1String(m_data + pos, n); } + [[nodiscard]] constexpr QLatin1String first(qsizetype n) const + { verify(n); return QLatin1String(m_data, n); } + [[nodiscard]] constexpr QLatin1String last(qsizetype n) const + { verify(n); return QLatin1String(m_data + size() - n, n); } + [[nodiscard]] constexpr QLatin1String chopped(qsizetype n) const + { verify(n); return QLatin1String(m_data, size() - n); } + + constexpr void chop(qsizetype n) + { verify(n); m_size -= n; } + constexpr void truncate(qsizetype n) + { verify(n); m_size = n; } Q_REQUIRED_RESULT QLatin1String trimmed() const noexcept { return QtPrivate::trimmed(*this); } @@ -239,7 +246,14 @@ public: #endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) private: - int m_size; + Q_ALWAYS_INLINE constexpr void verify(qsizetype pos, qsizetype n = 0) const + { + Q_ASSERT(pos >= 0); + Q_ASSERT(pos <= size()); + Q_ASSERT(n >= 0); + Q_ASSERT(n <= size() - pos); + } + qsizetype m_size; const char *m_data; }; Q_DECLARE_TYPEINFO(QLatin1String, Q_MOVABLE_TYPE); @@ -1142,7 +1156,7 @@ inline bool operator!=(QLatin1String s1, QLatin1String s2) noexcept { return !operator==(s1, s2); } inline bool operator<(QLatin1String s1, QLatin1String s2) noexcept { - const int len = qMin(s1.size(), s2.size()); + const qsizetype len = qMin(s1.size(), s2.size()); const int r = len ? memcmp(s1.latin1(), s2.latin1(), len) : 0; return r < 0 || (r == 0 && s1.size() < s2.size()); } diff --git a/src/corelib/text/qstringbuilder.h b/src/corelib/text/qstringbuilder.h index e5a3a59eb2..31d1526e1e 100644 --- a/src/corelib/text/qstringbuilder.h +++ b/src/corelib/text/qstringbuilder.h @@ -236,7 +236,7 @@ template <> struct QConcatenable : private QAbstractConcatenable typedef QLatin1String type; typedef QString ConvertTo; enum { ExactSize = true }; - static int size(const QLatin1String a) { return a.size(); } + static int size(const QLatin1String a) { return int(a.size()); } // ### Qt 6: qsizetype static inline void appendTo(const QLatin1String a, QChar *&out) { appendLatin1To(a.latin1(), a.size(), out); diff --git a/tests/auto/corelib/text/qlatin1string/tst_qlatin1string.cpp b/tests/auto/corelib/text/qlatin1string/tst_qlatin1string.cpp index 0427c81b85..2ced8c5bf0 100644 --- a/tests/auto/corelib/text/qlatin1string/tst_qlatin1string.cpp +++ b/tests/auto/corelib/text/qlatin1string/tst_qlatin1string.cpp @@ -177,7 +177,7 @@ void tst_QLatin1String::emptyString() { const char *notEmpty = "foo"; - QLatin1String l1(notEmpty, 0); + QLatin1String l1(notEmpty, qsizetype(0)); QCOMPARE(static_cast(l1.data()), static_cast(notEmpty)); QCOMPARE(l1.size(), 0); diff --git a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp index 9e1c9012ad..17d209ce69 100644 --- a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp +++ b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp @@ -536,6 +536,8 @@ private Q_SLOTS: void sliced_QString() { sliced_impl(); } void sliced_QStringView_data() { sliced_data(); } void sliced_QStringView() { sliced_impl(); } + void sliced_QLatin1String_data() { sliced_data(); } + void sliced_QLatin1String() { sliced_impl(); } void sliced_QByteArray_data() { sliced_data(); } void sliced_QByteArray() { sliced_impl(); } @@ -543,6 +545,8 @@ private Q_SLOTS: void first_truncate_QString() { first_impl(); } void first_truncate_QStringView_data() { first_data(); } void first_truncate_QStringView() { first_impl(); } + void first_truncate_QLatin1String_data() { first_data(); } + void first_truncate_QLatin1String() { first_impl(); } void first_truncate_QByteArray_data() { first_data(); } void first_truncate_QByteArray() { first_impl(); } @@ -550,6 +554,8 @@ private Q_SLOTS: void last_QString() { last_impl(); } void last_QStringView_data() { last_data(); } void last_QStringView() { last_impl(); } + void last_QLatin1String_data() { last_data(); } + void last_QLatin1String() { last_impl(); } void last_QByteArray_data() { last_data(); } void last_QByteArray() { last_impl(); }