diff options
-rw-r--r-- | src/corelib/text/qanystringview.h | 22 | ||||
-rw-r--r-- | src/corelib/text/qstring.cpp | 5 | ||||
-rw-r--r-- | src/corelib/text/qstringalgorithms.h | 56 | ||||
-rw-r--r-- | src/corelib/text/qstringview.h | 18 |
4 files changed, 66 insertions, 35 deletions
diff --git a/src/corelib/text/qanystringview.h b/src/corelib/text/qanystringview.h index ac5cb54c78..2be79c2b52 100644 --- a/src/corelib/text/qanystringview.h +++ b/src/corelib/text/qanystringview.h @@ -147,20 +147,6 @@ private: return qsizetype(strlen(reinterpret_cast<const char*>(str))); } - template <typename Container> - static constexpr qsizetype lengthHelperContainer(const Container &c) noexcept - { - return qsizetype(std::size(c)); - } - - 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)); - } - static QChar toQChar(char ch) noexcept { return toQChar(QLatin1Char{ch}); } // we don't handle UTF-8 multibytes static QChar toQChar(QChar ch) noexcept { return ch; } static QChar toQChar(QLatin1Char ch) noexcept { return ch; } @@ -202,8 +188,8 @@ public: inline constexpr QAnyStringView(QLatin1StringView str) noexcept; template <typename Container, if_compatible_container<Container> = true> - constexpr QAnyStringView(const Container &c) noexcept - : QAnyStringView(std::data(c), lengthHelperContainer(c)) {} + constexpr Q_ALWAYS_INLINE QAnyStringView(const Container &c) noexcept + : QAnyStringView(std::data(c), QtPrivate::lengthHelperContainer(c)) {} template <typename Container, if_convertible_to<QString, Container> = true> constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t<Container, QString> &&capacity = {}) @@ -227,11 +213,11 @@ public: : QAnyStringView(capacity = QChar::fromUcs4(c)) {} constexpr QAnyStringView(QStringView v) noexcept - : QAnyStringView(std::data(v), lengthHelperContainer(v)) {} + : QAnyStringView(std::data(v), QtPrivate::lengthHelperContainer(v)) {} template <bool UseChar8T> constexpr QAnyStringView(QBasicUtf8StringView<UseChar8T> v) noexcept - : QAnyStringView(std::data(v), lengthHelperContainer(v)) {} + : QAnyStringView(std::data(v), QtPrivate::lengthHelperContainer(v)) {} template <typename Char, size_t Size, if_compatible_char<Char> = true> [[nodiscard]] constexpr static QAnyStringView fromArray(const Char (&string)[Size]) noexcept diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 1fae9ef07a..15cf40ef88 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -698,6 +698,11 @@ qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept return result; } +qsizetype QtPrivate::qustrnlen(const char16_t *str, qsizetype maxlen) noexcept +{ + return qustrchr({ str, maxlen }, u'\0') - str; +} + /*! * \internal * diff --git a/src/corelib/text/qstringalgorithms.h b/src/corelib/text/qstringalgorithms.h index 888bad5dd3..a8d43b3ed0 100644 --- a/src/corelib/text/qstringalgorithms.h +++ b/src/corelib/text/qstringalgorithms.h @@ -11,11 +11,15 @@ #pragma qt_class(QStringAlgorithms) #endif +#include <algorithm> // std::find +#include <string> // std::char_traits + QT_BEGIN_NAMESPACE namespace QtPrivate { [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype qustrlen(const char16_t *str) noexcept; +[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype qustrnlen(const char16_t *str, qsizetype maxlen) noexcept; [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION const char16_t *qustrchr(QStringView str, char16_t ch) noexcept; [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int compareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept; @@ -114,7 +118,57 @@ namespace QtPrivate { [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isLatin1(QStringView s) noexcept; [[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isValidUtf16(QStringView s) noexcept; -} // namespace QtPRivate +template <typename Char, size_t N> [[nodiscard]] constexpr Q_ALWAYS_INLINE +std::enable_if_t<sizeof(Char) == sizeof(char16_t), qsizetype> +lengthHelperContainer(const Char (&str)[N]) +{ + // The following values were empirically determined to detect the threshold + // at which the compiler gives up pre-calculating the std::find() below and + // instead inserts code to be executed at runtime. + constexpr size_t RuntimeThreshold = +#if defined(Q_CC_CLANG) // tested through Clang 16.0.0 + 100 +#elif defined(Q_CC_GNU) // tested through GCC 13.1 at -O3 compilation level + __cplusplus >= 202002L ? 39 : 17 +#else + 0 +#endif + ; + if constexpr (N == 1) { + return str[0] == Char(0) ? 0 : 1; + } else if constexpr (N > RuntimeThreshold) { +#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED + if (!qIsConstantEvaluated()) + return QtPrivate::qustrnlen(reinterpret_cast<const char16_t *>(str), N); +#endif + } + + // libstdc++'s std::find_if yields a higher threshold than + // std::char_traits::find + +#if __cplusplus >= 202002 && defined(__cpp_lib_constexpr_algorithms) + const auto it = std::find(str, str + N, Char(0)); + return it - str; +#else + const auto it = std::char_traits<Char>::find(str, N, Char(0)); + return it ? std::distance(str, it) : ptrdiff_t(N); +#endif +} + +template <typename Char, size_t N> [[nodiscard]] constexpr inline +std::enable_if_t<sizeof(Char) == 1, qsizetype> lengthHelperContainer(const Char (&str)[N]) +{ + // std::char_traits::find will call memchr or __builtin_memchr for us + const auto it = std::char_traits<Char>::find(str, N, Char(0)); + return it ? std::distance(str, it) : ptrdiff_t(N); +} + +template <typename Container> +constexpr qsizetype lengthHelperContainer(const Container &c) noexcept +{ + return qsizetype(std::size(c)); +} +} // namespace QtPrivate QT_END_NAMESPACE diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h index e4c0c4dd8d..a6f217d2a5 100644 --- a/src/corelib/text/qstringview.h +++ b/src/corelib/text/qstringview.h @@ -116,20 +116,6 @@ private: return QtPrivate::qustrlen(reinterpret_cast<const char16_t *>(str)); } - template <typename Container> - static constexpr qsizetype lengthHelperContainer(const Container &c) noexcept - { - return qsizetype(std::size(c)); - } - - 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::end(str); - return qsizetype(std::distance(str, end)); - } - template <typename Char> static const storage_type *castHelper(const Char *str) noexcept { return reinterpret_cast<const storage_type*>(str); } @@ -178,8 +164,8 @@ public: #endif template <typename Container, if_compatible_container<Container> = true> - constexpr QStringView(const Container &c) noexcept - : QStringView(std::data(c), lengthHelperContainer(c)) {} + constexpr Q_ALWAYS_INLINE QStringView(const Container &c) noexcept + : QStringView(std::data(c), QtPrivate::lengthHelperContainer(c)) {} template <typename Char, size_t Size, if_compatible_char<Char> = true> [[nodiscard]] constexpr static QStringView fromArray(const Char (&string)[Size]) noexcept |