summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/text/qanystringview.h22
-rw-r--r--src/corelib/text/qstring.cpp5
-rw-r--r--src/corelib/text/qstringalgorithms.h56
-rw-r--r--src/corelib/text/qstringview.h18
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