From 4c12ae7e67abc3d9b5847f6b61177ede3ee3203b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 18 May 2024 17:42:06 -0500 Subject: [PATCH] QByteArrayView: inline the char overload of lastIndexOf() It's just memrchr()... which unfortunately is a GNU extension (picked by FreeBSD and OpenBSD too), so we need to provide a fallback implementation for other OSes and bootstrap mode. By creating a new overload instead of doing the inlining trick, this gets inlined in QtCore uses as well and has a simpler #ifdef'ery. We still reach the C library function indirectly, but that's going to be minimal (and unavoidable) overhead, more than offset by the gain in accessing an optimized memrchr(). Change-Id: If05cb740b64f42eba21efffd17d0b681bcfe9cf3 Reviewed-by: Ahmad Samir --- src/corelib/compat/removed_api.cpp | 9 ++++ src/corelib/configure.cmake | 19 +++++++++ src/corelib/global/qconfig-bootstrapped.h | 1 + src/corelib/text/qbytearray.cpp | 50 +++++++++++------------ src/corelib/text/qbytearrayalgorithms.h | 6 ++- src/corelib/text/qbytearrayview.h | 12 ++++++ 6 files changed, 70 insertions(+), 27 deletions(-) diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp index 6aafc6e6e0a..40ef9875b00 100644 --- a/src/corelib/compat/removed_api.cpp +++ b/src/corelib/compat/removed_api.cpp @@ -954,6 +954,15 @@ bool QPersistentModelIndex::operator!=(const QModelIndex &other) const noexcept #include "qbytearray.h" // inlined API +QT_BEGIN_NAMESPACE +namespace QtPrivate { +Q_CORE_EXPORT qsizetype lastIndexOf(QByteArrayView haystack, qsizetype from, char needle) noexcept +{ + return lastIndexOf(haystack, from, uchar(needle)); +} +} +QT_END_NAMESPACE + #include "qcborarray.h" // inlined API #include "qcbormap.h" // inlined API diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake index 83983dfa2e0..7c07aa1c88a 100644 --- a/src/corelib/configure.cmake +++ b/src/corelib/configure.cmake @@ -324,6 +324,21 @@ linkat(AT_FDCWD, \"foo\", AT_FDCWD, \"bar\", AT_SYMLINK_FOLLOW); } ") +# memrchr +qt_config_compile_test(memrchr + LABEL "memrchr()" + CODE +"#define _BSD_SOURCE 1 /* For FreeBSD */ +#define _GNU_SOURCE 1 /* For glibc, Bionic */ +#include + +int main(void) +{ + const void *r = memrchr(\"abc\", 'a', 3); + (void)r; + return 0; +}") + # ppoll qt_config_compile_test(ppoll LABEL "ppoll()" @@ -554,6 +569,10 @@ qt_feature("std-atomic64" PUBLIC LABEL "64 bit atomic operations" CONDITION WrapAtomic_FOUND ) +qt_feature("memrchr" PRIVATE + LABEL "C library function memrchr()" + CONDITION TEST_memrchr +) qt_feature("mimetype" PUBLIC SECTION "Utilities" LABEL "Mimetype handling" diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h index 4d80f23786c..0596b9d9f4c 100644 --- a/src/corelib/global/qconfig-bootstrapped.h +++ b/src/corelib/global/qconfig-bootstrapped.h @@ -72,6 +72,7 @@ # define QT_FEATURE_linkat -1 #endif #define QT_FEATURE_lttng -1 +#define QT_FEATURE_memrchr -1 #define QT_NO_QOBJECT #define QT_FEATURE_process -1 #define QT_FEATURE_regularexpression 1 diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index c140a6aec8b..d9f0ee405a6 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -60,6 +60,30 @@ static constexpr inline uchar asciiLower(uchar c) 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(s); + const char *n = b + size; + while (n-- != b) { + if (*n == needle) + return n; + } + return nullptr; +} + + /*! \relates QByteArray Returns a duplicate string. @@ -2738,30 +2762,6 @@ static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char 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 { if (haystack.isEmpty()) { @@ -2771,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); } diff --git a/src/corelib/text/qbytearrayalgorithms.h b/src/corelib/text/qbytearrayalgorithms.h index 7060161bb46..649ec2e39bd 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/qbytearrayview.h b/src/corelib/text/qbytearrayview.h index 45ebc812cdc..9f7d854a9ae 100644 --- a/src/corelib/text/qbytearrayview.h +++ b/src/corelib/text/qbytearrayview.h @@ -401,6 +401,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(n) - b : -1; +} + QT_END_NAMESPACE #endif // QBYTEARRAYVIEW_H