QObject: port findChild/ren() to QAnyStringView

Change the object's name type in QObject::findChild/ren() to
QAnyStringView, because they are only used for comparison against
objectName property.

qt_qFindChild{,ren}_helper() functions taking an objectname as
QString have to stay in the ABI as they were exported in inline
methods before Qt 6.7.

Unlike QString, constructing a null QAnyStringView doesn't involve
any code-size overhead. So, get rid of the split in qt_qFindChildren_helper
that was introduced for QString. Remove unneeded
qt_qFindChildren_with_name helper function and qt_qFindChildren_helper
overload without a name.
findChildren(options) method used to call qt_qFindChildren_helper overload.
Instead, call findChildren overload with name argument and pass
QAnyStringView{} as the object name.

[ChangeLog][QtCore][QObject] Ported QObject::findChild/ren() and
their helper functions to QAnyStringView.

Task-number: QTBUG-103986
Change-Id: I68bda0e581f984ae48b7581ad86cc1b95008c1b0
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
This commit is contained in:
Rym Bouabid 2023-10-06 18:34:57 +02:00
parent bdd41f491c
commit e608bc0192
4 changed files with 79 additions and 40 deletions

View File

@ -773,6 +773,20 @@ QString QLocale::bcp47Name() const
return bcp47Name(TagSeparator::Dash); return bcp47Name(TagSeparator::Dash);
} }
#include "qobject.h"
void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QMetaObject &mo,
QList<void*> *list, Qt::FindChildOptions options)
{
qt_qFindChildren_helper(parent, QAnyStringView{name}, mo, list, options);
}
QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo,
Qt::FindChildOptions options)
{
return qt_qFindChild_helper(parent, QAnyStringView{name}, mo, options);
}
#include "qobjectdefs.h" #include "qobjectdefs.h"
int QMetaObject::indexOfEnumerator(const char *name) const int QMetaObject::indexOfEnumerator(const char *name) const

View File

@ -1982,7 +1982,7 @@ void QObject::killTimer(int id)
/*! /*!
\fn template<typename T> T *QObject::findChild(const QString &name, Qt::FindChildOptions options) const \fn template<typename T> T *QObject::findChild(QAnyStringView name, Qt::FindChildOptions options) const
Returns the child of this object that can be cast into type T and Returns the child of this object that can be cast into type T and
that is called \a name, or \nullptr if there is no such object. that is called \a name, or \nullptr if there is no such object.
@ -2016,11 +2016,14 @@ void QObject::killTimer(int id)
\snippet code/src_corelib_kernel_qobject.cpp 42 \snippet code/src_corelib_kernel_qobject.cpp 42
\note In Qt versions prior to 6.7, this function took \a name as
\c{QString}, not \c{QAnyStringView}.
\sa findChildren() \sa findChildren()
*/ */
/*! /*!
\fn template<typename T> QList<T> QObject::findChildren(const QString &name, Qt::FindChildOptions options) const \fn template<typename T> QList<T> QObject::findChildren(QAnyStringView name, Qt::FindChildOptions options) const
Returns all children of this object with the given \a name that can be Returns all children of this object with the given \a name that can be
cast to type T, or an empty list if there are no such objects. cast to type T, or an empty list if there are no such objects.
@ -2042,6 +2045,9 @@ void QObject::killTimer(int id)
\snippet code/src_corelib_kernel_qobject.cpp 43 \snippet code/src_corelib_kernel_qobject.cpp 43
\note In Qt versions prior to 6.7, this function took \a name as
\c{QString}, not \c{QAnyStringView}.
\sa findChild() \sa findChild()
*/ */
@ -2103,46 +2109,26 @@ void QObject::killTimer(int id)
\sa QObject::findChildren() \sa QObject::findChildren()
*/ */
static void qt_qFindChildren_with_name(const QObject *parent, const QString &name, static bool matches_objectName_non_null(QObject *obj, QAnyStringView name)
const QMetaObject &mo, QList<void *> *list,
Qt::FindChildOptions options)
{ {
Q_ASSERT(parent); if (auto ext = QObjectPrivate::get(obj)->extraData)
Q_ASSERT(list); return ext ->objectName.valueBypassingBindings() == name;
Q_ASSERT(!name.isNull()); return name.isEmpty();
for (QObject *obj : parent->children()) {
if (mo.cast(obj) && obj->objectName() == name)
list->append(obj);
if (options & Qt::FindChildrenRecursively)
qt_qFindChildren_with_name(obj, name, mo, list, options);
}
} }
/*! /*!
\internal \internal
*/ */
void qt_qFindChildren_helper(const QObject *parent, const QString &name, void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name,
const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options) const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
{
if (name.isNull())
return qt_qFindChildren_helper(parent, mo, list, options);
else
return qt_qFindChildren_with_name(parent, name, mo, list, options);
}
/*!
\internal
*/
void qt_qFindChildren_helper(const QObject *parent, const QMetaObject &mo,
QList<void*> *list, Qt::FindChildOptions options)
{ {
Q_ASSERT(parent); Q_ASSERT(parent);
Q_ASSERT(list); Q_ASSERT(list);
for (QObject *obj : parent->children()) { for (QObject *obj : parent->children()) {
if (mo.cast(obj)) if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
list->append(obj); list->append(obj);
if (options & Qt::FindChildrenRecursively) if (options & Qt::FindChildrenRecursively)
qt_qFindChildren_helper(obj, mo, list, options); qt_qFindChildren_helper(obj, name, mo, list, options);
} }
} }
@ -2169,13 +2155,13 @@ void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re
/*! /*!
\internal \internal
*/ */
QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options) QObject *qt_qFindChild_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, Qt::FindChildOptions options)
{ {
Q_ASSERT(parent); Q_ASSERT(parent);
for (QObject *obj : parent->children()) { for (QObject *obj : parent->children()) {
if (mo.cast(obj) && (name.isNull() || obj->objectName() == name)) if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
return obj; return obj;
} }
if (options & Qt::FindChildrenRecursively) { if (options & Qt::FindChildrenRecursively) {
for (QObject *child : parent->children()) { for (QObject *child : parent->children()) {

View File

@ -43,13 +43,22 @@ struct QDynamicMetaObjectData;
typedef QList<QObject*> QObjectList; typedef QList<QObject*> QObjectList;
#if QT_CORE_REMOVED_SINCE(6, 7)
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name, Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name,
const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options); const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
#endif
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name,
const QMetaObject &mo, QList<void *> *list,
Qt::FindChildOptions options);
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QMetaObject &mo, Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QMetaObject &mo,
QList<void *> *list, Qt::FindChildOptions options); QList<void *> *list, Qt::FindChildOptions options);
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re, Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,
const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options); const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
#if QT_CORE_REMOVED_SINCE(6, 7)
Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options); Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options);
#endif
Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, QAnyStringView name,
const QMetaObject &mo, Qt::FindChildOptions options);
class Q_CORE_EXPORT QObjectData class Q_CORE_EXPORT QObjectData
{ {
@ -131,14 +140,14 @@ public:
void killTimer(int id); void killTimer(int id);
template<typename T> template<typename T>
inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const T findChild(QAnyStringView aName = {}, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
{ {
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType; typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
return static_cast<T>(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options)); return static_cast<T>(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));
} }
template<typename T> template<typename T>
inline QList<T> findChildren(const QString &aName, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const QList<T> findChildren(QAnyStringView aName, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
{ {
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType; typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
QList<T> list; QList<T> list;
@ -150,11 +159,7 @@ public:
template<typename T> template<typename T>
QList<T> findChildren(Qt::FindChildOptions options = Qt::FindChildrenRecursively) const QList<T> findChildren(Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
{ {
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType; return findChildren<T>(QAnyStringView{}, options);
QList<T> list;
qt_qFindChildren_helper(this, ObjType::staticMetaObject,
reinterpret_cast<QList<void *> *>(&list), options);
return list;
} }
#if QT_CONFIG(regularexpression) #if QT_CONFIG(regularexpression)

View File

@ -39,6 +39,8 @@
#include <math.h> #include <math.h>
using namespace Qt::StringLiterals;
class tst_QObject : public QObject class tst_QObject : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -520,6 +522,10 @@ void tst_QObject::findChildren()
QTimer t1(&o); QTimer t1(&o);
QTimer t121(&o12); QTimer t121(&o12);
QTimer emptyname(&o); QTimer emptyname(&o);
QObject oo;
QObject o21(&oo);
QObject o22(&oo);
QObject o23(&oo);
Q_SET_OBJECT_NAME(o); Q_SET_OBJECT_NAME(o);
Q_SET_OBJECT_NAME(o1); Q_SET_OBJECT_NAME(o1);
@ -530,6 +536,13 @@ void tst_QObject::findChildren()
Q_SET_OBJECT_NAME(t1); Q_SET_OBJECT_NAME(t1);
Q_SET_OBJECT_NAME(t121); Q_SET_OBJECT_NAME(t121);
emptyname.setObjectName(""); emptyname.setObjectName("");
Q_SET_OBJECT_NAME(oo);
const QUtf8StringView utf8_name = u8"utf8 obj";
o21.setObjectName(utf8_name);
const QStringView utf16_name = u"utf16 obj";
o22.setObjectName(utf16_name);
constexpr QLatin1StringView L1_name("L1 obj");
o23.setObjectName(L1_name);
QObject *op = nullptr; QObject *op = nullptr;
@ -560,6 +573,27 @@ void tst_QObject::findChildren()
op = o.findChild<QObject*>("o1"); op = o.findChild<QObject*>("o1");
QCOMPARE(op, &o1); QCOMPARE(op, &o1);
op = oo.findChild<QObject*>(utf8_name);
QCOMPARE(op, &o21);
op = oo.findChild<QObject*>(utf8_name.chopped(1));
QCOMPARE(op, nullptr);
const QUtf8StringView utf8_name_with_trailing_data = u8"utf8 obj_data";
op = oo.findChild<QObject*>(utf8_name_with_trailing_data.chopped(5));
QCOMPARE(op, &o21);
op = oo.findChild<QObject*>(utf16_name);
QCOMPARE(op, &o22);
op = oo.findChild<QObject*>(utf16_name.chopped(1));
QCOMPARE(op, nullptr);
const QStringView utf16_name_with_trailing_data = u"utf16 obj_data";
op = oo.findChild<QObject*>(utf16_name_with_trailing_data.chopped(5));
QCOMPARE(op, &o22);
op = oo.findChild<QObject*>(L1_name);
QCOMPARE(op, &o23);
op = oo.findChild<QObject*>(L1_name.chopped(1));
QCOMPARE(op, nullptr);
op = oo.findChild<QObject*>((L1_name + "_data"_L1).chopped(5));
QCOMPARE(op, &o23);
QList<QObject*> l; QList<QObject*> l;
QList<QTimer*> tl; QList<QTimer*> tl;