From fc88dd52a42da682cbd360916be7c9f94a69b72c Mon Sep 17 00:00:00 2001 From: David Faure Date: Thu, 25 Oct 2018 11:07:58 +0200 Subject: [PATCH] QByteArrayList: add indexOf(const char*) overload This avoids memory allocation and data copying in e.g. QObject::property(). Detected by heaptrack's "Temporary allocations" counter in an application using the breeze widget style (many animations). Change-Id: Iabdb58a3e504cb121cce906ef707b0722de89df6 Reviewed-by: Thiago Macieira --- src/corelib/tools/qbytearraylist.cpp | 22 ++++++++++++++++ src/corelib/tools/qbytearraylist.h | 4 +++ .../qbytearraylist/tst_qbytearraylist.cpp | 26 +++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/src/corelib/tools/qbytearraylist.cpp b/src/corelib/tools/qbytearraylist.cpp index c815e766ab9..d04555ed4d6 100644 --- a/src/corelib/tools/qbytearraylist.cpp +++ b/src/corelib/tools/qbytearraylist.cpp @@ -150,4 +150,26 @@ QByteArray QtPrivate::QByteArrayList_join(const QByteArrayList *that, const char return res; } +/*! + \fn int QByteArrayList::indexOf(const char *needle, int from) const + + Returns the index position of the first occurrence of \a needle in + the list, searching forward from index position \a from. Returns + -1 if no item matched. + + \a needle must be NUL-terminated. + + This overload doesn't require creating a QByteArray, thus saving a + memory allocation and some CPU time. + + \since 5.13 + \overload +*/ + +int QtPrivate::QByteArrayList_indexOf(const QByteArrayList *that, const char *needle, int from) +{ + const auto it = std::find_if(that->begin() + from, that->end(), [needle](const QByteArray &item) { return item == needle; }); + return it == that->end() ? -1 : int(std::distance(that->begin(), it)); +} + QT_END_NAMESPACE diff --git a/src/corelib/tools/qbytearraylist.h b/src/corelib/tools/qbytearraylist.h index be94bc1d403..d69e8bb54b3 100644 --- a/src/corelib/tools/qbytearraylist.h +++ b/src/corelib/tools/qbytearraylist.h @@ -55,6 +55,7 @@ typedef QList QByteArrayList; namespace QtPrivate { QByteArray Q_CORE_EXPORT QByteArrayList_join(const QByteArrayList *that, const char *separator, int separatorLength); + int Q_CORE_EXPORT QByteArrayList_indexOf(const QByteArrayList *that, const char *needle, int from); } #endif @@ -76,6 +77,9 @@ public: inline QByteArray join(char sep) const { return QtPrivate::QByteArrayList_join(self(), &sep, 1); } + inline int indexOf(const char *needle, int from = 0) const + { return QtPrivate::QByteArrayList_indexOf(self(), needle, from); } + private: typedef QList Self; Self *self() { return static_cast(this); } diff --git a/tests/auto/corelib/tools/qbytearraylist/tst_qbytearraylist.cpp b/tests/auto/corelib/tools/qbytearraylist/tst_qbytearraylist.cpp index 85b4c4bfb76..2d2c5364530 100644 --- a/tests/auto/corelib/tools/qbytearraylist/tst_qbytearraylist.cpp +++ b/tests/auto/corelib/tools/qbytearraylist/tst_qbytearraylist.cpp @@ -49,6 +49,9 @@ private slots: void operator_plus() const; void operator_plus_data() const; + void indexOf_data() const; + void indexOf() const; + void initializerList() const; }; @@ -259,6 +262,29 @@ void tst_QByteArrayList::operator_plus_data() const << ( QByteArrayList() << "a" << "" << "c" ); } +void tst_QByteArrayList::indexOf_data() const +{ + QTest::addColumn("list"); + QTest::addColumn("item"); + QTest::addColumn("expectedResult"); + + QTest::newRow("empty") << QByteArrayList() << QByteArray("a") << -1; + QTest::newRow("found_1") << ( QByteArrayList() << "a" ) << QByteArray("a") << 0; + QTest::newRow("not_found_1") << ( QByteArrayList() << "a" ) << QByteArray("b") << -1; + QTest::newRow("found_2") << ( QByteArrayList() << "hello" << "world" ) << QByteArray("world") << 1; + QTest::newRow("returns_first") << ( QByteArrayList() << "hello" << "world" << "hello" << "again" ) << QByteArray("hello") << 0; +} + +void tst_QByteArrayList::indexOf() const +{ + QFETCH(QByteArrayList, list); + QFETCH(QByteArray, item); + QFETCH(int, expectedResult); + + QCOMPARE(list.indexOf(item), expectedResult); + QCOMPARE(list.indexOf(item.constData()), expectedResult); +} + void tst_QByteArrayList::initializerList() const { #ifdef Q_COMPILER_INITIALIZER_LISTS