From 5be4f95d952135d185f2a5c52b0472f17c0adf48 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 12 Feb 2016 13:05:28 +0100 Subject: Fix QFileSelectorPrivate::addStatics() It must clear the previously cached sharedData->staticSelectors, or else QFileSelectorPrivate::updateSelectors() does nothing and the newly added static selectors end up being ignored. Change-Id: If6997664629199be9f00de64c5dd01de2bf0a044 Reviewed-by: Mitch Curtis --- src/corelib/io/qfileselector.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/corelib') diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp index 7a9a4b581c..4ac12fc9ea 100644 --- a/src/corelib/io/qfileselector.cpp +++ b/src/corelib/io/qfileselector.cpp @@ -396,6 +396,7 @@ void QFileSelectorPrivate::addStatics(const QStringList &statics) { QMutexLocker locker(&sharedDataMutex); sharedData->preloadedStatics << statics; + sharedData->staticSelectors.clear(); } QT_END_NAMESPACE -- cgit v1.2.3 From 94f5ed11a1f82e39e5bc25160deb501efbe67254 Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Thu, 11 Feb 2016 10:01:07 +0300 Subject: QStringListModel: optimize container usage. - don't call QList::removeAt() in loop. Just call erase() with two iterators. - don't re-evaluate QList::count() because of result is already cached. Change-Id: I4b3596df4a388f1d39b523c27decad612044cec6 Reviewed-by: Marc Mutz --- src/corelib/itemmodels/qstringlistmodel.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/itemmodels/qstringlistmodel.cpp b/src/corelib/itemmodels/qstringlistmodel.cpp index 61323ad9c7..1a1b2b9fb6 100644 --- a/src/corelib/itemmodels/qstringlistmodel.cpp +++ b/src/corelib/itemmodels/qstringlistmodel.cpp @@ -237,8 +237,8 @@ bool QStringListModel::removeRows(int row, int count, const QModelIndex &parent) beginRemoveRows(QModelIndex(), row, row + count - 1); - for (int r = 0; r < count; ++r) - lst.removeAt(row); + const auto it = lst.begin() + row; + lst.erase(it, it + count); endRemoveRows(); @@ -274,8 +274,8 @@ void QStringListModel::sort(int, Qt::SortOrder order) std::sort(list.begin(), list.end(), decendingLessThan); lst.clear(); - QVector forwarding(list.count()); - for (int i = 0; i < list.count(); ++i) { + QVector forwarding(lstCount); + for (int i = 0; i < lstCount; ++i) { lst.append(list.at(i).first); forwarding[list.at(i).second] = i; } -- cgit v1.2.3 From 6ffb0bdf60cbd592c37ad8104db288a30596c6bf Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sun, 19 Jul 2015 23:04:01 +0200 Subject: QXmlStream*: make nothrow move assignable and -constructible Unfortunately, we cannot rely on Q_DECL_EQ_DEFAULT, so I needed to code the special member functions by hand. The 'reserved' field is pretty useless, since the existing ctors didn't initialize it, but just in case someone finds a way how to store information in there, deal with the field in the usual way: set to nullptr in the move ctor and swap in the move assignment operator. Also schedule all this for removal again come Qt 6 (then without the reserved field). This amends a83be780aecd78bf8b2b76dab722097f74663d74, which only dealt with QXmlStreamAttribute. Change-Id: I6898e5d0423c9519f7c07d23e2c6d2700508151e Reviewed-by: Lars Knoll --- src/corelib/xml/qxmlstream.h | 70 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'src/corelib') diff --git a/src/corelib/xml/qxmlstream.h b/src/corelib/xml/qxmlstream.h index 765b3eeaca..bf6ddefcdd 100644 --- a/src/corelib/xml/qxmlstream.h +++ b/src/corelib/xml/qxmlstream.h @@ -99,13 +99,16 @@ class QXmlStreamReaderPrivate; class QXmlStreamAttributes; class Q_CORE_EXPORT QXmlStreamAttribute { QXmlStreamStringRef m_name, m_namespaceUri, m_qualifiedName, m_value; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void *reserved; +#endif uint m_isDefault : 1; friend class QXmlStreamReaderPrivate; friend class QXmlStreamAttributes; public: QXmlStreamAttribute(); QXmlStreamAttribute(const QString &qualifiedName, const QString &value); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QXmlStreamAttribute(const QString &namespaceUri, const QString &name, const QString &value); QXmlStreamAttribute(const QXmlStreamAttribute &); #ifdef Q_COMPILER_RVALUE_REFS @@ -132,6 +135,8 @@ public: #endif QXmlStreamAttribute& operator=(const QXmlStreamAttribute &); ~QXmlStreamAttribute(); +#endif // < Qt 6 + inline QStringRef namespaceUri() const { return m_namespaceUri; } inline QStringRef name() const { return m_name; } inline QStringRef qualifiedName() const { return m_qualifiedName; } @@ -185,15 +190,34 @@ public: class Q_CORE_EXPORT QXmlStreamNamespaceDeclaration { QXmlStreamStringRef m_prefix, m_namespaceUri; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void *reserved; +#endif friend class QXmlStreamReaderPrivate; public: QXmlStreamNamespaceDeclaration(); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QXmlStreamNamespaceDeclaration(const QXmlStreamNamespaceDeclaration &); + QXmlStreamNamespaceDeclaration(QXmlStreamNamespaceDeclaration &&other) Q_DECL_NOTHROW // = default + : m_prefix(std::move(other.m_prefix)), + m_namespaceUri(std::move(other.m_namespaceUri)), + reserved(other.reserved) + { + other.reserved = nullptr; + } + QXmlStreamNamespaceDeclaration &operator=(QXmlStreamNamespaceDeclaration &&other) Q_DECL_NOTHROW // = default + { + m_prefix = std::move(other.m_prefix); + m_namespaceUri = std::move(other.m_namespaceUri); + qSwap(reserved, other.reserved); + return *this; + } QXmlStreamNamespaceDeclaration(const QString &prefix, const QString &namespaceUri); ~QXmlStreamNamespaceDeclaration(); QXmlStreamNamespaceDeclaration& operator=(const QXmlStreamNamespaceDeclaration &); +#endif // < Qt 6 + inline QStringRef prefix() const { return m_prefix; } inline QStringRef namespaceUri() const { return m_namespaceUri; } inline bool operator==(const QXmlStreamNamespaceDeclaration &other) const { @@ -208,14 +232,35 @@ typedef QVector QXmlStreamNamespaceDeclarations; class Q_CORE_EXPORT QXmlStreamNotationDeclaration { QXmlStreamStringRef m_name, m_systemId, m_publicId; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void *reserved; +#endif friend class QXmlStreamReaderPrivate; public: QXmlStreamNotationDeclaration(); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) ~QXmlStreamNotationDeclaration(); QXmlStreamNotationDeclaration(const QXmlStreamNotationDeclaration &); + QXmlStreamNotationDeclaration(QXmlStreamNotationDeclaration &&other) Q_DECL_NOTHROW // = default + : m_name(std::move(other.m_name)), + m_systemId(std::move(other.m_systemId)), + m_publicId(std::move(other.m_publicId)), + reserved(other.reserved) + { + other.reserved = nullptr; + } QXmlStreamNotationDeclaration& operator=(const QXmlStreamNotationDeclaration &); + QXmlStreamNotationDeclaration &operator=(QXmlStreamNotationDeclaration &&other) Q_DECL_NOTHROW // = default + { + m_name = std::move(other.m_name); + m_systemId = std::move(other.m_systemId); + m_publicId = std::move(other.m_publicId); + qSwap(reserved, other.reserved); + return *this; + } +#endif // < Qt 6 + inline QStringRef name() const { return m_name; } inline QStringRef systemId() const { return m_systemId; } inline QStringRef publicId() const { return m_publicId; } @@ -232,14 +277,39 @@ typedef QVector QXmlStreamNotationDeclarations; class Q_CORE_EXPORT QXmlStreamEntityDeclaration { QXmlStreamStringRef m_name, m_notationName, m_systemId, m_publicId, m_value; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void *reserved; +#endif friend class QXmlStreamReaderPrivate; public: QXmlStreamEntityDeclaration(); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) ~QXmlStreamEntityDeclaration(); QXmlStreamEntityDeclaration(const QXmlStreamEntityDeclaration &); + QXmlStreamEntityDeclaration(QXmlStreamEntityDeclaration &&other) Q_DECL_NOTHROW // = default + : m_name(std::move(other.m_name)), + m_notationName(std::move(other.m_notationName)), + m_systemId(std::move(other.m_systemId)), + m_publicId(std::move(other.m_publicId)), + m_value(std::move(other.m_value)), + reserved(other.reserved) + { + other.reserved = nullptr; + } QXmlStreamEntityDeclaration& operator=(const QXmlStreamEntityDeclaration &); + QXmlStreamEntityDeclaration &operator=(QXmlStreamEntityDeclaration &&other) Q_DECL_NOTHROW // = default + { + m_name = std::move(other.m_name); + m_notationName = std::move(other.m_notationName); + m_systemId = std::move(other.m_systemId); + m_publicId = std::move(other.m_publicId); + m_value = std::move(other.m_value); + qSwap(reserved, other.reserved); + return *this; + } +#endif // < Qt 6 + inline QStringRef name() const { return m_name; } inline QStringRef notationName() const { return m_notationName; } inline QStringRef systemId() const { return m_systemId; } -- cgit v1.2.3 From c5d49725779292a04fed599eb7f508d334ffc5c3 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Thu, 3 Dec 2015 10:57:55 +0100 Subject: Fix for deferredDelete() bug when calling the glib loop directly This patch makes sure that all events posted using Qt on top of the GLib event loop have the loopLevel counter incremented. This is done since Qt depends on the fact that all deleteLater() calls are issued within the scope of some signal handler (in other words, triggered by the chain sendEvent() -> notifyInternal2()). There is a side effect though: in the conditions affected by this patch, that is deleteLater()s issued within a glib event handler for example, manually calling processEvents() or sendPostedEvents() with or without the QEvent::DeferredDelete flag has the same effect, and deferred deleted events are always processed. While this is not a currently working feature which the patch breaks, this side effect seems to be difficult to avoid without separating sendPostedEvents() and processEvents() into a public and a private method, in order to detect when they are manually called. Such change could perhaps be done for Qt6. An autotest for QTBUG-36434 is also included. Autotesting for QTBUG-32859 seems to be more challenging in this respect, due to its dependency on GLib. Task-number: QTBUG-18434 Task-number: QTBUG-32859 Task-number: QTBUG-36434 Change-Id: Ib89175aa27c9e38bca68ae254d182b2cd21cf7e9 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/kernel/qabstracteventdispatcher.cpp | 2 +- src/corelib/kernel/qcoreapplication.cpp | 46 +++++++++++++++++++------ src/corelib/thread/qthread.cpp | 2 +- src/corelib/thread/qthread_p.h | 11 +++--- 4 files changed, 44 insertions(+), 17 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index 31369f9a09..907b3ccf1f 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -458,7 +458,7 @@ bool QAbstractEventDispatcher::filterNativeEvent(const QByteArray &eventType, vo if (!d->eventFilters.isEmpty()) { // Raise the loopLevel so that deleteLater() calls in or triggered // by event_filter() will be processed from the main event loop. - QScopedLoopLevelCounter loopLevelCounter(d->threadData); + QScopedScopeLevelCounter scopeLevelCounter(d->threadData); for (int i = 0; i < d->eventFilters.size(); ++i) { QAbstractNativeEventFilter *filter = d->eventFilters.at(i); if (!filter) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 60f3dc0db0..42bda25be5 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -980,7 +980,7 @@ bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event) // call overhead. QObjectPrivate *d = receiver->d_func(); QThreadData *threadData = d->threadData; - QScopedLoopLevelCounter loopLevelCounter(threadData); + QScopedScopeLevelCounter scopeLevelCounter(threadData); if (!selfRequired) return doNotify(receiver, event); return self->notify(receiver, event); @@ -1193,6 +1193,9 @@ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags) */ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime) { + // ### Qt 6: consider splitting this method into a public and a private + // one, so that a user-invoked processEvents can be detected + // and handled properly. QThreadData *data = QThreadData::current(); if (!data->hasEventDispatcher()) return; @@ -1396,8 +1399,24 @@ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority) if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) { // remember the current running eventloop for DeferredDelete - // events posted in the receiver's thread - static_cast(event)->level = data->loopLevel; + // events posted in the receiver's thread. + + // Events sent by non-Qt event handlers (such as glib) may not + // have the scopeLevel set correctly. The scope level makes sure that + // code like this: + // foo->deleteLater(); + // qApp->processEvents(); // without passing QEvent::DeferredDelete + // will not cause "foo" to be deleted before returning to the event loop. + + // If the scope level is 0 while loopLevel != 0, we are called from a + // non-conformant code path, and our best guess is that the scope level + // should be 1. (Loop level 0 is special: it means that no event loops + // are running.) + int loopLevel = data->loopLevel; + int scopeLevel = data->scopeLevel; + if (scopeLevel == 0 && loopLevel != 0) + scopeLevel = 1; + static_cast(event)->level = loopLevel + scopeLevel; } // delete the event on exceptions to protect against memory leaks till the event is @@ -1474,6 +1493,9 @@ bool QCoreApplication::compressEvent(QEvent *event, QObject *receiver, QPostEven */ void QCoreApplication::sendPostedEvents(QObject *receiver, int event_type) { + // ### Qt 6: consider splitting this method into a public and a private + // one, so that a user-invoked sendPostedEvents can be detected + // and handled properly. QThreadData *data = QThreadData::current(); QCoreApplicationPrivate::sendPostedEvents(receiver, event_type, data); @@ -1565,15 +1587,19 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type } if (pe.event->type() == QEvent::DeferredDelete) { - // DeferredDelete events are only sent when we are explicitly asked to - // (s.a. QEvent::DeferredDelete), and then only if the event loop that - // posted the event has returned. - int loopLevel = static_cast(pe.event)->loopLevel(); + // DeferredDelete events are sent either + // 1) when the event loop that posted the event has returned; or + // 2) if explicitly requested (with QEvent::DeferredDelete) for + // events posted by the current event loop; or + // 3) if the event was posted before the outermost event loop. + + int eventLevel = static_cast(pe.event)->loopLevel(); + int loopLevel = data->loopLevel + data->scopeLevel; const bool allowDeferredDelete = - (loopLevel > data->loopLevel - || (!loopLevel && data->loopLevel > 0) + (eventLevel > loopLevel + || (!eventLevel && loopLevel > 0) || (event_type == QEvent::DeferredDelete - && loopLevel == data->loopLevel)); + && eventLevel == loopLevel)); if (!allowDeferredDelete) { // cannot send deferred delete if (!event_type && !receiver) { diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index 14209d8d8c..69f8d72b47 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE */ QThreadData::QThreadData(int initialRefCount) - : _ref(initialRefCount), loopLevel(0), thread(0), threadId(0), + : _ref(initialRefCount), loopLevel(0), scopeLevel(0), thread(0), threadId(0), eventDispatcher(0), quitNow(false), canWait(true), isAdopted(false), requiresCoreApplication(true) { diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index 39a41f1ef4..5f7d01f50f 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -280,6 +280,7 @@ private: public: int loopLevel; + int scopeLevel; QStack eventLoops; QPostEventList postEventList; @@ -295,15 +296,15 @@ public: bool requiresCoreApplication; }; -class QScopedLoopLevelCounter +class QScopedScopeLevelCounter { QThreadData *threadData; public: - inline QScopedLoopLevelCounter(QThreadData *threadData) + inline QScopedScopeLevelCounter(QThreadData *threadData) : threadData(threadData) - { ++threadData->loopLevel; } - inline ~QScopedLoopLevelCounter() - { --threadData->loopLevel; } + { ++threadData->scopeLevel; } + inline ~QScopedScopeLevelCounter() + { --threadData->scopeLevel; } }; // thread wrapper for the main() thread -- cgit v1.2.3 From 0df5c366e50b9533fd8ea3f31c4c360ae7f4c5b6 Mon Sep 17 00:00:00 2001 From: Andre Somers Date: Tue, 2 Feb 2016 14:40:29 +0100 Subject: Use QFlags::setFlag where prudent in qtbase QFlags::setFlag is most useful to replace explicit constructs like if (condition) { someFlags |= TheConditionFlag; } else { someFlags &= ~TheConditionFlag; } with someFlags.setFlag(TheConditionFlag, condition); Change-Id: Ie4586681c83e0af812d5bbf14965aad51941a960 Reviewed-by: Marc Mutz --- src/corelib/io/qtextstream.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 9d3689736c..bc4a5fa538 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -3130,10 +3130,7 @@ void QTextStream::setGenerateByteOrderMark(bool generate) { Q_D(QTextStream); if (d->writeBuffer.isEmpty()) { - if (generate) - d->writeConverterState.flags &= ~QTextCodec::IgnoreHeader; - else - d->writeConverterState.flags |= QTextCodec::IgnoreHeader; + d->writeConverterState.flags.setFlag(QTextCodec::IgnoreHeader, !generate); } } -- cgit v1.2.3 From 8ce34c2e8163cff56048acc761d1337889e09c6f Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 2 Nov 2015 22:05:58 +0100 Subject: QRect(F): add transposed() I didn't add a transpose(), because r = r.transposed() is perfectly capable of filling that role, and just as efficient. Existing API mistakes are no excuse to create more of them. [ChangeLog][QtCore][QRect/QRectF] Added transposed(). Change-Id: Ic38721e9028496fc9b50f4d4cef2e7a60532eed8 Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- src/corelib/tools/qrect.cpp | 28 ++++++++++++++++++++++++++++ src/corelib/tools/qrect.h | 9 +++++++++ 2 files changed, 37 insertions(+) (limited to 'src/corelib') diff --git a/src/corelib/tools/qrect.cpp b/src/corelib/tools/qrect.cpp index 6215c534f8..4b6183646b 100644 --- a/src/corelib/tools/qrect.cpp +++ b/src/corelib/tools/qrect.cpp @@ -706,6 +706,20 @@ QRect QRect::normalized() const Q_DECL_NOTHROW current position. */ +/*! + \fn QRect QRect::transposed() const + \since 5.7 + + Returns a copy of the rectangle that has its width and height + exchanged: + + \code + QRect r = {15, 51, 42, 24}; + r = r.transposed(); // r == {15, 51, 24, 42} + \endcode + + \sa QSize::transposed() +*/ /*! \fn void QRect::setRect(int x, int y, int width, int height) @@ -1842,6 +1856,20 @@ QRectF QRectF::normalized() const Q_DECL_NOTHROW current position. */ +/*! + \fn QRectF QRectF::transposed() const + \since 5.7 + + Returns a copy of the rectangle that has its width and height + exchanged: + + \code + QRectF r = {1.5, 5.1, 4.2, 2.4}; + r = r.transposed(); // r == {1.5, 5.1, 2.4, 4.2} + \endcode + + \sa QSizeF::transposed() +*/ /*! \fn void QRectF::setRect(qreal x, qreal y, qreal width, qreal height) diff --git a/src/corelib/tools/qrect.h b/src/corelib/tools/qrect.h index e90bb8a21e..31fdc8ce6b 100644 --- a/src/corelib/tools/qrect.h +++ b/src/corelib/tools/qrect.h @@ -102,6 +102,7 @@ public: Q_DECL_RELAXED_CONSTEXPR inline void translate(const QPoint &p) Q_DECL_NOTHROW; Q_DECL_CONSTEXPR inline QRect translated(int dx, int dy) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; Q_DECL_CONSTEXPR inline QRect translated(const QPoint &p) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; + Q_DECL_CONSTEXPR inline QRect transposed() const Q_DECL_NOTHROW Q_REQUIRED_RESULT; Q_DECL_RELAXED_CONSTEXPR inline void moveTo(int x, int t) Q_DECL_NOTHROW; Q_DECL_RELAXED_CONSTEXPR inline void moveTo(const QPoint &p) Q_DECL_NOTHROW; @@ -284,6 +285,9 @@ Q_DECL_CONSTEXPR inline QRect QRect::translated(int dx, int dy) const Q_DECL_NOT Q_DECL_CONSTEXPR inline QRect QRect::translated(const QPoint &p) const Q_DECL_NOTHROW { return QRect(QPoint(x1 + p.x(), y1 + p.y()), QPoint(x2 + p.x(), y2 + p.y())); } +Q_DECL_CONSTEXPR inline QRect QRect::transposed() const Q_DECL_NOTHROW +{ return QRect(topLeft(), size().transposed()); } + Q_DECL_RELAXED_CONSTEXPR inline void QRect::moveTo(int ax, int ay) Q_DECL_NOTHROW { x2 += ax - x1; @@ -551,6 +555,8 @@ public: Q_DECL_CONSTEXPR inline QRectF translated(qreal dx, qreal dy) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; Q_DECL_CONSTEXPR inline QRectF translated(const QPointF &p) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; + Q_DECL_CONSTEXPR inline QRectF transposed() const Q_DECL_NOTHROW Q_REQUIRED_RESULT; + Q_DECL_RELAXED_CONSTEXPR inline void moveTo(qreal x, qreal y) Q_DECL_NOTHROW; Q_DECL_RELAXED_CONSTEXPR inline void moveTo(const QPointF &p) Q_DECL_NOTHROW; @@ -751,6 +757,9 @@ Q_DECL_CONSTEXPR inline QRectF QRectF::translated(qreal dx, qreal dy) const Q_DE Q_DECL_CONSTEXPR inline QRectF QRectF::translated(const QPointF &p) const Q_DECL_NOTHROW { return QRectF(xp + p.x(), yp + p.y(), w, h); } +Q_DECL_CONSTEXPR inline QRectF QRectF::transposed() const Q_DECL_NOTHROW +{ return QRectF(topLeft(), size().transposed()); } + Q_DECL_RELAXED_CONSTEXPR inline void QRectF::getRect(qreal *ax, qreal *ay, qreal *aaw, qreal *aah) const { *ax = this->xp; -- cgit v1.2.3 From 6139fbeb5f41843e524ec40ce5be57f0df23e922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Sun, 7 Feb 2016 02:49:33 +0000 Subject: Introduce QHash::equal_range() Similar to QMap::equal_range(). Will allow to easily fix inefficient code such as: foreach (auto value, hash.values(key)) { ... } [ChangeLog][QtCore][QHash] Added QHash::equal_range() Change-Id: I6e19e25de632e897ad83d3141d9d07f0313f7200 Reviewed-by: Marc Mutz --- src/corelib/tools/qhash.cpp | 13 +++++++++++++ src/corelib/tools/qhash.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) (limited to 'src/corelib') diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index c1a1b9715f..b49c9d683a 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -1803,6 +1803,19 @@ uint qHash(long double key, uint seed) Q_DECL_NOTHROW returns \c false. */ +/*! \fn QPair QHash::equal_range(const Key &key) + \since 5.7 + + Returns a pair of iterators delimiting the range of values \c{[first, second)}, that + are stored under \a key. If the range is empty then both iterators will be equal to end(). +*/ + +/*! + \fn QPair QHash::equal_range(const Key &key) const + \overload + \since 5.7 +*/ + /*! \typedef QHash::ConstIterator Qt-style synonym for QHash::const_iterator. diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 819631932b..5e3016d313 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -458,6 +458,8 @@ public: inline key_iterator keyBegin() const { return key_iterator(begin()); } inline key_iterator keyEnd() const { return key_iterator(end()); } + QPair equal_range(const Key &key); + QPair equal_range(const Key &key) const Q_DECL_NOTHROW; iterator erase(iterator it) { return erase(const_iterator(it.i)); } iterator erase(const_iterator it); @@ -944,6 +946,39 @@ Q_OUTOFLINE_TEMPLATE bool QHash::operator==(const QHash &other) const return true; } +template +QPair::iterator, typename QHash::iterator> QHash::equal_range(const Key &akey) +{ + detach(); + auto pair = qAsConst(*this).equal_range(akey); + return qMakePair(iterator(pair.first.i), iterator(pair.second.i)); +} + +template +QPair::const_iterator, typename QHash::const_iterator> QHash::equal_range(const Key &akey) const Q_DECL_NOTHROW +{ + uint h; + Node *node = *findNode(akey, &h); + const_iterator firstIt = const_iterator(node); + + if (node != e) { + // equal keys must hash to the same value and so they all + // end up in the same bucket. So we can use node->next, + // which only works within a bucket, instead of (out-of-line) + // QHashData::nextNode() + while (node->next != e && node->next->key == akey) + node = node->next; + + // 'node' may be the last node in the bucket. To produce the end iterator, we'd + // need to enter the next bucket in this case, so we need to use + // QHashData::nextNode() here, which, unlike node->next above, can move between + // buckets. + node = concrete(QHashData::nextNode(reinterpret_cast(node))); + } + + return qMakePair(firstIt, const_iterator(node)); +} + template class QMultiHash : public QHash { -- cgit v1.2.3 From ab8cc8387f1891ccf99721bfe5a6182c507e332f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20K=C3=BCmmel?= Date: Tue, 10 Nov 2015 18:57:40 +0100 Subject: Add qOverload to select overloaded functions [ChangeLog][QtCore][Global] qOverload added to select overloaded functions. Change-Id: I7c9b1b054e6631eca0b5594db59e1202ef552c33 Reviewed-by: Olivier Goffart (Woboq GmbH) --- .../snippets/code/src_corelib_global_qglobal.cpp | 23 +++++++++ src/corelib/global/qglobal.cpp | 43 ++++++++++++++++ src/corelib/global/qglobal.h | 60 ++++++++++++++++++++++ src/corelib/kernel/qobject.cpp | 6 +++ 4 files changed, 132 insertions(+) (limited to 'src/corelib') diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp index ccf8399e0d..ba02f75963 100644 --- a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp @@ -568,6 +568,29 @@ struct A : public B { template<> class QTypeInfo : public QTypeInfoMerger {}; //! [51] +//! [52] + struct Foo { + void overloadedFunction(); + void overloadedFunction(int, QString); + }; + ... qOverload<>(&Foo:overloadedFunction) + ... qOverload(&Foo:overloadedFunction) +//! [52] + +//! [53] + ... QOverload<>::of(&Foo:overloadedFunction) + ... QOverload::of(&Foo:overloadedFunction) +//! [53] + +//! [54] + struct Foo { + void overloadedFunction(int, QString); + void overloadedFunction(int, QString) const; + }; + ... qConstOverload<>(&Foo:overloadedFunction) + ... qNonConstOverload(&Foo:overloadedFunction) +//! [54] + //! [qlikely] // the condition inside the "if" will be successful most of the times for (int i = 1; i <= 365; i++) { diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index a7ed29d859..e4fa0f7391 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -921,6 +921,49 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in \sa qMin(), qMax() */ +/*! \fn auto qOverload(T functionPointer) + \relates + \since 5.7 + + qOverload() returns a pointer to an overloaded function. The template + parameter is the list of the argument types of the function. + \a functionPointer is the pointer to the (member) function: + + \snippet code/src_corelib_global_qglobal.cpp 52 + + If a member function is also const-overladed \l qConstOverload and + \l qNonConstOverload needs to be used. + + qOverload() needs C++14 enabled. In C++11 only code the helper + classes QOverload, QConstOverload, and QNonConstOverload could be used directly: + + \snippet code/src_corelib_global_qglobal.cpp 53 + + \sa qConstOverload(), qNonConstOverload() +*/ + +/*! \fn auto qConstOverload(T memberFunctionPointer) + \relates + \since 5.7 + + qConstOverload() returns a pointer to an constant member function: + + \snippet code/src_corelib_global_qglobal.cpp 54 + + \sa qOverload, qNonConstOverload +*/ + +/*! \fn auto qNonConstOverload(T memberFunctionPointer) + \relates + \since 5.7 + + qNonConstOverload() eturns a pointer to an non constant member function: + + \snippet code/src_corelib_global_qglobal.cpp 54 + + \sa qOverload, qNonConstOverload +*/ + /*! \macro QT_VERSION_CHECK \relates diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 69840996dc..d607b04192 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1018,6 +1018,66 @@ Q_CORE_EXPORT QString qtTrId(const char *id, int n = -1); { return T::dynamic_cast_will_always_fail_because_rtti_is_disabled; } #endif + +#ifdef Q_QDOC + +// Just for documentation generation +auto qOverload(T functionPointer); +auto qConstOverload(T memberFunctionPointer); +auto qNonConstOverload(T memberFunctionPointer); + +#elif defined(Q_COMPILER_VARIADIC_TEMPLATES) + +template +struct QNonConstOverload +{ + template + Q_DECL_CONSTEXPR auto operator()(R (T::*ptr)(Args...)) const Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } + + template + static Q_DECL_CONSTEXPR auto of(R (T::*ptr)(Args...)) Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } +}; + +template +struct QConstOverload +{ + template + Q_DECL_CONSTEXPR auto operator()(R (T::*ptr)(Args...) const) const Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } + + template + static Q_DECL_CONSTEXPR auto of(R (T::*ptr)(Args...) const) Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } +}; + +template +struct QOverload : QConstOverload, QNonConstOverload +{ + using QConstOverload::of; + using QConstOverload::operator(); + using QNonConstOverload::of; + using QNonConstOverload::operator(); + + template + Q_DECL_CONSTEXPR auto operator()(R (*ptr)(Args...)) const Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } + + template + static Q_DECL_CONSTEXPR auto of(R (*ptr)(Args...)) Q_DECL_NOTHROW -> decltype(ptr) + { return ptr; } +}; + +#if defined(__cpp_variable_templates) && __cpp_variable_templates >= 201304 // C++14 +template Q_CONSTEXPR QOverload qOverload Q_DECL_UNUSED = {}; +template Q_CONSTEXPR QConstOverload qConstOverload Q_DECL_UNUSED = {}; +template Q_CONSTEXPR QNonConstOverload qNonConstOverload Q_DECL_UNUSED = {}; +#endif + +#endif + + class QByteArray; Q_CORE_EXPORT QByteArray qgetenv(const char *varName); Q_CORE_EXPORT bool qputenv(const char *varName, const QByteArray& value); diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index dea8c200ef..6702f78a04 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -4538,6 +4538,8 @@ void qDeleteInEventHandler(QObject *o) make sure to declare the argument type with Q_DECLARE_METATYPE + Overloaded functions can be resolved with help of \l qOverload. + \note The number of arguments in the signal or slot are limited to 6 if the compiler does not support C++11 variadic templates. */ @@ -4573,6 +4575,8 @@ void qDeleteInEventHandler(QObject *o) However, you should take care that any objects used within the functor are still alive when the signal is emitted. + Overloaded functions can be resolved with help of \l qOverload. + \note If the compiler does not support C++11 variadic templates, the number of arguments in the signal or slot are limited to 6, and the functor object must not have an overloaded or templated operator(). @@ -4612,6 +4616,8 @@ void qDeleteInEventHandler(QObject *o) However, you should take care that any objects used within the functor are still alive when the signal is emitted. + Overloaded functions can be resolved with help of \l qOverload. + \note If the compiler does not support C++11 variadic templates, the number of arguments in the signal or slot are limited to 6, and the functor object must not have an overloaded or templated operator(). -- cgit v1.2.3 From e1538b39bb7f18b55e50f36a95bf0232cc43b328 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Sun, 14 Feb 2016 15:35:27 +0100 Subject: Share code between const and non-const QMetaObject::cast variants. Change-Id: I7aad8e5060bb17ebc04fdb137dad3b6d167895a8 Reviewed-by: Marc Mutz Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/kernel/qmetaobject.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index c5a6875a77..1c426225a5 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -333,14 +333,8 @@ const char *QMetaObject::className() const */ QObject *QMetaObject::cast(QObject *obj) const { - if (obj) { - const QMetaObject *m = obj->metaObject(); - do { - if (m == this) - return obj; - } while ((m = m->d.superdata)); - } - return 0; + // ### Qt 6: inline + return const_cast(cast(const_cast(obj))); } /*! -- cgit v1.2.3 From bd352604153543d8527929c7671fcfd2a22acc4a Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Sun, 14 Feb 2016 16:24:13 +0100 Subject: Microoptimize QObject::activate. This patch removes temporary variables that are not used in all cases. This reduces the instruction count per iteration for the corresponding benchmark by 1 or 2. Before: ********* Start testing of QObjectBenchmark ********* Config: Using QtTest library 5.7.0, Qt 5.7.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 5.3.0) PASS : QObjectBenchmark::initTestCase() PASS : QObjectBenchmark::signal_slot_benchmark(simple function) RESULT : QObjectBenchmark::signal_slot_benchmark():"simple function": 21.0065466 instructions per iteration (total: 210,065,466, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(single signal/slot) RESULT : QObjectBenchmark::signal_slot_benchmark():"single signal/slot": 405.0829559 instructions per iteration (total: 4,050,829,559, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(multi signal/slot) RESULT : QObjectBenchmark::signal_slot_benchmark():"multi signal/slot": 405.0812465 instructions per iteration (total: 4,050,812,465, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(unconnected signal) RESULT : QObjectBenchmark::signal_slot_benchmark():"unconnected signal": 104.0147348 instructions per iteration (total: 1,040,147,349, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(single signal/ptr) RESULT : QObjectBenchmark::signal_slot_benchmark():"single signal/ptr": 369.1021099 instructions per iteration (total: 3,691,021,100, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(functor) RESULT : QObjectBenchmark::signal_slot_benchmark():"functor": 370.0982862 instructions per iteration (total: 3,700,982,862, iterations: 10000000) PASS : QObjectBenchmark::cleanupTestCase() Totals: 8 passed, 0 failed, 0 skipped, 0 blacklisted, 6036ms ********* Finished testing of QObjectBenchmark ********* After: ********* Start testing of QObjectBenchmark ********* Config: Using QtTest library 5.7.0, Qt 5.7.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 5.3.0) PASS : QObjectBenchmark::initTestCase() PASS : QObjectBenchmark::signal_slot_benchmark(simple function) RESULT : QObjectBenchmark::signal_slot_benchmark():"simple function": 21.0061664 instructions per iteration (total: 210,061,664, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(single signal/slot) RESULT : QObjectBenchmark::signal_slot_benchmark():"single signal/slot": 403.0829161 instructions per iteration (total: 4,030,829,162, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(multi signal/slot) RESULT : QObjectBenchmark::signal_slot_benchmark():"multi signal/slot": 403.0836305 instructions per iteration (total: 4,030,836,305, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(unconnected signal) RESULT : QObjectBenchmark::signal_slot_benchmark():"unconnected signal": 104.0150038 instructions per iteration (total: 1,040,150,039, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(single signal/ptr) RESULT : QObjectBenchmark::signal_slot_benchmark():"single signal/ptr": 368.0981987 instructions per iteration (total: 3,680,981,988, iterations: 10000000) PASS : QObjectBenchmark::signal_slot_benchmark(functor) RESULT : QObjectBenchmark::signal_slot_benchmark():"functor": 369.1179429 instructions per iteration (total: 3,691,179,429, iterations: 10000000) PASS : QObjectBenchmark::cleanupTestCase() Totals: 8 passed, 0 failed, 0 skipped, 0 blacklisted, 5975ms ********* Finished testing of QObjectBenchmark ********* Change-Id: Iba3bffbca5b58109816c8b1a7dea0796b18c8785 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/kernel/qobject.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 6702f78a04..e3e536d7e1 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -3713,8 +3713,6 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i if (receiverInSameThread) { sw.switchSender(receiver, sender, signal_index); } - const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction; - const int method_relative = c->method_relative; if (c->isSlotObject) { c->slotObj->ref(); QScopedPointer obj(c->slotObj); @@ -3727,10 +3725,12 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i obj.reset(); locker.relock(); - } else if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { + } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { //we compare the vtable to make sure we are not in the destructor of the object. - locker.unlock(); const int methodIndex = c->method(); + const int method_relative = c->method_relative; + const auto callFunction = c->callFunction; + locker.unlock(); if (qt_signal_spy_callback_set.slot_begin_callback != 0) qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv ? argv : empty_argv); @@ -3740,7 +3740,7 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex); locker.relock(); } else { - const int method = method_relative + c->method_offset; + const int method = c->method_relative + c->method_offset; locker.unlock(); if (qt_signal_spy_callback_set.slot_begin_callback != 0) { -- cgit v1.2.3