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 <a.samirh78@gmail.com>
This commit is contained in:
Thiago Macieira 2024-05-18 17:42:06 -05:00
parent 5bf0c3d5d3
commit 4c12ae7e67
6 changed files with 70 additions and 27 deletions

View File

@ -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

View File

@ -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 <string.h>
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"

View File

@ -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

View File

@ -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<const char *>(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);
}

View File

@ -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)

View File

@ -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<const char *>(n) - b : -1;
}
QT_END_NAMESPACE
#endif // QBYTEARRAYVIEW_H