diff options
Diffstat (limited to 'src/corelib/text/qstring.cpp')
-rw-r--r-- | src/corelib/text/qstring.cpp | 182 |
1 files changed, 104 insertions, 78 deletions
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 65a0bed949..59ef2b2f59 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -493,8 +493,8 @@ const char16_t *QtPrivate::qustrchr(QStringView str, char16_t c) noexcept } return UnrollTailLoop<3>::exec(e - n, e, - [=](int i) { return n[i] == c; }, - [=](int i) { return n + i; }); + [=](qsizetype i) { return n[i] == c; }, + [=](qsizetype i) { return n + i; }); # endif #elif defined(__ARM_NEON__) const uint16x8_t vmask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 }; @@ -812,7 +812,7 @@ Q_CORE_EXPORT void qt_from_latin1(char16_t *dst, const char *str, size_t size) n dst += offset; str += offset; # if !defined(__OPTIMIZE_SIZE__) - return UnrollTailLoop<7>::exec(int(size), [=](int i) { dst[i] = (uchar)str[i]; }); + return UnrollTailLoop<7>::exec(qsizetype(size), [=](qsizetype i) { dst[i] = (uchar)str[i]; }); # endif #endif #if defined(__mips_dsp) @@ -939,7 +939,7 @@ static void qt_to_latin1_internal(uchar *dst, const char16_t *src, qsizetype len src += offset; # if !defined(__OPTIMIZE_SIZE__) - return UnrollTailLoop<3>::exec(length, [=](int i) { + return UnrollTailLoop<3>::exec(length, [=](qsizetype i) { if (Checked) dst[i] = (src[i]>0xff) ? '?' : (uchar) src[i]; else @@ -2652,11 +2652,11 @@ void QString::resize(qsizetype size) \snippet qstring/main.cpp 46 */ -void QString::resize(qsizetype size, QChar fillChar) +void QString::resize(qsizetype newSize, QChar fillChar) { - const qsizetype oldSize = length(); - resize(size); - const qsizetype difference = length() - oldSize; + const qsizetype oldSize = size(); + resize(newSize); + const qsizetype difference = size() - oldSize; if (difference > 0) std::fill_n(d.data() + oldSize, difference, fillChar.unicode()); } @@ -3040,6 +3040,14 @@ QString &QString::append(const QString &str) } /*! + \fn QString &QString::append(QStringView v) + \overload append() + \since 6.0 + + Appends the given string view \a v to this string and returns the result. +*/ + +/*! \overload append() \since 5.0 @@ -3380,7 +3388,7 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs) */ QString &QString::replace(qsizetype pos, qsizetype len, const QString &after) { - return replace(pos, len, after.constData(), after.length()); + return replace(pos, len, after.constData(), after.size()); } /*! @@ -4102,7 +4110,7 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity */ qsizetype QString::indexOf(const QString &str, qsizetype from, Qt::CaseSensitivity cs) const { - return QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs); + return QtPrivate::findString(QStringView(unicode(), size()), from, QStringView(str.unicode(), str.size()), cs); } /*! @@ -4156,7 +4164,7 @@ qsizetype QString::indexOf(QLatin1StringView str, qsizetype from, Qt::CaseSensit */ qsizetype QString::indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const { - return qFindChar(QStringView(unicode(), length()), ch, from, cs); + return qFindChar(QStringView(unicode(), size()), ch, from, cs); } /*! @@ -4356,7 +4364,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after) // 1. build the backreferences list, holding where the backreferences // are in the replacement string QList<QStringCapture> backReferences; - const qsizetype al = after.length(); + const qsizetype al = after.size(); const QChar *ac = after.unicode(); for (qsizetype i = 0; i < al - 1; i++) { @@ -4401,7 +4409,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after) lastEnd = 0; // add the after string, with replacements for the backreferences - for (const QStringCapture &backReference : qAsConst(backReferences)) { + for (const QStringCapture &backReference : std::as_const(backReferences)) { // part of "after" before the backreference len = backReference.pos - lastEnd; if (len > 0) { @@ -4420,7 +4428,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after) } // add the last part of the after string - len = afterView.length() - lastEnd; + len = afterView.size() - lastEnd; if (len > 0) { chunks << afterView.mid(lastEnd, len); newLength += len; @@ -4430,17 +4438,17 @@ QString &QString::replace(const QRegularExpression &re, const QString &after) } // 3. trailing string after the last match - if (copyView.length() > lastEnd) { + if (copyView.size() > lastEnd) { chunks << copyView.mid(lastEnd); - newLength += copyView.length() - lastEnd; + newLength += copyView.size() - lastEnd; } // 4. assemble the chunks together resize(newLength); qsizetype i = 0; QChar *uc = data(); - for (const QStringView &chunk : qAsConst(chunks)) { - qsizetype len = chunk.length(); + for (const QStringView &chunk : std::as_const(chunks)) { + qsizetype len = chunk.size(); memcpy(uc + i, chunk.constData(), len * sizeof(QChar)); i += len; } @@ -4803,7 +4811,7 @@ static QString extractSections(const QList<qt_section_chunk> §ions, qsizetyp qsizetype skip = 0; for (qsizetype k = 0; k < sectionsSize; ++k) { const qt_section_chunk §ion = sections.at(k); - if (section.length == section.string.length()) + if (section.length == section.string.size()) skip++; } if (start < 0) @@ -4819,7 +4827,7 @@ static QString extractSections(const QList<qt_section_chunk> §ions, qsizetyp qsizetype first_i = start, last_i = end; for (qsizetype i = 0; x <= end && i < sectionsSize; ++i) { const qt_section_chunk §ion = sections.at(i); - const bool empty = (section.length == section.string.length()); + const bool empty = (section.length == section.string.size()); if (x >= start) { if (x == start) first_i = i; @@ -4878,7 +4886,7 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp sep.setPatternOptions(sep.patternOptions() | QRegularExpression::CaseInsensitiveOption); QList<qt_section_chunk> sections; - qsizetype n = length(), m = 0, last_m = 0, last_len = 0; + qsizetype n = size(), m = 0, last_m = 0, last_len = 0; QRegularExpressionMatchIterator iterator = sep.globalMatch(*this); while (iterator.hasNext()) { QRegularExpressionMatch match = iterator.next(); @@ -5236,7 +5244,7 @@ static QByteArray qt_convert_to_latin1(QStringView string) if (Q_UNLIKELY(string.isNull())) return QByteArray(); - QByteArray ba(string.length(), Qt::Uninitialized); + QByteArray ba(string.size(), Qt::Uninitialized); // since we own the only copy, we're going to const_cast the constData; // that avoids an unnecessary call to detach() and expansion code that will never get used @@ -5405,7 +5413,7 @@ QList<uint> QString::toUcs4() const static QList<uint> qt_convert_to_ucs4(QStringView string) { - QList<uint> v(string.length()); + QList<uint> v(string.size()); uint *a = const_cast<uint*>(v.constData()); QStringIterator it(string); while (it.hasNext()) @@ -5610,7 +5618,7 @@ QString QString::fromUtf8(QByteArrayView ba) host byte order is assumed. This function is slow compared to the other Unicode conversions. - Use QString(const QChar *, int) or QString(const QChar *) if possible. + Use QString(const QChar *, qsizetype) or QString(const QChar *) if possible. QString makes a deep copy of the Unicode data. @@ -6361,7 +6369,7 @@ int QLatin1StringView::compare_helper(const QChar *data1, qsizetype length1, QLa */ int QString::localeAwareCompare(const QString &other) const { - return localeAwareCompare_helper(constData(), length(), other.constData(), other.length()); + return localeAwareCompare_helper(constData(), size(), other.constData(), other.size()); } /*! @@ -6477,7 +6485,7 @@ const ushort *QString::utf16() const QString QString::leftJustified(qsizetype width, QChar fill, bool truncate) const { QString result; - qsizetype len = length(); + qsizetype len = size(); qsizetype padlen = width - len; if (padlen > 0) { result.resize(len+padlen); @@ -6516,7 +6524,7 @@ QString QString::leftJustified(qsizetype width, QChar fill, bool truncate) const QString QString::rightJustified(qsizetype width, QChar fill, bool truncate) const { QString result; - qsizetype len = length(); + qsizetype len = size(); qsizetype padlen = width - len; if (padlen > 0) { result.resize(len+padlen); @@ -6759,14 +6767,14 @@ static int parse_field_width(const char *&c, qsizetype size) // can't be negative - started with a digit // contains at least one digit - const char *endp; - bool ok; - const qulonglong result = qstrntoull(c, size, &endp, 10, &ok); + auto [result, endp] = qstrntoull(c, size, 10); c = endp; + if (!endp) + return false; // preserve Qt 5.5 behavior of consuming all digits, no matter how many while (c < stop && qIsDigit(*c)) ++c; - return ok && result < qulonglong(std::numeric_limits<int>::max()) ? int(result) : 0; + return result < qulonglong(std::numeric_limits<int>::max()) ? int(result) : 0; } enum LengthMod { lm_none, lm_hh, lm_h, lm_l, lm_ll, lm_L, lm_j, lm_z, lm_t }; @@ -6872,6 +6880,7 @@ QString QString::vasprintf(const char *cformat, va_list ap) int precision = -1; // -1 means unspecified if (*c == '.') { ++c; + precision = 0; if (qIsDigit(*c)) { precision = parse_field_width(c, formatEnd - c); } else if (*c == '*') { // can't parse this in another function, not portably, at least @@ -7017,27 +7026,27 @@ QString QString::vasprintf(const char *cformat, va_list ap) switch (length_mod) { case lm_hh: { signed char *n = va_arg(ap, signed char*); - *n = result.length(); + *n = result.size(); break; } case lm_h: { short int *n = va_arg(ap, short int*); - *n = result.length(); + *n = result.size(); break; } case lm_l: { long int *n = va_arg(ap, long int*); - *n = result.length(); + *n = result.size(); break; } case lm_ll: { qint64 *n = va_arg(ap, qint64*); - *n = result.length(); + *n = result.size(); break; } default: { int *n = va_arg(ap, int*); - *n = result.length(); + *n = result.size(); break; } } @@ -7100,7 +7109,9 @@ qlonglong QString::toIntegral_helper(QStringView string, bool *ok, int base) } #endif - return QLocaleData::c()->stringToLongLong(string, base, ok, QLocale::RejectGroupSeparator); + QVarLengthArray<uchar> latin1(string.size()); + qt_to_latin1(latin1.data(), string.utf16(), string.size()); + return QLocaleData::bytearrayToLongLong(latin1, base, ok); } @@ -7145,7 +7156,9 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base) } #endif - return QLocaleData::c()->stringToUnsLongLong(string, base, ok, QLocale::RejectGroupSeparator); + QVarLengthArray<uchar> latin1(string.size()); + qt_to_latin1(latin1.data(), string.utf16(), string.size()); + return QLocaleData::bytearrayToUnsLongLong(latin1, base, ok); } /*! @@ -7356,6 +7369,11 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base) double QString::toDouble(bool *ok) const { + return QStringView(*this).toDouble(ok); +} + +double QStringView::toDouble(bool *ok) const +{ return QLocaleData::c()->stringToDouble(*this, ok, QLocale::RejectGroupSeparator); } @@ -7394,6 +7412,11 @@ float QString::toFloat(bool *ok) const return QLocaleData::convertDoubleToFloat(toDouble(ok), ok); } +float QStringView::toFloat(bool *ok) const +{ + return QLocaleData::convertDoubleToFloat(toDouble(ok), ok); +} + /*! \fn QString &QString::setNum(int n, int base) Sets the string to the printed value of \a n in the specified \a @@ -7671,14 +7694,15 @@ QStringList QString::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensit \fn QList<QStringView> QStringView::split(QStringView sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const - Splits the string into substring views wherever \a sep occurs, and + Splits the view into substring views wherever \a sep occurs, and returns the list of those string views. See QString::split() for how \a sep, \a behavior and \a cs interact to form the result. - \note All views are valid as long as this string is. Destroying this - string will cause all views to be dangling pointers. + \note All the returned views are valid as long as the data referenced by + this string view is valid. Destroying the data will cause all views to + become dangling. \since 6.0 */ @@ -7839,7 +7863,7 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar:: // check if it's fully ASCII first, because then we have no work auto start = reinterpret_cast<const char16_t *>(data->constData()); const char16_t *p = start + from; - if (isAscii_helper(p, p + data->length() - from)) + if (isAscii_helper(p, p + data->size() - from)) return; if (p > start + from) from = p - start - 1; // need one before the non-ASCII to perform NFC @@ -7859,7 +7883,7 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar:: char16_t ucs4Low = QChar::lowSurrogate(n.ucs4); char16_t oldHigh = QChar::highSurrogate(n.old_mapping); char16_t oldLow = QChar::lowSurrogate(n.old_mapping); - while (pos < s.length() - 1) { + while (pos < s.size() - 1) { if (s.at(pos).unicode() == ucs4High && s.at(pos + 1).unicode() == ucs4Low) { if (!d) d = data->data(); @@ -7869,7 +7893,7 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar:: ++pos; } } else { - while (pos < s.length()) { + while (pos < s.size()) { if (s.at(pos).unicode() == n.ucs4) { if (!d) d = data->data(); @@ -7938,9 +7962,9 @@ static void checkArgEscape(QStringView s) struct ArgEscapeData { int min_escape; // lowest escape sequence number - int occurrences; // number of occurrences of the lowest escape sequence number - int locale_occurrences; // number of occurrences of the lowest escape sequence number that - // contain 'L' + qsizetype occurrences; // number of occurrences of the lowest escape sequence number + qsizetype locale_occurrences; // number of occurrences of the lowest escape sequence number that + // contain 'L' qsizetype escape_len; // total length of escape sequences which will be replaced }; @@ -8026,14 +8050,14 @@ static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetyp // Negative field-width for right-padding, positive for left-padding: const qsizetype abs_field_width = qAbs(field_width); const qsizetype result_len = - s.length() - d.escape_len - + (d.occurrences - d.locale_occurrences) * qMax(abs_field_width, arg.length()) - + d.locale_occurrences * qMax(abs_field_width, larg.length()); + s.size() - d.escape_len + + (d.occurrences - d.locale_occurrences) * qMax(abs_field_width, arg.size()) + + d.locale_occurrences * qMax(abs_field_width, larg.size()); QString result(result_len, Qt::Uninitialized); QChar *rc = const_cast<QChar *>(result.unicode()); QChar *const result_end = rc + result_len; - int repl_cnt = 0; + qsizetype repl_cnt = 0; const QChar *c = s.begin(); const QChar *const uc_end = s.end(); @@ -8071,7 +8095,7 @@ static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetyp rc += escape_start - text_start; const QStringView use = localize ? larg : arg; - const qsizetype pad_chars = abs_field_width - use.length(); + const qsizetype pad_chars = abs_field_width - use.size(); // (If negative, relevant loops are no-ops: no need to check.) if (field_width > 0) { // left padded @@ -8079,8 +8103,8 @@ static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetyp *rc++ = fillChar; } - memcpy(rc, use.data(), use.length() * sizeof(QChar)); - rc += use.length(); + memcpy(rc, use.data(), use.size() * sizeof(QChar)); + rc += use.size(); if (field_width < 0) { // right padded for (qsizetype i = 0; i < pad_chars; ++i) @@ -8314,7 +8338,7 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) cons if (d.occurrences > d.locale_occurrences) { arg = QLocaleData::c()->longLongToString(a, -1, base, fieldWidth, flags); Q_ASSERT(fillChar != u'0' || !qIsFinite(a) - || fieldWidth <= arg.length()); + || fieldWidth <= arg.size()); } QString localeArg; @@ -8324,7 +8348,7 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) cons flags |= QLocaleData::GroupDigits; localeArg = locale.d->m_data->longLongToString(a, -1, base, fieldWidth, flags); Q_ASSERT(fillChar != u'0' || !qIsFinite(a) - || fieldWidth <= localeArg.length()); + || fieldWidth <= localeArg.size()); } return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar); @@ -8362,7 +8386,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) con if (d.occurrences > d.locale_occurrences) { arg = QLocaleData::c()->unsLongLongToString(a, -1, base, fieldWidth, flags); Q_ASSERT(fillChar != u'0' || !qIsFinite(a) - || fieldWidth <= arg.length()); + || fieldWidth <= arg.size()); } QString localeArg; @@ -8372,7 +8396,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) con flags |= QLocaleData::GroupDigits; localeArg = locale.d->m_data->unsLongLongToString(a, -1, base, fieldWidth, flags); Q_ASSERT(fillChar != u'0' || !qIsFinite(a) - || fieldWidth <= localeArg.length()); + || fieldWidth <= localeArg.size()); } return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar); @@ -8484,7 +8508,7 @@ QString QString::arg(double a, int fieldWidth, char format, int precision, QChar arg = QLocaleData::c()->doubleToString(a, precision, form, fieldWidth, flags | QLocaleData::ZeroPadExponent); Q_ASSERT(fillChar != u'0' || !qIsFinite(a) - || fieldWidth <= arg.length()); + || fieldWidth <= arg.size()); } QString localeArg; @@ -8500,7 +8524,7 @@ QString QString::arg(double a, int fieldWidth, char format, int precision, QChar flags |= QLocaleData::AddTrailingZeroes; localeArg = locale.d->m_data->doubleToString(a, precision, form, fieldWidth, flags); Q_ASSERT(fillChar != u'0' || !qIsFinite(a) - || fieldWidth <= localeArg.length()); + || fieldWidth <= localeArg.size()); } return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar); @@ -8995,8 +9019,8 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) \c{const char *} instead of QString. This includes the copy constructor, the assignment operator, the comparison operators, and various other functions such as \l{QString::insert()}{insert()}, - \l{QString::replace()}{replace()}, and \l{QString::indexOf()}{indexOf()}. - These functions are usually optimized to avoid constructing a + \l{QString::append()}{append()}, and \l{QString::prepend()}{prepend()}. + Some of these functions are optimized to avoid constructing a QString object for the \c{const char *} data. For example, assuming \c str is a QString, @@ -9009,6 +9033,12 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size) because it doesn't construct four temporary QString objects and make a deep copy of the character data. + However, that is not true for all QString member functions that take + \c{const char *} and therefore applications should assume a temporary will + be created, such as in + + \snippet code/src_corelib_text_qstring.cpp 4bis + Applications that define \l QT_NO_CAST_FROM_ASCII (as explained in the QString documentation) don't have access to QString's \c{const char *} API. To provide an efficient way of specifying @@ -10247,10 +10277,10 @@ QDataStream &operator<<(QDataStream &out, const QString &str) if (!str.isNull() || out.version() < 3) { if ((out.byteOrder() == QDataStream::BigEndian) == (QSysInfo::ByteOrder == QSysInfo::BigEndian)) { out.writeBytes(reinterpret_cast<const char *>(str.unicode()), - static_cast<uint>(sizeof(QChar) * str.length())); + static_cast<uint>(sizeof(QChar) * str.size())); } else { - QVarLengthArray<char16_t> buffer(str.length()); - qbswap<sizeof(char16_t)>(str.constData(), str.length(), buffer.data()); + QVarLengthArray<char16_t> buffer(str.size()); + qbswap<sizeof(char16_t)>(str.constData(), str.size(), buffer.data()); out.writeBytes(reinterpret_cast<const char *>(buffer.data()), static_cast<uint>(sizeof(char16_t) * buffer.size())); } @@ -10873,13 +10903,19 @@ qsizetype QtPrivate::count(QStringView haystack, const QRegularExpression &re) } qsizetype count = 0; qsizetype index = -1; - qsizetype len = haystack.length(); + qsizetype len = haystack.size(); while (index <= len - 1) { QRegularExpressionMatch match = re.match(haystack, index + 1); if (!match.hasMatch()) break; - index = match.capturedStart(); count++; + + // Search again, from the next character after the beginning of this + // capture. If the capture starts with a surrogate pair, both together + // count as "one character". + index = match.capturedStart(); + if (index < len && haystack[index].isHighSurrogate()) + ++index; } return count; } @@ -10900,7 +10936,7 @@ qsizetype QtPrivate::count(QStringView haystack, const QRegularExpression &re) QString QString::toHtmlEscaped() const { QString rich; - const qsizetype len = length(); + const qsizetype len = size(); rich.reserve(qsizetype(len * 1.1)); for (QChar ch : *this) { if (ch == u'<') @@ -11040,16 +11076,6 @@ void QAbstractConcatenable::appendLatin1To(QLatin1StringView in, QChar *out) noe qt_from_latin1(reinterpret_cast<char16_t *>(out), in.data(), size_t(in.size())); } -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); -} - /*! \fn template <typename T> qsizetype erase(QString &s, const T &t) \relates QString |