QByteArray: inline QByteArray::indexOf() and use a char overload
QByteArray::indexOf() had the best implementation of the two *because*
it was out-of-line, in qbytearray.cpp. The compiler could thus see the
body of the QtPrivate::findByteArray() function and inline it, with
constant-propagation, so only findCharHelper() was expanded and we had a
fast path towards memchr().
On the other hand, QByteArrayView::indexOf() was inline, so the
compiler emitted the call to QtPrivate::findByteArray() in user code,
causing the full function to be executed. We fix that by adding a char
overload for QtPrivate::findByteArray() and lastIndexOf(), so we get to
memchr() more quickly.
Also, inline QByteArray::indexOf() and lastIndexOf().
Before:
QByteArray::indexOf():
8.83287376 nsecs per iteration
22.01766832 CPU cycles per iteration, 2.49 GHz
62.00000330 instructions per iteration, 2.816 instr/cycle
21.00000281 branch instructions per iteration, 2.38 G/sec
QByteArrayView::indexOf():
9.64034694 nsecs per iteration
24.03001151 CPU cycles per iteration, 2.49 GHz
68.00000355 instructions per iteration, 2.830 instr/cycle
23.00000306 branch instructions per iteration, 2.39 G/sec
After (same result for both, requires recompilation):
8.83207052 nsecs per iteration
22.01568546 CPU cycles per iteration, 2.49 GHz
60.00000331 instructions per iteration, 2.725 instr/cycle
21.00000281 branch instructions per iteration, 2.38 G/sec
The inlining appears to have cut 2 instructions, but the effect is not
measurable in this benchmark (the entire code is in cache and the Branch
Predictor is probably primed).
Fixes: QTBUG-119750
Change-Id: Ica7a43f6147b49c187ccfffd179e1cb4b306fc62
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
bb10
parent
dfe968e970
commit
5ea4e27661
|
|
@ -625,7 +625,7 @@ QBitArray QBitArray::operator~() const
|
|||
return QBitArray(*this).inverted_inplace();
|
||||
}
|
||||
|
||||
#include "qbytearray.h"
|
||||
#include "qbytearray.h" // also includes inlined API
|
||||
|
||||
QByteArray QByteArray::left(qsizetype len) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2656,6 +2656,11 @@ static inline qsizetype findCharHelper(QByteArrayView haystack, qsizetype from,
|
|||
return -1;
|
||||
}
|
||||
|
||||
qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, char needle) noexcept
|
||||
{
|
||||
return findCharHelper(haystack, from, needle);
|
||||
}
|
||||
|
||||
qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept
|
||||
{
|
||||
const auto ol = needle.size();
|
||||
|
|
@ -2690,6 +2695,7 @@ qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByt
|
|||
*/
|
||||
|
||||
/*!
|
||||
\fn qsizetype QByteArray::indexOf(char ch, qsizetype from) const
|
||||
\overload
|
||||
|
||||
Returns the index position of the start of the first occurrence of the
|
||||
|
|
@ -2702,11 +2708,6 @@ qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByt
|
|||
\sa lastIndexOf(), contains()
|
||||
*/
|
||||
|
||||
qsizetype QByteArray::indexOf(char ch, qsizetype from) const
|
||||
{
|
||||
return qToByteArrayViewIgnoringNull(*this).indexOf(ch, from);
|
||||
}
|
||||
|
||||
static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char *needle,
|
||||
qsizetype ol, qsizetype from)
|
||||
{
|
||||
|
|
@ -2760,6 +2761,11 @@ static inline qsizetype lastIndexOfCharHelper(QByteArrayView haystack, qsizetype
|
|||
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()) {
|
||||
|
|
@ -2813,6 +2819,7 @@ qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteA
|
|||
*/
|
||||
|
||||
/*!
|
||||
\fn qsizetype QByteArray::lastIndexOf(char ch, qsizetype from) const
|
||||
\overload
|
||||
|
||||
Returns the index position of the start of the last occurrence of byte \a ch
|
||||
|
|
@ -2826,11 +2833,6 @@ qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteA
|
|||
\sa indexOf(), contains()
|
||||
*/
|
||||
|
||||
qsizetype QByteArray::lastIndexOf(char ch, qsizetype from) const
|
||||
{
|
||||
return qToByteArrayViewIgnoringNull(*this).lastIndexOf(ch, from);
|
||||
}
|
||||
|
||||
static inline qsizetype countCharHelper(QByteArrayView haystack, char needle) noexcept
|
||||
{
|
||||
qsizetype num = 0;
|
||||
|
|
|
|||
|
|
@ -133,10 +133,12 @@ public:
|
|||
[[nodiscard]] char back() const { return at(size() - 1); }
|
||||
[[nodiscard]] inline char &back();
|
||||
|
||||
QT_CORE_INLINE_SINCE(6, 7)
|
||||
qsizetype indexOf(char c, qsizetype from = 0) const;
|
||||
qsizetype indexOf(QByteArrayView bv, qsizetype from = 0) const
|
||||
{ return QtPrivate::findByteArray(qToByteArrayViewIgnoringNull(*this), from, bv); }
|
||||
|
||||
QT_CORE_INLINE_SINCE(6, 7)
|
||||
qsizetype lastIndexOf(char c, qsizetype from = -1) const;
|
||||
qsizetype lastIndexOf(QByteArrayView bv) const
|
||||
{ return lastIndexOf(bv, size()); }
|
||||
|
|
@ -688,6 +690,16 @@ bool QByteArray::isNull() const noexcept
|
|||
return d->isNull();
|
||||
}
|
||||
#endif
|
||||
#if QT_CORE_INLINE_IMPL_SINCE(6, 7)
|
||||
qsizetype QByteArray::indexOf(char ch, qsizetype from) const
|
||||
{
|
||||
return qToByteArrayViewIgnoringNull(*this).indexOf(ch, from);
|
||||
}
|
||||
qsizetype QByteArray::lastIndexOf(char ch, qsizetype from) const
|
||||
{
|
||||
return qToByteArrayViewIgnoringNull(*this).lastIndexOf(ch, from);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
|
||||
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QByteArray &);
|
||||
|
|
|
|||
|
|
@ -25,9 +25,15 @@ bool startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept;
|
|||
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
|
||||
bool endsWith(QByteArrayView haystack, QByteArrayView needle) noexcept;
|
||||
|
||||
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
|
||||
qsizetype findByteArray(QByteArrayView haystack, qsizetype from, char needle) noexcept;
|
||||
|
||||
[[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]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
|
||||
qsizetype lastIndexOf(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept;
|
||||
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ public:
|
|||
[[nodiscard]] qsizetype indexOf(QByteArrayView a, qsizetype from = 0) const noexcept
|
||||
{ return QtPrivate::findByteArray(*this, from, a); }
|
||||
[[nodiscard]] qsizetype indexOf(char ch, qsizetype from = 0) const noexcept
|
||||
{ return QtPrivate::findByteArray(*this, from, QByteArrayView(&ch, 1)); }
|
||||
{ return QtPrivate::findByteArray(*this, from, ch); }
|
||||
|
||||
[[nodiscard]] bool contains(QByteArrayView a) const noexcept
|
||||
{ return indexOf(a) != qsizetype(-1); }
|
||||
|
|
@ -275,7 +275,7 @@ public:
|
|||
[[nodiscard]] qsizetype lastIndexOf(QByteArrayView a, qsizetype from) const noexcept
|
||||
{ return QtPrivate::lastIndexOf(*this, from, a); }
|
||||
[[nodiscard]] qsizetype lastIndexOf(char ch, qsizetype from = -1) const noexcept
|
||||
{ return QtPrivate::lastIndexOf(*this, from, QByteArrayView(&ch, 1)); }
|
||||
{ return QtPrivate::lastIndexOf(*this, from, ch); }
|
||||
|
||||
[[nodiscard]] qsizetype count(QByteArrayView a) const noexcept
|
||||
{ return QtPrivate::count(*this, a); }
|
||||
|
|
|
|||
Loading…
Reference in New Issue