diff options
Diffstat (limited to 'src/corelib/text')
-rw-r--r-- | src/corelib/text/qanystringview.h | 23 | ||||
-rw-r--r-- | src/corelib/text/qbytearray.cpp | 116 | ||||
-rw-r--r-- | src/corelib/text/qbytearray.h | 6 | ||||
-rw-r--r-- | src/corelib/text/qbytearrayalgorithms.h | 6 | ||||
-rw-r--r-- | src/corelib/text/qbytearraymatcher.cpp | 71 | ||||
-rw-r--r-- | src/corelib/text/qbytearrayview.h | 25 | ||||
-rw-r--r-- | src/corelib/text/qchar.cpp | 51 | ||||
-rw-r--r-- | src/corelib/text/qchar.h | 14 | ||||
-rw-r--r-- | src/corelib/text/qlocale.cpp | 5 | ||||
-rw-r--r-- | src/corelib/text/qlocale_tools.cpp | 87 | ||||
-rw-r--r-- | src/corelib/text/qlocale_tools_p.h | 21 | ||||
-rw-r--r-- | src/corelib/text/qstring.cpp | 105 | ||||
-rw-r--r-- | src/corelib/text/qstring.h | 6 | ||||
-rw-r--r-- | src/corelib/text/qstringalgorithms.h | 1 | ||||
-rw-r--r-- | src/corelib/text/qstringconverter.cpp | 64 | ||||
-rw-r--r-- | src/corelib/text/qstringconverter.h | 10 | ||||
-rw-r--r-- | src/corelib/text/qstringconverter_base.h | 7 | ||||
-rw-r--r-- | src/corelib/text/qstringconverter_p.h | 1 | ||||
-rw-r--r-- | src/corelib/text/qstringview.h | 2 | ||||
-rw-r--r-- | src/corelib/text/qutf8stringview.h | 12 |
20 files changed, 342 insertions, 291 deletions
diff --git a/src/corelib/text/qanystringview.h b/src/corelib/text/qanystringview.h index 01efd83743..075d64679c 100644 --- a/src/corelib/text/qanystringview.h +++ b/src/corelib/text/qanystringview.h @@ -62,10 +62,13 @@ private: }; template <typename Char> - using if_compatible_char = std::enable_if_t<std::disjunction_v< + using is_compatible_char = std::disjunction< QtPrivate::IsCompatibleCharType<Char>, QtPrivate::IsCompatibleChar8Type<Char> - >, bool>; + >; + + template <typename Char> + using if_compatible_char = std::enable_if_t<is_compatible_char<Char>::value, bool>; template <typename Pointer> using if_compatible_pointer = std::enable_if_t<std::disjunction_v< @@ -87,6 +90,7 @@ private: std::is_same<q20::remove_cvref_t<T>, QAnyStringView::Tag>, std::is_same<q20::remove_cvref_t<T>, QAnyStringView>, // don't make a copy/move ctor std::is_pointer<std::decay_t<T>>, // const char*, etc + is_compatible_char<T>, // don't create a QString/QByteArray, we have a ctor std::is_same<q20::remove_cvref_t<T>, QByteArray>, std::is_same<q20::remove_cvref_t<T>, QString> >>, @@ -133,7 +137,7 @@ private: static constexpr qsizetype lengthHelperPointer(const Char *str) noexcept { if (q20::is_constant_evaluated()) - return qsizetype(std::char_traits<Char>::length(str)); + return QtPrivate::lengthHelperPointer(str); if constexpr (sizeof(Char) == sizeof(char16_t)) return QtPrivate::qustrlen(reinterpret_cast<const char16_t*>(str)); else @@ -144,6 +148,11 @@ private: static QChar toQChar(QChar ch) noexcept { return ch; } static QChar toQChar(QLatin1Char ch) noexcept { return ch; } + struct QCharContainer { // private, so users can't pass their own + explicit QCharContainer() = default; + QChar ch; + }; + explicit constexpr QAnyStringView(const void *d, qsizetype n, std::size_t sizeAndType) noexcept : m_data{d}, m_size{std::size_t(n) | (sizeAndType & TypeMask)} {} public: @@ -193,16 +202,16 @@ public: constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t<Container, QByteArray> &&capacity = {}) //noexcept(std::is_nothrow_constructible_v<QByteArray, Container>) : QAnyStringView(capacity = std::forward<Container>(c)) {} - template <typename Char, if_compatible_char<Char> = true> constexpr QAnyStringView(const Char &c) noexcept : QAnyStringView{&c, 1} {} - constexpr QAnyStringView(const QChar &c) noexcept - : QAnyStringView{&c, 1} {} + template <typename Char, if_convertible_to<QChar, Char> = true> + constexpr QAnyStringView(Char ch, QCharContainer &&capacity = QCharContainer()) noexcept + : QAnyStringView{&(capacity.ch = ch), 1} {} template <typename Char, typename Container = decltype(QChar::fromUcs4(U'x')), std::enable_if_t<std::is_same_v<Char, char32_t>, bool> = true> - constexpr QAnyStringView(Char c, Container &&capacity = {}) + constexpr QAnyStringView(Char c, Container &&capacity = {}) noexcept : QAnyStringView(capacity = QChar::fromUcs4(c)) {} constexpr QAnyStringView(QStringView v) noexcept diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index e6387e4bed..d9f0ee405a 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -56,15 +56,35 @@ static constexpr inline uchar asciiLower(uchar c) return c >= 'A' && c <= 'Z' ? c | 0x20 : c; } -qsizetype qFindByteArray( - const char *haystack0, qsizetype haystackLen, qsizetype from, - const char *needle0, qsizetype needleLen); - /***************************************************************************** Safe and portable C string functions; extensions to standard string.h *****************************************************************************/ /*! \relates QByteArray + \internal + + Wrapper around memrchr() for systems that don't have it. It's provided in + every system because, as a GNU extension, memrchr() may not be declared in + string.h depending on how strict the compiler was asked to be. + + Used in QByteArrayView::lastIndexOf() overload for a single char. +*/ +const void *qmemrchr(const void *s, int needle, size_t size) noexcept +{ +#if QT_CONFIG(memrchr) + return memrchr(s, needle, size); +#endif + auto b = static_cast<const char *>(s); + const char *n = b + size; + while (n-- != b) { + if (*n == needle) + return n; + } + return nullptr; +} + + +/*! \relates QByteArray Returns a duplicate string. @@ -2680,31 +2700,6 @@ QByteArray QByteArray::repeated(qsizetype times) const return result; } -#define REHASH(a) \ - if (ol_minus_1 < sizeof(std::size_t) * CHAR_BIT) \ - hashHaystack -= std::size_t(a) << ol_minus_1; \ - hashHaystack <<= 1 - -qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept -{ - const auto ol = needle.size(); - const auto l = haystack.size(); - if (ol == 0) { - if (from < 0) - return qMax(from + l, 0); - else - return from > l ? -1 : from; - } - - if (ol == 1) - return findByteArray(haystack, from, needle.front()); - - if (from > l || ol + from > l) - return -1; - - return qFindByteArray(haystack.data(), haystack.size(), from, needle.data(), ol); -} - /*! \fn qsizetype QByteArray::indexOf(QByteArrayView bv, qsizetype from) const \since 6.0 @@ -2745,10 +2740,10 @@ static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char const char *end = haystack; haystack += from; - const auto ol_minus_1 = std::size_t(ol - 1); + const qregisteruint ol_minus_1 = ol - 1; const char *n = needle + ol_minus_1; const char *h = haystack + ol_minus_1; - std::size_t hashNeedle = 0, hashHaystack = 0; + qregisteruint hashNeedle = 0, hashHaystack = 0; qsizetype idx; for (idx = 0; idx < ol; ++idx) { hashNeedle = ((hashNeedle<<1) + *(n-idx)); @@ -2760,34 +2755,11 @@ static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char if (hashHaystack == hashNeedle && memcmp(needle, haystack, ol) == 0) return haystack - end; --haystack; - REHASH(*(haystack + ol)); + if (ol_minus_1 < sizeof(ol_minus_1) * CHAR_BIT) + hashHaystack -= qregisteruint(*(haystack + ol)) << ol_minus_1; + hashHaystack <<= 1; } return -1; - -} - -static inline qsizetype lastIndexOfCharHelper(QByteArrayView haystack, qsizetype from, char needle) noexcept -{ - if (haystack.size() == 0) - return -1; - if (from < 0) - from += haystack.size(); - else if (from > haystack.size()) - from = haystack.size() - 1; - if (from >= 0) { - const char *b = haystack.data(); - const char *n = b + from + 1; - while (n-- != b) { - if (*n == needle) - return n - b; - } - } - return -1; -} - -qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, char needle) noexcept -{ - return lastIndexOfCharHelper(haystack, from, needle); } qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept @@ -2799,7 +2771,7 @@ qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteA } const auto ol = needle.size(); if (ol == 1) - return lastIndexOfCharHelper(haystack, from, needle.front()); + return QtPrivate::lastIndexOf(haystack, from, needle.front()); return lastIndexOfHelper(haystack.data(), haystack.size(), needle.data(), ol, from); } @@ -4218,24 +4190,6 @@ QByteArray QByteArray::toBase64(Base64Options options) const \sa toUShort() */ -static char *qulltoa2(char *p, qulonglong n, int base) -{ -#if defined(QT_CHECK_RANGE) - if (base < 2 || base > 36) { - qWarning("QByteArray::setNum: Invalid base %d", base); - base = 10; - } -#endif - constexpr char b = 'a' - 10; - do { - const int c = n % base; - n /= base; - *--p = c + (c < 10 ? '0' : b); - } while (n); - - return p; -} - /*! \overload @@ -4255,9 +4209,7 @@ QByteArray &QByteArray::setNum(qlonglong n, int base) p = qulltoa2(buff + buffsize, qulonglong(n), base); } - clear(); - append(p, buffsize - (p - buff)); - return *this; + return assign(QByteArrayView{p, buff + buffsize}); } /*! @@ -4272,9 +4224,7 @@ QByteArray &QByteArray::setNum(qulonglong n, int base) char buff[buffsize]; char *p = qulltoa2(buff + buffsize, n, base); - clear(); - append(p, buffsize - (p - buff)); - return *this; + return assign(QByteArrayView{p, buff + buffsize}); } /*! @@ -5206,5 +5156,3 @@ size_t qHash(const QByteArray::FromBase64Result &key, size_t seed) noexcept */ QT_END_NAMESPACE - -#undef REHASH diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index 3c8a3bba45..5902b01516 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -136,12 +136,12 @@ public: [[nodiscard]] char back() const { return at(size() - 1); } [[nodiscard]] inline char &back(); - QT_CORE_INLINE_SINCE(6, 7) + QT_CORE_INLINE_SINCE(6, 8) qsizetype indexOf(char c, qsizetype from = 0) const; qsizetype indexOf(QByteArrayView bv, qsizetype from = 0) const { return QtPrivate::findByteArray(qToByteArrayViewIgnoringNull(*this), from, bv); } - QT_CORE_INLINE_SINCE(6, 7) + QT_CORE_INLINE_SINCE(6, 8) qsizetype lastIndexOf(char c, qsizetype from = -1) const; qsizetype lastIndexOf(QByteArrayView bv) const { return lastIndexOf(bv, size()); } @@ -706,7 +706,7 @@ bool QByteArray::isNull() const noexcept return d->isNull(); } #endif -#if QT_CORE_INLINE_IMPL_SINCE(6, 7) +#if QT_CORE_INLINE_IMPL_SINCE(6, 8) qsizetype QByteArray::indexOf(char ch, qsizetype from) const { return qToByteArrayViewIgnoringNull(*this).indexOf(ch, from); diff --git a/src/corelib/text/qbytearrayalgorithms.h b/src/corelib/text/qbytearrayalgorithms.h index 7060161bb4..649ec2e39b 100644 --- a/src/corelib/text/qbytearrayalgorithms.h +++ b/src/corelib/text/qbytearrayalgorithms.h @@ -31,8 +31,8 @@ qsizetype findByteArray(QByteArrayView haystack, qsizetype from, char needle) no [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findByteArray(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept; -[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION -qsizetype lastIndexOf(QByteArrayView haystack, qsizetype from, char needle) noexcept; +[[nodiscard]] inline Q_DECL_PURE_FUNCTION +qsizetype lastIndexOf(QByteArrayView haystack, qsizetype from, uchar needle) noexcept; [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept; @@ -99,6 +99,8 @@ static inline T toIntegral(ByteArrayView data, bool *ok, int base) Safe and portable C string functions; extensions to standard string.h *****************************************************************************/ +[[nodiscard]] Q_DECL_PURE_FUNCTION Q_CORE_EXPORT +const void *qmemrchr(const void *s, int needle, size_t n) noexcept; Q_CORE_EXPORT char *qstrdup(const char *); inline size_t qstrlen(const char *str) diff --git a/src/corelib/text/qbytearraymatcher.cpp b/src/corelib/text/qbytearraymatcher.cpp index ae38fb584b..9f27e10f3d 100644 --- a/src/corelib/text/qbytearraymatcher.cpp +++ b/src/corelib/text/qbytearraymatcher.cpp @@ -3,6 +3,11 @@ #include "qbytearraymatcher.h" +#include <qtconfiginclude.h> +#ifndef QT_BOOTSTRAPPED +# include <private/qtcore-config_p.h> +#endif + #include <limits.h> QT_BEGIN_NAMESPACE @@ -212,26 +217,10 @@ qsizetype QByteArrayMatcher::indexIn(QByteArrayView data, qsizetype from) const \sa setPattern() */ - -static qsizetype findChar(const char *str, qsizetype len, char ch, qsizetype from) -{ - const uchar *s = (const uchar *)str; - uchar c = (uchar)ch; - if (from < 0) - from = qMax(from + len, qsizetype(0)); - if (from < len) { - const uchar *n = s + from - 1; - const uchar *e = s + len; - while (++n != e) - if (*n == c) - return n - s; - } - return -1; -} - /*! \internal */ +Q_NEVER_INLINE static qsizetype qFindByteArrayBoyerMoore( const char *haystack, qsizetype haystackLen, qsizetype haystackOffset, const char *needle, qsizetype needleLen) @@ -244,20 +233,21 @@ static qsizetype qFindByteArrayBoyerMoore( (const uchar *)needle, needleLen, skiptable); } -#define REHASH(a) \ - if (sl_minus_1 < sizeof(std::size_t) * CHAR_BIT) \ - hashHaystack -= std::size_t(a) << sl_minus_1; \ - hashHaystack <<= 1 - /*! \internal */ -qsizetype qFindByteArray( - const char *haystack0, qsizetype haystackLen, qsizetype from, - const char *needle, qsizetype needleLen) +static qsizetype qFindByteArray(const char *haystack0, qsizetype l, qsizetype from, + const char *needle, qsizetype sl); +qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept { - const auto l = haystackLen; - const auto sl = needleLen; + const auto haystack0 = haystack.data(); + const auto l = haystack.size(); + const auto sl = needle.size(); +#if !QT_CONFIG(memmem) + if (sl == 1) + return findByteArray(haystack, from, needle.front()); +#endif + if (from < 0) from += l; if (std::size_t(sl + from) > std::size_t(l)) @@ -267,8 +257,10 @@ qsizetype qFindByteArray( if (!l) return -1; - if (sl == 1) - return findChar(haystack0, haystackLen, needle[0], from); +#if QT_CONFIG(memmem) + auto where = memmem(haystack0 + from, l - from, needle.data(), sl); + return where ? static_cast<const char *>(where) - haystack0 : -1; +#endif /* We use the Boyer-Moore algorithm in cases where the overhead @@ -276,18 +268,22 @@ qsizetype qFindByteArray( hash function. */ if (l > 500 && sl > 5) - return qFindByteArrayBoyerMoore(haystack0, haystackLen, from, - needle, needleLen); + return qFindByteArrayBoyerMoore(haystack0, l, from, needle.data(), sl); + return qFindByteArray(haystack0, l, from, needle.data(), sl); +} +qsizetype qFindByteArray(const char *haystack0, qsizetype l, qsizetype from, + const char *needle, qsizetype sl) +{ /* We use some hashing for efficiency's sake. Instead of comparing strings, we compare the hash value of str with that - of a part of this QString. Only if that matches, we call memcmp(). + of a part of this QByteArray. Only if that matches, we call memcmp(). */ const char *haystack = haystack0 + from; const char *end = haystack0 + (l - sl); - const auto sl_minus_1 = std::size_t(sl - 1); - std::size_t hashNeedle = 0, hashHaystack = 0; + const qregisteruint sl_minus_1 = sl - 1; + qregisteruint hashNeedle = 0, hashHaystack = 0; qsizetype idx; for (idx = 0; idx < sl; ++idx) { hashNeedle = ((hashNeedle<<1) + needle[idx]); @@ -301,7 +297,9 @@ qsizetype qFindByteArray( && memcmp(needle, haystack, sl) == 0) return haystack - haystack0; - REHASH(*haystack); + if (sl_minus_1 < sizeof(sl_minus_1) * CHAR_BIT) + hashHaystack -= qregisteruint(*haystack) << sl_minus_1; + hashHaystack <<= 1; ++haystack; } return -1; @@ -409,7 +407,4 @@ qsizetype QStaticByteArrayMatcherBase::indexOfIn(const char *needle, size_t nlen \snippet code/src_corelib_text_qbytearraymatcher.cpp 1 */ - QT_END_NAMESPACE - -#undef REHASH diff --git a/src/corelib/text/qbytearrayview.h b/src/corelib/text/qbytearrayview.h index 45ebc812cd..dea0e6cbe8 100644 --- a/src/corelib/text/qbytearrayview.h +++ b/src/corelib/text/qbytearrayview.h @@ -68,7 +68,15 @@ struct IsContainerCompatibleWithQByteArrayView<T, std::enable_if_t< template <typename Char> static constexpr qsizetype lengthHelperPointer(const Char *data) noexcept { - return qsizetype(std::char_traits<Char>::length(data)); + // std::char_traits can only be used with one of the regular char types + // (char, char16_t, wchar_t, but not uchar or QChar), so we roll the loop + // out by ourselves. + qsizetype i = 0; + if (!data) + return i; + while (data[i] != Char(0)) + ++i; + return i; } } // namespace QtPrivate @@ -169,7 +177,8 @@ public: : QByteArrayView(data, lengthHelperCharArray(data, Size)) {} constexpr QByteArrayView(QLatin1StringView v) noexcept; // defined in qlatin1stringview.h - constexpr QByteArrayView(QUtf8StringView v) noexcept; // defined in qutf8stringview.h + template <bool UseChar8T> + constexpr QByteArrayView(QBasicUtf8StringView<UseChar8T> v) noexcept; // defined in qutf8stringview.h #ifdef Q_QDOC template <typename Byte, size_t Size> @@ -401,6 +410,18 @@ qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, char return -1; } +qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, uchar needle) noexcept +{ + if (from < 0) + from = qMax(from + haystack.size(), qsizetype(0)); + else + from = qMin(from, haystack.size() - 1); + + const char *const b = haystack.data(); + const void *n = b ? qmemrchr(b, needle, from + 1) : nullptr; + return n ? static_cast<const char *>(n) - b : -1; +} + QT_END_NAMESPACE #endif // QBYTEARRAYVIEW_H diff --git a/src/corelib/text/qchar.cpp b/src/corelib/text/qchar.cpp index 63296a92de..7b114e9723 100644 --- a/src/corelib/text/qchar.cpp +++ b/src/corelib/text/qchar.cpp @@ -123,9 +123,7 @@ QT_BEGIN_NAMESPACE Starting with Qt 6.0, most QChar constructors are \c explicit. This is done to avoid dangerous mistakes when accidentally mixing - integral types and strings. You can opt-out (and make these - constructors implicit) by defining the macro \c - QT_IMPLICIT_QCHAR_CONSTRUCTION. + integral types and strings. For more information see \l{https://www.unicode.org/ucd/}{"About the Unicode Character Database"}. @@ -2110,51 +2108,4 @@ static bool normalizationQuickCheckHelper(QString *str, QString::NormalizationFo return true; } -/*! - \macro QT_IMPLICIT_QCHAR_CONSTRUCTION - \since 6.0 - \relates QChar - - Defining this macro makes certain QChar constructors implicit - rather than explicit. This is done to enforce safe conversions: - - \badcode - - QString str = getString(); - if (str == 123) { - // Oops, meant str == "123". By default does not compile, - // *unless* this macro is defined, in which case, it's interpreted - // as `if (str == QChar(123))`, that is, `if (str == '{')`. - // Likely, not what we meant. - } - - \endcode - - This macro is provided to keep existing code working; it is - recommended to instead use explicit conversions and/or QLatin1Char. - For instance: - - \code - - QChar c1 = 'x'; // OK, unless QT_NO_CAST_FROM_ASCII is defined - QChar c2 = u'x'; // always OK, recommended - QChar c3 = QLatin1Char('x'); // always OK, recommended - - // from int to 1 UTF-16 code unit: must guarantee that the input is <= 0xFFFF - QChar c4 = 120; // compile error, unless QT_IMPLICIT_QCHAR_CONSTRUCTION is defined - QChar c5(120); // OK (direct initialization) - auto c6 = QChar(120); // ditto - - // from int/char32_t to 1/2 UTF-16 code units: - // 𝄞 'MUSICAL SYMBOL G CLEF' (U+1D11E) - auto c7 = QChar(0x1D11E); // compiles, but undefined behavior at runtime - auto c8 = QChar::fromUcs4(0x1D11E); // always OK - auto c9 = QChar::fromUcs4(U'\U0001D11E'); // always OK - // => use c8/c9 as QStringView objects - - \endcode - - \sa QLatin1Char, QChar::fromUcs4, QT_NO_CAST_FROM_ASCII -*/ - QT_END_NAMESPACE diff --git a/src/corelib/text/qchar.h b/src/corelib/text/qchar.h index c0c53664c2..b3fd794726 100644 --- a/src/corelib/text/qchar.h +++ b/src/corelib/text/qchar.h @@ -63,17 +63,15 @@ public: }; #ifdef QT_IMPLICIT_QCHAR_CONSTRUCTION -#define QCHAR_MAYBE_IMPLICIT Q_IMPLICIT -#else -#define QCHAR_MAYBE_IMPLICIT explicit +#error This macro has been removed in Qt 6.8. #endif constexpr Q_IMPLICIT QChar() noexcept : ucs(0) {} constexpr Q_IMPLICIT QChar(ushort rc) noexcept : ucs(rc) {} - constexpr QCHAR_MAYBE_IMPLICIT QChar(uchar c, uchar r) noexcept : ucs(char16_t((r << 8) | c)) {} + constexpr explicit QChar(uchar c, uchar r) noexcept : ucs(char16_t((r << 8) | c)) {} constexpr Q_IMPLICIT QChar(short rc) noexcept : ucs(char16_t(rc)) {} - constexpr QCHAR_MAYBE_IMPLICIT QChar(uint rc) noexcept : ucs((Q_ASSERT(rc <= 0xffff), char16_t(rc))) {} - constexpr QCHAR_MAYBE_IMPLICIT QChar(int rc) noexcept : QChar(uint(rc)) {} + constexpr explicit QChar(uint rc) noexcept : ucs((Q_ASSERT(rc <= 0xffff), char16_t(rc))) {} + constexpr explicit QChar(int rc) noexcept : QChar(uint(rc)) {} constexpr Q_IMPLICIT QChar(SpecialCharacter s) noexcept : ucs(char16_t(s)) {} constexpr Q_IMPLICIT QChar(QLatin1Char ch) noexcept : ucs(ch.unicode()) {} constexpr Q_IMPLICIT QChar(char16_t ch) noexcept : ucs(ch) {} @@ -85,12 +83,10 @@ public: // Always implicit -- allow for 'x' => QChar conversions QT_ASCII_CAST_WARN constexpr Q_IMPLICIT QChar(char c) noexcept : ucs(uchar(c)) { } #ifndef QT_RESTRICTED_CAST_FROM_ASCII - QT_ASCII_CAST_WARN constexpr QCHAR_MAYBE_IMPLICIT QChar(uchar c) noexcept : ucs(c) { } + QT_ASCII_CAST_WARN constexpr explicit QChar(uchar c) noexcept : ucs(c) { } #endif #endif -#undef QCHAR_MAYBE_IMPLICIT - static constexpr QChar fromUcs2(char16_t c) noexcept { return QChar{c}; } static constexpr inline auto fromUcs4(char32_t c) noexcept; diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index ab95b300eb..86ab072b73 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -4760,6 +4760,11 @@ QStringList QLocale::uiLanguages(TagSeparator separator) const const bool isSystem = d->m_data == &systemLocaleData; if (isSystem) { uiLanguages = systemLocale()->query(QSystemLocale::UILanguages).toStringList(); + if (separator != TagSeparator::Dash) { + // Map from default separator, Dash, used by backends: + const QChar join = QLatin1Char(sep); + uiLanguages = uiLanguages.replaceInStrings(u"-", QStringView(&join, 1)); + } // ... but we need to include likely-adjusted forms of each of those, too. // For now, collect up locale Ids representing the entries, for later processing: for (const auto &entry : std::as_const(uiLanguages)) diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp index b6639bcb71..6b04bc92cd 100644 --- a/src/corelib/text/qlocale_tools.cpp +++ b/src/corelib/text/qlocale_tools.cpp @@ -552,6 +552,18 @@ QString qulltoa(qulonglong number, int base, const QStringView zero) return QString(reinterpret_cast<QChar *>(p), end - p); } +char *qulltoa2(char *p, qulonglong n, int base) +{ +#if defined(QT_CHECK_RANGE) + if (base < 2 || base > 36) { + qWarning("QByteArray::setNum: Invalid base %d", base); + base = 10; + } +#endif + qulltoString_helper(n, base, p); + return p; +} + /*! \internal @@ -795,4 +807,79 @@ QByteArray qdtoAscii(double d, QLocaleData::DoubleForm form, int precision, bool return dtoString<QByteArray>(d, form, precision, uppercase); } +#if defined(QT_SUPPORTS_INT128) || defined(QT_USE_MSVC_INT128) +static inline quint64 toUInt64(qinternaluint128 v) +{ +#if defined(QT_USE_MSVC_INT128) + return quint64(v._Word[0]); +#else + return quint64(v); +#endif +} + +QString quint128toBasicLatin(qinternaluint128 number, int base) +{ + // We divide our 128-bit number into parts that we can do text + // concatenation with. This list is the maximum power of the + // base that is less than 2^64. + static constexpr auto dividers = []() constexpr { + std::array<quint64, 35> bases {}; + for (int base = 2; base <= 36; ++base) { + quint64 v = base; + while (v * base > v) + v *= base; + bases[base - 2] = v; + } + return bases; + }(); + static constexpr auto digitCounts = []() constexpr { + std::array<quint8, 35> digits{}; + for (int base = 2; base <= 36; ++base) { + quint64 v = base; + int i = 0; + for (i = 0; v * base > v; ++i) + v *= base; + digits[base - 2] = i; + } + return digits; + }(); + + QString result; + + constexpr unsigned flags = QLocaleData::NoFlags; + const QLocaleData *dd = QLocaleData::c(); + + // special base cases: + constexpr int Width = -1; + if (base == 2 || base == 4 || base == 16) { + // 2^64 is a power of 2, 4 and 16 + result = dd->unsLongLongToString(quint64(number), 64, base, Width, flags); + result.prepend(dd->unsLongLongToString(quint64(number >> 64), -1, base, Width, flags)); + } else { + int digitCount = digitCounts[base - 2]; + quint64 divider = dividers[base - 2]; + quint64 lower = toUInt64(number % divider); + number /= divider; + while (number) { + result.prepend(dd->unsLongLongToString(lower, digitCount, base, Width, flags)); + lower = toUInt64(number % divider); + number /= divider; + } + result.prepend(dd->unsLongLongToString(lower, -1, base, Width, flags)); + } + return result; +} + +QString qint128toBasicLatin(qinternalint128 number, int base) +{ + const bool negative = number < 0; + if (negative) + number *= -1; + QString result = quint128toBasicLatin(qinternaluint128(number), base); + if (negative) + result.prepend(u'-'); + return result; +} +#endif // defined(QT_SUPPORTS_INT128) || defined(QT_USE_MSVC_INT128) + QT_END_NAMESPACE diff --git a/src/corelib/text/qlocale_tools_p.h b/src/corelib/text/qlocale_tools_p.h index 9b02403ea4..2cfe25d299 100644 --- a/src/corelib/text/qlocale_tools_p.h +++ b/src/corelib/text/qlocale_tools_p.h @@ -18,8 +18,21 @@ #include "qlocale_p.h" #include "qstring.h" +#if !defined(QT_SUPPORTS_INT128) && (defined(Q_CC_MSVC) && (_MSC_VER >= 1930) && __has_include(<__msvc_int128.hpp>)) +#include <__msvc_int128.hpp> +#define QT_USE_MSVC_INT128 +#endif + QT_BEGIN_NAMESPACE +#if defined(QT_SUPPORTS_INT128) +using qinternalint128 = qint128; +using qinternaluint128 = quint128; +#elif defined(QT_USE_MSVC_INT128) +using qinternalint128 = std::_Signed128; +using qinternaluint128 = std::_Unsigned128; +#endif + enum StrayCharacterMode { TrailingJunkProhibited, TrailingJunkAllowed, @@ -36,12 +49,20 @@ void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, [[nodiscard]] QString qulltoBasicLatin(qulonglong l, int base, bool negative); [[nodiscard]] QString qulltoa(qulonglong l, int base, const QStringView zero); +[[nodiscard]] char *qulltoa2(char *p, qulonglong n, int base); [[nodiscard]] Q_CORE_EXPORT QString qdtoa(qreal d, int *decpt, int *sign); [[nodiscard]] QString qdtoBasicLatin(double d, QLocaleData::DoubleForm form, int precision, bool uppercase); [[nodiscard]] QByteArray qdtoAscii(double d, QLocaleData::DoubleForm form, int precision, bool uppercase); +#if defined(QT_SUPPORTS_INT128) || defined(QT_USE_MSVC_INT128) +[[nodiscard]] Q_CORE_EXPORT QString quint128toBasicLatin(qinternaluint128 number, + int base = 10); +[[nodiscard]] Q_CORE_EXPORT QString qint128toBasicLatin(qinternalint128 number, + int base = 10); +#endif + [[nodiscard]] constexpr inline bool isZero(double d) { return d == 0; // Amusingly, compilers do not grumble. diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index f0bf0c50a3..2d0e4531d1 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -63,8 +63,8 @@ #endif #define REHASH(a) \ - if (sl_minus_1 < sizeof(std::size_t) * CHAR_BIT) \ - hashHaystack -= std::size_t(a) << sl_minus_1; \ + if (sl_minus_1 < sizeof(sl_minus_1) * CHAR_BIT) \ + hashHaystack -= decltype(hashHaystack)(a) << sl_minus_1; \ hashHaystack <<= 1 QT_BEGIN_NAMESPACE @@ -183,10 +183,10 @@ static qsizetype qLastIndexOf(Haystack haystack0, qsizetype from, const auto needle = needle0.data(); const auto *end = haystack; haystack += from; - const std::size_t sl_minus_1 = sl ? sl - 1 : 0; + const qregisteruint sl_minus_1 = sl ? sl - 1 : 0; const auto *n = needle + sl_minus_1; const auto *h = haystack + sl_minus_1; - std::size_t hashNeedle = 0, hashHaystack = 0; + qregisteruint hashNeedle = 0, hashHaystack = 0; if (cs == Qt::CaseSensitive) { for (qsizetype idx = 0; idx < sl; ++idx) { @@ -361,7 +361,7 @@ extern "C" void qt_toLatin1_mips_dsp_asm(uchar *dst, const char16_t *src, int le #if defined(__SSE2__) && defined(Q_CC_GNU) // We may overrun the buffer, but that's a false positive: // this won't crash nor produce incorrect results -# define ATTRIBUTE_NO_SANITIZE __attribute__((__no_sanitize_address__)) +# define ATTRIBUTE_NO_SANITIZE __attribute__((__no_sanitize_address__, __no_sanitize_thread__)) #else # define ATTRIBUTE_NO_SANITIZE #endif @@ -657,7 +657,7 @@ static int ucstrncmp_sse2(const char16_t *a, const Char *b, size_t l) Q_NEVER_INLINE qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept { -#if defined(__SSE2__) && !(defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)) +#if defined(__SSE2__) && !(defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)) && !(defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)) return qustrlen_sse2(str); #endif @@ -1543,6 +1543,8 @@ int QtPrivate::compareStrings(QLatin1StringView lhs, QLatin1StringView rhs, Qt:: { if (lhs.isEmpty()) return qt_lencmp(qsizetype(0), rhs.size()); + if (rhs.isEmpty()) + return qt_lencmp(lhs.size(), qsizetype(0)); if (cs == Qt::CaseInsensitive) return latin1nicmp(lhs.data(), lhs.size(), rhs.data(), rhs.size()); const auto l = std::min(lhs.size(), rhs.size()); @@ -5251,8 +5253,9 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp \fn QString QString::left(qsizetype n) const & \fn QString QString::left(qsizetype n) && - Returns a substring that contains the \a n leftmost characters - of the string. + Returns a substring that contains the \a n leftmost characters of + this string (that is, from the beginning of this string up to, but not + including, the element at index position \a n). If you know that \a n cannot be out of bounds, use first() instead in new code, because it is faster. @@ -5283,8 +5286,9 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp \fn QString QString::mid(qsizetype position, qsizetype n) const & \fn QString QString::mid(qsizetype position, qsizetype n) && - Returns a string that contains \a n characters of this string, - starting at the specified \a position index. + Returns a string that contains \a n characters of this string, starting + at the specified \a position index up to, but not including, the element + at index position \c {\a position + n}. If you know that \a position and \a n cannot be out of bounds, use sliced() instead in new code, because it is faster. @@ -5339,8 +5343,9 @@ QString QString::mid(qsizetype position, qsizetype n) && \fn QString QString::first(qsizetype n) && \since 6.0 - Returns a string that contains the first \a n characters - of this string. + Returns a string that contains the first \a n characters of this string, + (that is, from the beginning of this string up to, but not including, + the element at index position \a n). \note The behavior is undefined when \a n < 0 or \a n > size(). @@ -5368,8 +5373,9 @@ QString QString::mid(qsizetype position, qsizetype n) && \fn QString QString::sliced(qsizetype pos, qsizetype n) && \since 6.0 - Returns a string that contains \a n characters of this string, - starting at position \a pos. + Returns a string that contains \a n characters of this string, starting + at position \a pos up to, but not including, the element at index position + \c {\a pos + n}. \note The behavior is undefined when \a pos < 0, \a n < 0, or \a pos + \a n > size(). @@ -5405,8 +5411,9 @@ QString QString::sliced_helper(QString &str, qsizetype pos, qsizetype n) \fn QString &QString::slice(qsizetype pos, qsizetype n) \since 6.8 - Modifies this string to start at position \a pos, extending for \a n - characters (code points), and returns a reference to this string. + Modifies this string to start at position \a pos, up to, but not including, + the character (code point) at index position \c {\a pos + n}; and returns + a reference to this string. \note The behavior is undefined if \a pos < 0, \a n < 0, or \a pos + \a n > size(). @@ -6302,7 +6309,8 @@ QString QString::trimmed_helper(QString &str) /*! \fn void QString::truncate(qsizetype position) - Truncates the string at the given \a position index. + Truncates the string starting from, and including, the element at index + \a position. If the specified \a position index is beyond the end of the string, nothing happens. @@ -9140,18 +9148,13 @@ namespace { struct Part { Part() = default; // for QVarLengthArray; do not use - constexpr Part(QStringView s, int num = -1) - : tag{QtPrivate::ArgBase::U16}, number{num}, data{s.utf16()}, size{s.size()} {} - constexpr Part(QLatin1StringView s, int num = -1) - : tag{QtPrivate::ArgBase::L1}, number{num}, data{s.data()}, size{s.size()} {} + constexpr Part(QAnyStringView s, int num = -1) + : string{s}, number{num} {} - void reset(QStringView s) noexcept { *this = {s, number}; } - void reset(QLatin1StringView s) noexcept { *this = {s, number}; } + void reset(QAnyStringView s) noexcept { *this = {s, number}; } - QtPrivate::ArgBase::Tag tag; + QAnyStringView string; int number; - const void *data; - qsizetype size; }; } // unnamed namespace @@ -9234,16 +9237,13 @@ static qsizetype resolveStringRefsAndReturnTotalSize(ParseResult &parts, const A } } } - totalSize += part.size; + totalSize += part.string.size(); } return totalSize; } } // unnamed namespace -Q_ALWAYS_INLINE QString to_string(QLatin1StringView s) noexcept { return s; } -Q_ALWAYS_INLINE QString to_string(QStringView s) noexcept { return s.toString(); } - template <typename StringView> static QString argToQStringImpl(StringView pattern, size_t numArgs, const QtPrivate::ArgBase **args) { @@ -9257,7 +9257,7 @@ static QString argToQStringImpl(StringView pattern, size_t numArgs, const QtPriv argIndexToPlaceholderMap.resize(qsizetype(numArgs)); else if (Q_UNLIKELY(static_cast<size_t>(argIndexToPlaceholderMap.size()) < numArgs)) // 3b qWarning("QString::arg: %d argument(s) missing in %ls", - int(numArgs - argIndexToPlaceholderMap.size()), qUtf16Printable(to_string(pattern))); + int(numArgs - argIndexToPlaceholderMap.size()), qUtf16Printable(pattern.toString())); // 5 const qsizetype totalSize = resolveStringRefsAndReturnTotalSize(parts, argIndexToPlaceholderMap, args); @@ -9266,24 +9266,33 @@ static QString argToQStringImpl(StringView pattern, size_t numArgs, const QtPriv QString result(totalSize, Qt::Uninitialized); auto out = const_cast<QChar*>(result.constData()); - for (const Part &part : parts) { - switch (part.tag) { - case QtPrivate::ArgBase::L1: - if (part.size) { + struct Concatenate { + QChar *out; + QChar *operator()(QLatin1String part) noexcept + { + if (part.size()) { qt_from_latin1(reinterpret_cast<char16_t*>(out), - reinterpret_cast<const char*>(part.data), part.size); + part.data(), part.size()); } - break; - case QtPrivate::ArgBase::U8: - Q_UNREACHABLE(); // waiting for QUtf8String - break; - case QtPrivate::ArgBase::U16: - if (part.size) - memcpy(out, part.data, part.size * sizeof(QChar)); - break; + return out + part.size(); } - out += part.size; - } + QChar *operator()(QUtf8StringView part) noexcept + { + return QUtf8::convertToUnicode(out, part); + } + QChar *operator()(QStringView part) noexcept + { + if (part.size()) + memcpy(out, part.data(), part.size() * sizeof(QChar)); + return out + part.size(); + } + }; + + for (const Part &part : parts) + out = part.string.visit(Concatenate{out}); + + // UTF-8 decoding may have caused an overestimate of totalSize - correct it: + result.truncate(out - result.cbegin()); return result; } @@ -9905,8 +9914,8 @@ qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringVi const char16_t *needle = needle0.utf16(); const char16_t *haystack = haystack0.utf16() + from; const char16_t *end = haystack0.utf16() + (l - sl); - const std::size_t sl_minus_1 = sl - 1; - std::size_t hashNeedle = 0, hashHaystack = 0; + const qregisteruint sl_minus_1 = sl - 1; + qregisteruint hashNeedle = 0, hashHaystack = 0; qsizetype idx; if (cs == Qt::CaseSensitive) { diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 895ec4b5c0..98c2f3cdb0 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -287,7 +287,7 @@ public: static QString vasprintf(const char *format, va_list ap) Q_ATTRIBUTE_FORMAT_PRINTF(1, 0); static QString asprintf(const char *format, ...) Q_ATTRIBUTE_FORMAT_PRINTF(1, 2); - [[nodiscard]] QT_CORE_INLINE_SINCE(6, 7) + [[nodiscard]] QT_CORE_INLINE_SINCE(6, 8) qsizetype indexOf(QChar c, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; [[nodiscard]] qsizetype indexOf(QLatin1StringView s, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; [[nodiscard]] qsizetype indexOf(const QString &s, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; @@ -295,7 +295,7 @@ public: { return QtPrivate::findString(*this, from, s, cs); } [[nodiscard]] qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return lastIndexOf(c, -1, cs); } - [[nodiscard]] QT_CORE_INLINE_SINCE(6, 7) + [[nodiscard]] QT_CORE_INLINE_SINCE(6, 8) qsizetype lastIndexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; [[nodiscard]] qsizetype lastIndexOf(QLatin1StringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return lastIndexOf(s, size(), cs); } @@ -1510,7 +1510,7 @@ quint64 QString::toULongLong(bool *ok, int base) const return toIntegral_helper<qulonglong>(*this, ok, base); } #endif -#if QT_CORE_INLINE_IMPL_SINCE(6, 7) +#if QT_CORE_INLINE_IMPL_SINCE(6, 8) qsizetype QString::indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const { return qToStringViewIgnoringNull(*this).indexOf(ch, from, cs); diff --git a/src/corelib/text/qstringalgorithms.h b/src/corelib/text/qstringalgorithms.h index 71a1dbd526..755e3f82bd 100644 --- a/src/corelib/text/qstringalgorithms.h +++ b/src/corelib/text/qstringalgorithms.h @@ -56,7 +56,6 @@ namespace QtPrivate { [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool endsWith(QLatin1StringView haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool endsWith(QLatin1StringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; -[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findStringInsensitive(QStringView haystack, qsizetype from, char16_t needle) noexcept; [[nodiscard]] inline qsizetype findString(QStringView str, qsizetype from, QChar needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QStringView haystack, qsizetype from, QLatin1StringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp index 67c75d708e..9fc3318d71 100644 --- a/src/corelib/text/qstringconverter.cpp +++ b/src/corelib/text/qstringconverter.cpp @@ -1910,20 +1910,37 @@ const QStringConverter::Interface QStringConverter::encodingInterfaces[QStringCo }; // match names case insensitive and skipping '-' and '_' -static bool nameMatch(const char *a, const char *b) +static bool nameMatch_impl(const char *a, QLatin1StringView rhs) { + const char *b = rhs.data(); + const char *b_end = rhs.end(); do { while (*a == '-' || *a == '_') ++a; - while (*b == '-' || *b == '_') + while (b != b_end && (*b == '-' || *b == '_')) ++b; - if (!*a && !*b) // end of both strings + if (!*a && b == b_end) // end of both strings return true; } while (QtMiscUtils::toAsciiLower(*a++) == QtMiscUtils::toAsciiLower(*b++)); return false; } +static bool nameMatch_impl(const char *a, QUtf8StringView b) +{ + return nameMatch_impl(a, QLatin1StringView{QByteArrayView{b}}); +} + +static bool nameMatch_impl(const char *a, QStringView b) +{ + return nameMatch_impl(a, QLatin1StringView{b.toString().toLatin1()}); // ### optimize +} + +static bool nameMatch(const char *a, QAnyStringView b) +{ + return b.visit([a](auto b) { return nameMatch_impl(a, b); }); +} + /*! \fn constexpr QStringConverter::QStringConverter() @@ -2129,6 +2146,10 @@ struct QStringConverterICU : QStringConverter return conv; } + static const QStringConverter::Interface * + make_icu_converter(QStringConverterBase::State *state, QAnyStringView name) + { return make_icu_converter(state, name.toString().toLatin1().constData()); } // ### optimize + static const QStringConverter::Interface *make_icu_converter( QStringConverterBase::State *state, const char *name) @@ -2166,7 +2187,7 @@ struct QStringConverterICU : QStringConverter /*! \internal */ -QStringConverter::QStringConverter(const char *name, Flags f) +QStringConverter::QStringConverter(QAnyStringView name, Flags f) : iface(nullptr), state(f) { auto e = encodingForName(name); @@ -2237,17 +2258,18 @@ const char *QStringConverter::name() const noexcept the QStringConverter constructor when Qt is built with ICU, if ICU provides a converter with the given name. - \a name is expected to be UTF-8 encoded. + \note In Qt versions prior to 6.8, this function took only a \c{const char *}, + which was expected to be UTF-8-encoded. */ -std::optional<QStringConverter::Encoding> QStringConverter::encodingForName(const char *name) noexcept +std::optional<QStringConverter::Encoding> QStringConverter::encodingForName(QAnyStringView name) noexcept { - if (!name) + if (name.isEmpty()) return std::nullopt; for (qsizetype i = 0; i < LastEncoding + 1; ++i) { if (nameMatch(encodingInterfaces[i].name, name)) return QStringConverter::Encoding(i); } - if (nameMatch(name, "latin1")) + if (nameMatch("latin1", name)) return QStringConverter::Latin1; return std::nullopt; } @@ -2501,20 +2523,13 @@ const char *QStringConverter::nameForEncoding(QStringConverter::Encoding e) */ /*! - \fn constexpr QStringEncoder::QStringEncoder(const char *name, Flags flags = Flag::Default) + \fn QStringEncoder::QStringEncoder(QAnyStringView name, Flags flags = Flag::Default) Creates an encoder object using \a name and \a flags. If \a name is not the name of a known encoding an invalid converter will get created. - \sa isValid() -*/ - -/*! - \fn constexpr QStringEncoder::QStringEncoder(const QString &name, Flags flags = Flag::Default) - \since 6.8 - - Creates an encoder object using \a name and \a flags. - If \a name is not the name of a known encoding an invalid converter will get created. + \note In Qt versions prior to 6.8, this function took only a \c{const char *}, + which was expected to be UTF-8-encoded. \sa isValid() */ @@ -2602,20 +2617,13 @@ const char *QStringConverter::nameForEncoding(QStringConverter::Encoding e) */ /*! - \fn constexpr QStringDecoder::QStringDecoder(const char *name, Flags flags = Flag::Default) + \fn QStringDecoder::QStringDecoder(QAnyStringView name, Flags flags = Flag::Default) Creates an decoder object using \a name and \a flags. If \a name is not the name of a known encoding an invalid converter will get created. - \sa isValid() -*/ - -/*! - \fn constexpr QStringDecoder::QStringDecoder(const QString &name, Flags flags = Flag::Default) - \since 6.8 - - Creates an decoder object using \a name and \a flags. - If \a name is not the name of a known encoding an invalid converter will get created. + \note In Qt versions prior to 6.8, this function took only a \c{const char *}, + which was expected to be UTF-8-encoded. \sa isValid() */ diff --git a/src/corelib/text/qstringconverter.h b/src/corelib/text/qstringconverter.h index 40791f8e26..5df6f84e06 100644 --- a/src/corelib/text/qstringconverter.h +++ b/src/corelib/text/qstringconverter.h @@ -30,12 +30,9 @@ public: constexpr explicit QStringEncoder(Encoding encoding, Flags flags = Flag::Default) : QStringConverter(encoding, flags) {} - explicit QStringEncoder(const char *name, Flags flags = Flag::Default) + explicit QStringEncoder(QAnyStringView name, Flags flags = Flag::Default) : QStringConverter(name, flags) {} - Q_WEAK_OVERLOAD explicit QStringEncoder(const QString &name, Flags flags = Flag::Default) - : QStringEncoder(name.toLatin1().constData(), flags) - {} template<typename T> struct DecodedData @@ -95,12 +92,9 @@ public: constexpr QStringDecoder() noexcept : QStringConverter() {} - explicit QStringDecoder(const char *name, Flags f = Flag::Default) + explicit QStringDecoder(QAnyStringView name, Flags f = Flag::Default) : QStringConverter(name, f) {} - Q_WEAK_OVERLOAD explicit QStringDecoder(const QString &name, Flags f = Flag::Default) - : QStringDecoder(name.toLatin1().constData(), f) - {} template<typename T> struct EncodedData diff --git a/src/corelib/text/qstringconverter_base.h b/src/corelib/text/qstringconverter_base.h index d6b6fcb484..a78c64a96b 100644 --- a/src/corelib/text/qstringconverter_base.h +++ b/src/corelib/text/qstringconverter_base.h @@ -14,6 +14,7 @@ #include <QtCore/qglobal.h> // QT_{BEGIN,END}_NAMESPACE #include <QtCore/qflags.h> // Q_DECLARE_FLAGS #include <QtCore/qcontainerfwd.h> +#include <QtCore/qstringfwd.h> #include <cstring> @@ -137,7 +138,10 @@ protected: constexpr explicit QStringConverter(const Interface *i) noexcept : iface(i) {} +#if QT_CORE_REMOVED_SINCE(6, 8) Q_CORE_EXPORT explicit QStringConverter(const char *name, Flags f); +#endif + Q_CORE_EXPORT explicit QStringConverter(QAnyStringView name, Flags f); ~QStringConverter() = default; @@ -156,7 +160,10 @@ public: Q_CORE_EXPORT const char *name() const noexcept; +#if QT_CORE_REMOVED_SINCE(6, 8) Q_CORE_EXPORT static std::optional<Encoding> encodingForName(const char *name) noexcept; +#endif + Q_CORE_EXPORT static std::optional<Encoding> encodingForName(QAnyStringView name) noexcept; Q_CORE_EXPORT static const char *nameForEncoding(Encoding e); Q_CORE_EXPORT static std::optional<Encoding> encodingForData(QByteArrayView data, char16_t expectedFirstCharacter = 0) noexcept; diff --git a/src/corelib/text/qstringconverter_p.h b/src/corelib/text/qstringconverter_p.h index e68ffb2bb0..5c530cf1bd 100644 --- a/src/corelib/text/qstringconverter_p.h +++ b/src/corelib/text/qstringconverter_p.h @@ -52,6 +52,7 @@ struct QLatin1 static char *convertFromUnicode(char *out, QStringView in, QStringConverter::State *state) noexcept; // Defined in qstring.cpp + Q_CORE_EXPORT static char *convertFromUnicode(char *out, QStringView in) noexcept; }; diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h index ab97d834d3..2ad245caa3 100644 --- a/src/corelib/text/qstringview.h +++ b/src/corelib/text/qstringview.h @@ -108,7 +108,7 @@ private: static constexpr qsizetype lengthHelperPointer(const Char *str) noexcept { if (q20::is_constant_evaluated()) - return std::char_traits<Char>::length(str); + return QtPrivate::lengthHelperPointer(str); return QtPrivate::qustrlen(reinterpret_cast<const char16_t *>(str)); } static qsizetype lengthHelperPointer(const QChar *str) noexcept diff --git a/src/corelib/text/qutf8stringview.h b/src/corelib/text/qutf8stringview.h index fe105e283e..7ae06c0ec4 100644 --- a/src/corelib/text/qutf8stringview.h +++ b/src/corelib/text/qutf8stringview.h @@ -134,14 +134,12 @@ private: return qsizetype(std::size(c)); } - // Note: Do not replace with std::size(const Char (&)[N]), cause the result + // Note: Do not replace with std::size(const Char (&)[N]), because the result // will be of by one. template <typename Char, size_t N> static constexpr qsizetype lengthHelperContainer(const Char (&str)[N]) noexcept { - const auto it = std::char_traits<Char>::find(str, N, Char(0)); - const auto end = it ? it : std::next(str, N); - return qsizetype(std::distance(str, end)); + return QtPrivate::lengthHelperContainer(str); } template <typename Char> @@ -174,8 +172,7 @@ public: #else template <typename Pointer, if_compatible_pointer<Pointer> = true> constexpr QBasicUtf8StringView(const Pointer &str) noexcept - : QBasicUtf8StringView(str, - str ? std::char_traits<std::remove_cv_t<std::remove_pointer_t<Pointer>>>::length(str) : 0) {} + : QBasicUtf8StringView(str, QtPrivate::lengthHelperPointer(str)) {} #endif #ifdef Q_QDOC @@ -414,7 +411,8 @@ private: qsizetype m_size; }; -constexpr QByteArrayView::QByteArrayView(QUtf8StringView v) noexcept +template <bool UseChar8T> +constexpr QByteArrayView::QByteArrayView(QBasicUtf8StringView<UseChar8T> v) noexcept : QByteArrayView(v.data(), v.size()) {} |