diff --git a/src/corelib/text/qanystringview.h b/src/corelib/text/qanystringview.h index 774651cb6a..6cdc58ddbf 100644 --- a/src/corelib/text/qanystringview.h +++ b/src/corelib/text/qanystringview.h @@ -47,6 +47,8 @@ #endif #include +class tst_QAnyStringView; + QT_BEGIN_NAMESPACE template class QStringBuilder; @@ -81,14 +83,41 @@ private: static_assert(QtPrivate::IsContainerCompatibleWithQStringView::value == false); static_assert(QtPrivate::IsContainerCompatibleWithQUtf8StringView::value == false); - template - static constexpr std::size_t encodeType(qsizetype sz) noexcept + template + static constexpr bool isAsciiOnlyCharsAtCompileTime(Char *str, qsizetype sz) noexcept { - // only deals with Utf8 and Utf16 - there's only one way to create - // a Latin1 string, and that ctor deals with the tag itself + // do not perform check if not at compile time +#if defined(__cpp_lib_is_constant_evaluated) + if (!std::is_constant_evaluated()) + return false; +#elif defined(Q_CC_GNU) && !defined(Q_CC_CLANG) + if (!str || !__builtin_constant_p(*str)) + return false; +#else + return false; +#endif + if constexpr (sizeof(Char) != sizeof(char)) { + Q_UNUSED(str); + Q_UNUSED(sz); + return false; + } else { + for (qsizetype i = 0; i < sz; ++i) { + if (uchar(str[i]) > 0x7f) + return false; + } + } + return true; + } + + template + static constexpr std::size_t encodeType(const Char *str, qsizetype sz) noexcept + { + // Utf16 if 16 bit, Latin1 if ASCII, else Utf8 Q_ASSERT(sz >= 0); Q_ASSERT(sz <= qsizetype(SizeMask)); - return std::size_t(sz) | uint(sizeof(Char) == sizeof(char16_t)) * Tag::Utf16; + Q_ASSERT(str || !sz); + return std::size_t(sz) | uint(sizeof(Char) == sizeof(char16_t)) * Tag::Utf16 + | uint(isAsciiOnlyCharsAtCompileTime(str, sz)) * Tag::Latin1; } template @@ -136,8 +165,9 @@ public: template = true> constexpr QAnyStringView(const Char *str, qsizetype len) - : m_data{str}, - m_size{encodeType((Q_ASSERT(len >= 0), Q_ASSERT(str || !len), len))} {} + : m_data{str}, m_size{encodeType(str, len)} + { + } template = true> constexpr QAnyStringView(const Char *f, const Char *l) @@ -204,6 +234,13 @@ public: [[nodiscard]] Q_CORE_EXPORT static int compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; [[nodiscard]] Q_CORE_EXPORT static bool equal(QAnyStringView lhs, QAnyStringView rhs) noexcept; + static constexpr inline bool detects_US_ASCII_at_compile_time = +#ifdef __cpp_lib_is_constant_evaluated + true +#else + false +#endif + ; // // STL compatibility API: // @@ -286,6 +323,7 @@ private: const char16_t *m_data_utf16; }; size_t m_size; + friend class ::tst_QAnyStringView; }; Q_DECLARE_TYPEINFO(QAnyStringView, Q_PRIMITIVE_TYPE); diff --git a/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp b/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp index 73dc02b082..c92f4171ff 100644 --- a/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp +++ b/tests/auto/corelib/text/qanystringview/tst_qanystringview.cpp @@ -246,6 +246,7 @@ class tst_QAnyStringView : public QObject private Q_SLOTS: void constExpr() const; void basics() const; + void asciiLiteralIsLatin1() const; void fromQString() const { fromQStringOrByteArray(); } void fromQByteArray() const { fromQStringOrByteArray(); } @@ -431,6 +432,27 @@ void tst_QAnyStringView::basics() const QVERIFY(!(sv2 != sv1)); } +void tst_QAnyStringView::asciiLiteralIsLatin1() const +{ + if constexpr (QAnyStringView::detects_US_ASCII_at_compile_time) { + constexpr bool asciiCstringIsLatin1 = QAnyStringView("Hello, World").isLatin1(); + QVERIFY(asciiCstringIsLatin1); + constexpr bool asciiUtf8stringIsLatin1 = QAnyStringView(u8"Hello, World").isLatin1(); + QVERIFY(asciiUtf8stringIsLatin1); + constexpr bool utf8StringIsNotLatin1 = !QAnyStringView(u8"Tørrfisk").isLatin1(); + QVERIFY(utf8StringIsNotLatin1); + constexpr bool asciiCstringArrayIsLatin1 = + QAnyStringView::fromArray("Hello, World").isLatin1(); + QVERIFY(asciiCstringArrayIsLatin1); + constexpr bool asciiUtfstringArrayIsLatin1 = + QAnyStringView::fromArray(u8"Hello, World").isLatin1(); + QVERIFY(asciiUtfstringArrayIsLatin1); + constexpr bool utf8StringArrayIsNotLatin1 = + !QAnyStringView::fromArray(u8"Tørrfisk").isLatin1(); + QVERIFY(utf8StringArrayIsNotLatin1); + } +} + template void tst_QAnyStringView::fromQStringBuilder(StringBuilder &&sb, QStringView expected) const {