Q{Any,}StringView: optimize lengthHelperContainer for the runtime
Deduplicate it in the process by moving to qstringalgorithms.h. In non-constexpr contexts, both GCC and Clang were giving up in pre-calculating the length if the UTF-16 string literal was too big. For the old code, that was 14 and 16 characters respectively. That number can be raised by adding some Q_ALWAYS_INLINE and (for GCC's case), replacing std::char_traits::find() with std::find(). If that limit is exceeded, we call the newly introduced qustrnlen() function. qustrnlen() is just qustrchr(), like qstrnlen() is just memchr(). But it is introduced as a separate function so we could change implementation if we ever wished to, plus QStringView is only forward-declared at this point. Change-Id: Ieab617d69f3b4b54ab30fffd175c560d926db1c3 Reviewed-by: Ahmad Samir <a.samirh78@gmail.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>bb10
parent
95e6fac0a5
commit
b1ee49b465
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue