summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/animation/qpropertyanimation.cpp4
-rw-r--r--src/corelib/doc/snippets/code/doc_src_containers.cpp59
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp94
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_text_qstring.cpp3
-rw-r--r--src/corelib/doc/snippets/qstringlist/main.cpp18
-rw-r--r--src/corelib/doc/src/animation.qdoc338
-rw-r--r--src/corelib/doc/src/containers.qdoc31
-rw-r--r--src/corelib/global/qcompilerdetection.h25
-rw-r--r--src/corelib/global/qflags.h5
-rw-r--r--src/corelib/global/qlogging.cpp16
-rw-r--r--src/corelib/global/qnumeric.cpp31
-rw-r--r--src/corelib/global/qnumeric_p.h35
-rw-r--r--src/corelib/io/qdir.cpp3
-rw-r--r--src/corelib/io/qfilesystemwatcher_win_p.h5
-rw-r--r--src/corelib/io/qlockfile.h6
-rw-r--r--src/corelib/kernel/qcore_mac_p.h12
-rw-r--r--src/corelib/kernel/qdeadlinetimer.h8
-rw-r--r--src/corelib/kernel/qmetatype.cpp9
-rw-r--r--src/corelib/kernel/qmetatype.h5
-rw-r--r--src/corelib/kernel/qobject.h6
-rw-r--r--src/corelib/kernel/qsharedmemory.cpp6
-rw-r--r--src/corelib/kernel/qtimer.h8
-rw-r--r--src/corelib/kernel/qvariant.cpp21
-rw-r--r--src/corelib/platform/android/qandroidextras.cpp6
-rw-r--r--src/corelib/text/qbytearray.cpp337
-rw-r--r--src/corelib/text/qlocale_win.cpp10
-rw-r--r--src/corelib/text/qstring.cpp19
-rw-r--r--src/corelib/text/qstringconverter.cpp2
-rw-r--r--src/corelib/text/qstringlist.cpp20
-rw-r--r--src/corelib/thread/qatomic.cpp82
-rw-r--r--src/corelib/thread/qatomic.h5
-rw-r--r--src/corelib/thread/qfutureinterface.cpp47
-rw-r--r--src/corelib/thread/qfutureinterface_p.h5
-rw-r--r--src/corelib/thread/qmutex.h8
-rw-r--r--src/corelib/thread/qpromise.h1
-rw-r--r--src/corelib/time/qdatetime.h17
-rw-r--r--src/corelib/tools/qlist.qdoc16
-rw-r--r--src/corelib/tools/qmap.h26
-rw-r--r--src/corelib/tools/qmap.qdoc9
-rw-r--r--src/corelib/tools/qtaggedpointer.h23
40 files changed, 894 insertions, 487 deletions
diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp
index fe7ab0c070..94bf442a74 100644
--- a/src/corelib/animation/qpropertyanimation.cpp
+++ b/src/corelib/animation/qpropertyanimation.cpp
@@ -58,6 +58,10 @@
\snippet code/src_corelib_animation_qpropertyanimation.cpp 0
+ \note You can also control an animation's lifespan by choosing a
+ \l{QAbstractAnimation::DeletionPolicy}{delete policy} while starting the
+ animation.
+
The property name and the QObject instance of which property
should be animated are passed to the constructor. You can then
specify the start and end value of the property. The procedure is
diff --git a/src/corelib/doc/snippets/code/doc_src_containers.cpp b/src/corelib/doc/snippets/code/doc_src_containers.cpp
index a191c9af5c..15380da378 100644
--- a/src/corelib/doc/snippets/code/doc_src_containers.cpp
+++ b/src/corelib/doc/snippets/code/doc_src_containers.cpp
@@ -63,10 +63,30 @@ private:
};
//! [0]
+//! [range_for]
+QList<QString> list = {"A", "B", "C", "D"};
+for (const auto &item : list) {
+ ...
+}
+//! [range_for]
+
+//! [range_for_as_const]
+QList<QString> list = {"A", "B", "C", "D"};
+for (const auto &item : std::as_const(list)) {
+ ...
+}
+//! [range_for_as_const]
+
+//! [index]
+QList<QString> list = {"A", "B", "C", "D"};
+for (qsizetype i = 0; i < list.size(); ++i) {
+ const auto &item = list.at(i);
+ ...
+}
+//! [index]
//! [1]
-QList<QString> list;
-list << "A" << "B" << "C" << "D";
+QList<QString> list = {"A", "B", "C", "D"};
QListIterator<QString> i(list);
while (i.hasNext())
@@ -118,11 +138,12 @@ while (i.hasNext())
//! [7]
-QMap<QString, QString> map;
-map.insert("Paris", "France");
-map.insert("Guatemala City", "Guatemala");
-map.insert("Mexico City", "Mexico");
-map.insert("Moscow", "Russia");
+QMap<QString, QString> map = {
+ {"Paris", "France"},
+ {"Guatemala City", "Guatemala"},
+ {"Mexico City", "Mexico"},
+ {"Moscow", "Russia"}
+};
...
QMutableMapIterator<QString, QString> i(map);
@@ -153,28 +174,23 @@ while (i.findNext(widget))
//! [10]
-QList<QString> list;
-list << "A" << "B" << "C" << "D";
+QList<QString> list = {"A", "B", "C", "D"};
-QList<QString>::iterator i;
-for (i = list.begin(); i != list.end(); ++i)
+for (auto i = list.begin(), end = list.end(); i != end; ++i)
*i = (*i).toLower();
//! [10]
//! [11]
-QList<QString> list;
-list << "A" << "B" << "C" << "D";
+QList<QString> list = {"A", "B", "C", "D"};
-QList<QString>::reverse_iterator i;
-for (i = list.rbegin(); i != list.rend(); ++i)
+for (auto i = list.rbegin(), rend = list.rend(); i != rend; ++i)
*i = i->toLower();
//! [11]
//! [12]
-QList<QString>::const_iterator i;
-for (i = list.constBegin(); i != list.constEnd(); ++i)
+for (auto i = list.cbegin(), end = list.cend(); i != end; ++i)
qDebug() << *i;
//! [12]
@@ -182,8 +198,7 @@ for (i = list.constBegin(); i != list.constEnd(); ++i)
//! [13]
QMap<int, int> map;
...
-QMap<int, int>::const_iterator i;
-for (i = map.constBegin(); i != map.constEnd(); ++i)
+for (auto i = map.cbegin(), end = map.cend(); i != end; ++i)
qDebug() << i.key() << ':' << i.value();
//! [13]
@@ -191,13 +206,11 @@ for (i = map.constBegin(); i != map.constEnd(); ++i)
//! [14]
// RIGHT
const QList<int> sizes = splitter->sizes();
-QList<int>::const_iterator i;
-for (i = sizes.begin(); i != sizes.end(); ++i)
+for (auto i = sizes.begin(), end = sizes.end(); i != end; ++i)
...
// WRONG
-QList<int>::const_iterator i;
-for (i = splitter->sizes().begin();
+for (auto i = splitter->sizes().begin();
i != splitter->sizes().end(); ++i)
...
//! [14]
diff --git a/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp b/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp
index 7bd8121b90..e507c78a3d 100644
--- a/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp
@@ -50,10 +50,94 @@
//! [0]
- QPropertyAnimation *animation = new QPropertyAnimation(myWidget, "geometry");
- animation->setDuration(10000);
- animation->setStartValue(QRect(0, 0, 100, 30));
- animation->setEndValue(QRect(250, 250, 100, 30));
+#include <QApplication>
+#include <QPushButton>
+#include <QPropertyAnimation>
+//! [1]
+class MyButtonWidget : public QWidget
+{
+public:
+ MyButtonWidget(QWidget *parent = nullptr);
+};
- animation->start();
+MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent)
+{
+ QPushButton *button = new QPushButton(tr("Animated Button"), this);
+ QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this);
+ anim->setDuration(10000);
+ anim->setStartValue(QPoint(0, 0));
+ anim->setEndValue(QPoint(100, 250));
+ anim->start();
+}
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MyButtonWidget buttonAnimWidget;
+ buttonAnimWidget.resize(QSize(800, 600));
+ buttonAnimWidget.show();
+ return a.exec();
+}
+//! [1]
//! [0]
+
+
+//! [easing-curve]
+MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent)
+{
+ QPushButton *button = new QPushButton(tr("Animated Button"), this);
+ QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this);
+ anim->setDuration(10000);
+ anim->setStartValue(QPoint(0, 0));
+ anim->setEndValue(QPoint(100, 250));
+ anim->setEasingCurve(QEasingCurve::OutBounce);
+ anim->start();
+}
+//! [easing-curve]
+
+
+//! [animation-group1]
+MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent)
+{
+ QPushButton *bonnie = new QPushButton(tr("Bonnie"), this);
+ QPushButton *clyde = new QPushButton(tr("Clyde"), this);
+
+ QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this);
+ anim1->setDuration(3000);
+ anim1->setStartValue(QPoint(0, 0));
+ anim1->setEndValue(QPoint(100, 250));
+
+ QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this);
+ anim2->setDuration(3000);
+ anim2->setStartValue(QPoint(100, 250));
+ anim2->setEndValue(QPoint(500, 500));
+
+ QParallelAnimationGroup *parallelAnim = new QParallelAnimationGroup;
+ parallelAnim->addAnimation(anim1);
+ parallelAnim->addAnimation(anim2);
+ parallelAnim->start();
+}
+//! [animation-group1]
+
+//! [animation-group2]
+MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent)
+{
+ QPushButton *bonnie = new QPushButton(tr("Bonnie"), this);
+ QPushButton *clyde = new QPushButton(tr("Clyde"), this);
+
+ QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this);
+ anim1->setDuration(3000);
+ anim1->setStartValue(QPoint(0, 0));
+ anim1->setEndValue(QPoint(100, 250));
+
+ QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this);
+ anim2->setDuration(3000);
+ anim2->setStartValue(QPoint(0, 0));
+ anim2->setEndValue(QPoint(200, 250));
+
+ QSequentialAnimationGroup *sequenceAnim = new QSequentialAnimationGroup;
+ sequenceAnim->addAnimation(anim1);
+ sequenceAnim->addAnimation(anim2);
+ sequenceAnim->start();
+}
+//! [animation-group2]
diff --git a/src/corelib/doc/snippets/code/src_corelib_text_qstring.cpp b/src/corelib/doc/snippets/code/src_corelib_text_qstring.cpp
index fe44bee4a8..4f7831d642 100644
--- a/src/corelib/doc/snippets/code/src_corelib_text_qstring.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_text_qstring.cpp
@@ -75,6 +75,9 @@ if (str == QString("auto") || str == QString("extern")
}
//! [4]
+//! [4bis]
+str.append("Hello ").append("World");
+//! [4bis]
//! [5]
if (str == QLatin1String("auto")
diff --git a/src/corelib/doc/snippets/qstringlist/main.cpp b/src/corelib/doc/snippets/qstringlist/main.cpp
index fceadc4e99..5ee0624487 100644
--- a/src/corelib/doc/snippets/qstringlist/main.cpp
+++ b/src/corelib/doc/snippets/qstringlist/main.cpp
@@ -69,24 +69,6 @@ Widget::Widget(QWidget *parent)
fonts << "Courier" << "Verdana";
//! [0b]
-//! [1]
- for (int i = 0; i < fonts.size(); ++i)
- cout << fonts.at(i).toLocal8Bit().constData() << Qt::endl;
-//! [1]
-
-//! [2]
- QStringListIterator javaStyleIterator(fonts);
- while (javaStyleIterator.hasNext())
- cout << javaStyleIterator.next().toLocal8Bit().constData() << Qt::endl;
-//! [2]
-
-//! [3]
- QStringList::const_iterator constIterator;
- for (constIterator = fonts.constBegin(); constIterator != fonts.constEnd();
- ++constIterator)
- cout << (*constIterator).toLocal8Bit().constData() << Qt::endl;
-//! [3]
-
//! [4]
QString str = fonts.join(", ");
// str == "Arial, Helvetica, Times, Courier"
diff --git a/src/corelib/doc/src/animation.qdoc b/src/corelib/doc/src/animation.qdoc
index d67ac2e505..ceef6efc45 100644
--- a/src/corelib/doc/src/animation.qdoc
+++ b/src/corelib/doc/src/animation.qdoc
@@ -46,153 +46,134 @@
\keyword Animation
- The animation framework aims to provide an easy way for creating animated
- and smooth GUIs. By animating Qt properties, the framework provides great
- freedom for animating widgets and other \l{QObject}s. The framework can
- also be used with the Graphics View framework. Many of the concepts
- available in the animation framework are also available in \l{Qt Quick},
- where it offers a declarative way of defining animations. Much of the
- knowledge acquired about the animation framework can be applied to
- \l{Qt Quick}.
-
- In this overview, we explain the basics of its architecture. We
- also show examples of the most common techniques that the
- framework allows for animating \l{QObject}s and graphics items.
+ The animation framework provides an easy way to animate your GUI elements.
+ It enables you to animate a Qt property value of a widget or QObject.
+ Most of the features offered by the framework are also available in
+ \l{Qt Quick}, where it's possible to define animations in a declarative way.
+
+ This overview explains the framework's architecture, with examples that
+ demonstrate the common techniques used for animating QObject and
+ GUI elements.
\tableofcontents
- \section1 The Animation Architecture
+ \section1 The Animation architecture
- We will in this section take a high-level look at the animation
- framework's architecture and how it is used to animate Qt
- properties. The following diagram shows the most important classes
- in the animation framework.
+ The following diagram shows the most important classes provided by the
+ framework:
\image animations-architecture.png
- The animation framework foundation consists of the base class
- QAbstractAnimation, and its two subclasses QVariantAnimation and
- QAnimationGroup. QAbstractAnimation is the ancestor of all
- animations. It represents basic properties that are common for all
- animations in the framework; notably, the ability to start, stop,
- and pause an animation. It is also receives the time change
- notifications.
-
- The animation framework further provides the QPropertyAnimation
- class, which inherits QVariantAnimation and performs animation of
- a Qt property, which is part of Qt's \l{Meta-Object
- System}{meta-object system}. The class performs an interpolation
- over the property using an easing curve. So when you want to
- animate a value, you can declare it as a property and make your
- class a QObject. Note that this gives us great freedom in
- animating already existing widgets and other \l{QObject}s.
+ It includes the QAbstractAnimation class, which provides the
+ necessary foundation for animations. This class defines the
+ generic properties for all animations supported by the framework.
+ For example, the ability to start, stop, and pause an animation. The
+ class also receives the time change notifications.
+
+ The framework further provides the QVariantAnimation and
+ QAnimationGroup classes, which build on their base case, QAbstractAnimation.
+ Next in the hierarchy is QPropertyAnimation, which is derived from
+ QVariantAnmiation, and it lets you animate a Qt property of a widget or
+ QObject. The class performs interpolation on the property value using an
+ easing curve. With these in place, you just need a QObject class with a
+ Qt property value that you can animate.
+
+ \note It is required that the target object you are animating is a QObject
+ or its subclass. This is necessary as the animation framework depends on the
+ \l{Meta-Object System}{meta-object system} for all the information about the
+ object it is animating.
Complex animations can be constructed by building a tree structure
- of \l{QAbstractAnimation}s. The tree is built by using
- \l{QAnimationGroup}s, which function as containers for other
- animations. Note also that the groups are subclasses of
- QAbstractAnimation, so groups can themselves contain other groups.
+ of \l{QAbstractAnimation}s, where the tree is a QAnimationGroup that
+ contains other animations. These animation groups can also contain
+ subgroups representing different groups or animations, such as
+ QParallelAnimationGroup and QSequentialAnimationGroup.
- Behind the scenes, the animations are controlled by a global
- timer, which sends \l{QAbstractAnimation::updateCurrentTime()}{updates} to
- all animations that are playing.
+ Behind the scenes, all animations are controlled by a global
+ timer, which sends \l{QAbstractAnimation::updateCurrentTime()}{updates} about
+ all animations that are running.
- For detailed descriptions of the classes' function and roles in
- the framework, please look up their class descriptions.
+ For detailed information of these individual classes' and their roles in
+ the framework, refer to their documentation.
- \section1 Classes in the Animation Framework
+ \section1 Classes offered by the framework
- These classes provide a framework for creating both simple and complex
- animations.
+ These classes provide the necessary infrastructure to create both simple and
+ complex animations.
\annotatedlist animation
- \section1 Animating Qt Properties
+ \section1 Animating Qt properties
- As mentioned in the previous section, the QPropertyAnimation class can
- interpolate over Qt properties. It is often this class that should be used
- for animation of values; in fact, its superclass, QVariantAnimation, has an
- empty implementation of \l{QVariantAnimation::}{updateCurrentValue()}, and
- does not change any value unless we change it ourselves on the
+ As the QPropertyAnimation class can interpolate on Qt properties, it is
+ used often. In fact, its superclass---QVariantAnimation---provides an
+ abstract implementation of \l{QVariantAnimation::}{updateCurrentValue()},
+ which does not change any value unless you change it on the
\l{QVariantAnimation::valueChanged()}{valueChanged signal}.
- A major reason we chose to animate Qt properties is that it
- presents us with freedom to animate already existing classes in
- the Qt API. Notably, the QWidget class (which we can also embed in
- a QGraphicsView) has properties for its bounds, colors, etc.
- Let's look at a small example:
-
- \code
- QPushButton button("Animated Button");
- button.show();
+ The framework lets you animate the Qt properties of the existing
+ classes in Qt. For example, the QWidget class---can be embedded in
+ a QGraphicsView---has properties for its bounds, colors, and so on.
+ The following example demonstrates how you can animate a QPushButton
+ widget:
- QPropertyAnimation animation(&button, "geometry");
- animation.setDuration(10000);
- animation.setStartValue(QRect(0, 0, 100, 30));
- animation.setEndValue(QRect(250, 250, 100, 30));
+ \snippet code/src_corelib_animation_qpropertyanimation.cpp 0
- animation.start();
- \endcode
+ The example animates the \c pos Qt property of a QPushButton, to move
+ it from the top--left corner of the screen to the end position (250, 250),
+ in 10 seconds (10000 milliseconds).
- This code will move \c button from the top left corner of the
- screen to the position (250, 250) in 10 seconds (10000 milliseconds).
-
- The example above will do a linear interpolation between the
- start and end value. It is also possible to set values
- situated between the start and end value. The interpolation
- will then go by these points.
+ It uses the linear interpolation method to control the speed of
+ animation between the start and end values. Try adding another value
+ in--between the start and end value to see how they are interpolated.
+ This time use the QPropertyAnimation::setKeyValueAt function to add
+ these values:
\code
- QPushButton button("Animated Button");
- button.show();
-
- QPropertyAnimation animation(&button, "geometry");
- animation.setDuration(10000);
-
- animation.setKeyValueAt(0, QRect(0, 0, 100, 30));
- animation.setKeyValueAt(0.8, QRect(250, 250, 100, 30));
- animation.setKeyValueAt(1, QRect(0, 0, 100, 30));
-
- animation.start();
+ ...
+ anim->setDuration(10000);
+ anim->setKeyValueAt(0, QPoint(0, 0));
+ anim->setKeyValueAt(0.8, QPoint(250, 250));
+ anim->setKeyValueAt(1, QPoint(0, 0));
+ ...
\endcode
- In this example, the animation will take the button to (250, 250)
- in 8 seconds, and then move it back to its original position in
- the remaining 2 seconds. The movement will be linearly
- interpolated between these points.
+ In this example, the animation moves the button to
+ (250, 250) in 8 seconds, and moves it back to its original position in
+ the remaining 2 seconds. The button's movement is linear-interpolated
+ between these points.
+
+ You can also animate a QObject's value that is not declared as a Qt
+ property, if the value has a setter method. In such cases, derive
+ a new class from the class that contains the value, and add a Qt property
+ for that value with the setter.
- You also have the possibility to animate values of a QObject
- that is not declared as a Qt property. The only requirement is
- that this value has a setter. You can then subclass the class
- containing the value and declare a property that uses this setter.
- Note that each Qt property requires a getter, so you will need to
- provide a getter yourself if this is not defined.
+ \note Each Qt property requires a getter also, so you should provide a
+ getter if that is not defined.
\code
class MyGraphicsRectItem : public QObject, public QGraphicsRectItem
{
Q_OBJECT
- Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry)
+ Q_PROPERTY(QPointF pos READ pos WRITE setPos)
};
\endcode
- In the above code example, we subclass QGraphicsRectItem and
- define a geometry property. We can now animate the widgets
- geometry even if QGraphicsRectItem does not provide the geometry
- property.
+ In this example, the \c MyGraphicsRectItem derives from
+ QGraphicsRectItem and QObject, and defines the \c pos property. You can
+ animate the item's \c pos even if QGraphicsRectItem does not provide
+ the \c pos property.
- For a general introduction to the Qt property system, see its
- \l{Qt's Property System}{overview}.
+ For a general introduction to the Qt property system, refer to
+ \l{Qt's Property System}.
\section1 Animations and the Graphics View Framework
- When you want to animate \l{QGraphicsItem}s, you also use
- QPropertyAnimation. However, QGraphicsItem does not inherit QObject.
- A good solution is to subclass the graphics item you wish to animate.
- This class will then also inherit QObject.
- This way, QPropertyAnimation can be used for \l{QGraphicsItem}s.
- The example below shows how this is done. Another possibility is
- to inherit QGraphicsWidget, which already is a QObject.
+ QPropertyAnimation can also be used to animate a QGraphicsItem, which does
+ not inherit QObject. In such cases, you derive a class from the graphics
+ item that you want to animate. This derived class should also inherit form
+ QObject to enable using QPropertyAnimation on a QGraphicsItem. The
+ following example shows how this is done:
\code
class Pixmap : public QObject, public QGraphicsPixmapItem
@@ -200,121 +181,78 @@
Q_OBJECT
Q_PROPERTY(QPointF pos READ pos WRITE setPos)
...
+ }
\endcode
- As described in the previous section, we need to define
- properties that we wish to animate.
+ \note You can also derive from QGraphicsWidget, which already is a
+ QObject.
- Note that QObject must be the first class inherited as the
- meta-object system demands this.
+ As described in the previous section, you need to define
+ properties that you want to animate. The derived class must inherit
+ from QObject first as the meta-object system requires it.
- \section1 Easing Curves
+ \section1 Easing curves
- As mentioned, QPropertyAnimation performs an interpolation between
- the start and end property value. In addition to adding more key
- values to the animation, you can also use an easing curve. Easing
- curves describe a function that controls how the speed of the
- interpolation between 0 and 1 should be, and are useful if you
- want to control the speed of an animation without changing the
- path of the interpolation.
+ A QPropertyAnimation performs linear interpolation
+ between the start and end property values. In addition to adding more key
+ values to the animation, you can also choose an easing curve to control the
+ speed of interpolation between 0 and 1, without changing the
+ path.
- \code
- QPushButton button("Animated Button");
- button.show();
- QPropertyAnimation animation(&button, "geometry");
- animation.setDuration(3000);
- animation.setStartValue(QRect(0, 0, 100, 30));
- animation.setEndValue(QRect(250, 250, 100, 30));
-
- animation.setEasingCurve(QEasingCurve::OutBounce);
-
- animation.start();
- \endcode
+ \snippet code/src_corelib_animation_qpropertyanimation.cpp easing-curve
- Here the animation will follow a curve that makes it bounce like a
- ball as if it was dropped from the start to the end position.
- QEasingCurve has a large collection of curves for you to choose
- from. These are defined by the QEasingCurve::Type enum. If you are
- in need of another curve, you can also implement one yourself, and
+ In this example, the animation follows a curve that makes the
+ \c button bounce like a ball. QEasingCurve offers a large collection of curves
+ to choose from the QEasingCurve::Type enum. If you want
+ to use another curve that is not available, implement one yourself and
register it with QEasingCurve.
- \omit Drop this for the first Lab release
- (Example of custom easing curve (without the actual impl of
- the function I expect)
- \endomit
+ \section1 Grouping animations
- \section1 Putting Animations Together
-
- An application will often contain more than one animation. For
- instance, you might want to move more than one graphics item
+ An application often contains more than one animation. For
+ example, it wants to move more than one graphics item
simultaneously or move them in sequence after each other.
- The subclasses of QAnimationGroup (QSequentialAnimationGroup and
- QParallelAnimationGroup) are containers for other animations so
+ The subclasses of QAnimationGroup---QSequentialAnimationGroup and
+ QParallelAnimationGroup---are containers for other animations so
that these animations can be animated either in sequence or
- parallel. The QAnimationGroup is an example of an animation that
- does not animate properties, but it gets notified of time changes
- periodically. This enables it to forward those time changes to its
- contained animations, and thereby controlling when its animations
- are played.
-
- Let's look at code examples that use both
- QSequentialAnimationGroup and QParallelAnimationGroup, starting
- off with the latter.
-
- \code
- QPushButton *bonnie = new QPushButton("Bonnie");
- bonnie->show();
+ parallel. The QAnimationGroup does not animate properties, but it
+ gets notified of time changes periodically. This enables it to
+ forward those time changes to the animation groups, which control when
+ their animations are played.
- QPushButton *clyde = new QPushButton("Clyde");
- clyde->show();
+ The two following examples demonstrate the use of both
+ QSequentialAnimationGroup and QParallelAnimationGroup:
- QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry");
- // Set up anim1
-
- QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry");
- // Set up anim2
-
- QParallelAnimationGroup *group = new QParallelAnimationGroup;
- group->addAnimation(anim1);
- group->addAnimation(anim2);
-
- group->start();
- \endcode
+ \snippet code/src_corelib_animation_qpropertyanimation.cpp animation-group1
A parallel group plays more than one animation at the same time.
- Calling its \l{QAbstractAnimation::}{start()} function will start
- all animations it governs.
-
- \code
- QPushButton button("Animated Button");
- button.show();
+ Its \l{QAbstractAnimation::}{start()} function starts all
+ animations that are part of the group.
- QPropertyAnimation anim1(&button, "geometry");
- anim1.setDuration(3000);
- anim1.setStartValue(QRect(0, 0, 100, 30));
- anim1.setEndValue(QRect(500, 500, 100, 30));
+ \snippet code/src_corelib_animation_qpropertyanimation.cpp animation-group2
- QPropertyAnimation anim2(&button, "geometry");
- anim2.setDuration(3000);
- anim2.setStartValue(QRect(500, 500, 100, 30));
- anim2.setEndValue(QRect(1000, 500, 100, 30));
+ As the name suggests, a QSequentialAnimationGroup plays
+ its animations in sequence. It starts the next animation in
+ the list after the previous finishes.
- QSequentialAnimationGroup group;
+ A group is an animation itself, so you can add
+ it to another group. This way, building an animation tree, which define
+ when the animations are played in relation to each other.
- group.addAnimation(&anim1);
- group.addAnimation(&anim2);
+ \section1 Object ownership
- group.start();
- \endcode
+ A QPropertyAnimation should always have a parent that controls
+ its lifespan. A typical application may include several animations that
+ are grouped, where the animation group takes ownership of those animations.
+ An independent QProperyAnimation must be explicitly assigned a parent to
+ control its lifespan. In the following example, you can see that an
+ independent QPropertyAnimation has the QApplication instance as its
+ parent:
- As you no doubt have guessed, QSequentialAnimationGroup plays
- its animations in sequence. It starts the next animation in
- the list after the previous is finished.
+ \snippet code/src_corelib_animation_qpropertyanimation.cpp 0
- Since an animation group is an animation itself, you can add
- it to another group. This way, you can build a tree structure
- of animations which specifies when the animations are played
- in relation to each other.
+ \note You can also control the animation's lifespan by choosing a
+ \l{QAbstractAnimation::DeletionPolicy}{delete policy} while starting it.
*/
diff --git a/src/corelib/doc/src/containers.qdoc b/src/corelib/doc/src/containers.qdoc
index 1050223791..93ba5b456d 100644
--- a/src/corelib/doc/src/containers.qdoc
+++ b/src/corelib/doc/src/containers.qdoc
@@ -215,7 +215,30 @@
the C++ language doesn't specify any initialization; in those
cases, Qt's containers automatically initialize the value to 0.
- \section1 The Iterator Classes
+ \section1 Iterating over Containers
+
+ \section2 Range-based for
+
+ Range-based \c for should preferably be used for containers:
+
+ \snippet code/doc_src_containers.cpp range_for
+
+ Note that when using a Qt container in a non-const context,
+ \l{implicit sharing} may perform an undesired detach of the container.
+ To prevent this, use \c std::as_const():
+
+ \snippet code/doc_src_containers.cpp range_for_as_const
+
+ For associative containers, this will loop over the values.
+
+ \section2 Index-based
+
+ For sequential containers that store their items contiguously in memory
+ (for example, QList), index-based iteration can be used:
+
+ \snippet code/doc_src_containers.cpp index
+
+ \section2 The Iterator Classes
Iterators provide a uniform means to access items in a container.
Qt's container classes provide two types of iterators: STL-style
@@ -224,7 +247,7 @@
from \l{Implicit Sharing}{implicitly shared copies} due to a call
to a non-const member function.
- \section2 STL-Style Iterators
+ \section3 STL-Style Iterators
STL-style iterators have been available since the release of Qt
2.0. They are compatible with Qt's and STL's \l{generic
@@ -339,7 +362,7 @@
This problem doesn't occur with functions that return a const or
non-const reference to a container.
- \section3 Implicit sharing iterator problem
+ \section4 Implicit sharing iterator problem
\l{Implicit sharing} has another consequence on STL-style
iterators: you should avoid copying a container while
@@ -352,7 +375,7 @@
The above example only shows a problem with QList, but
the problem exists for all the implicitly shared Qt containers.
- \section2 Java-Style Iterators
+ \section3 Java-Style Iterators
\l{java-style-iterators}{Java-Style iterators} were introduced in Qt 4. Their API is modelled
on Java's iterator classes.
New code should should prefer \l{STL-Style Iterators}.
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index 898abb12e8..5a19a20367 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -48,6 +48,7 @@
/*
The compiler, must be one of: (Q_CC_x)
+ COVERITY - Coverity cov-scan
SYM - Digital Mars C/C++ (used to be Symantec C++)
MSVC - Microsoft Visual C/C++, Intel C++ for Windows
BOR - Borland/Turbo C++
@@ -74,6 +75,10 @@
Should be sorted most to least authoritative.
*/
+#if defined(__COVERITY__)
+# define Q_CC_COVERITY
+#endif
+
/* Symantec C++ is now Digital Mars */
#if defined(__DMC__) || defined(__SC__)
# define Q_CC_SYM
@@ -1255,6 +1260,26 @@
#endif
/*
+ * If one wants to add functions that use post-C++17 APIs, one needs to:
+ *
+ * 1) make them fully inline; and
+ * 2) guard them using the necessary feature-testing macros.
+ *
+ * This decouples the C++ version used to build Qt with the one used by
+ * end-user applications; Qt and the application can either choose any C++
+ * version.
+ *
+ * A problem arises on MSVC for member functions of exported classes. Client
+ * code that tries to use such a function will see it as exported, and simply
+ * try to consume the function's *symbol*. However, if Qt has been built in
+ * C++17, it won't have such a symbol, and linking will fail.
+ *
+ * The workaround: declare such functions as function templates.
+ * (Obviously a function template does not need this marker.)
+*/
+#define QT_POST_CXX17_API_IN_EXPORTED_CLASS template <typename = void>
+
+/*
* Warning/diagnostic handling
*/
diff --git a/src/corelib/global/qflags.h b/src/corelib/global/qflags.h
index c6cbaa1adb..afec512fd4 100644
--- a/src/corelib/global/qflags.h
+++ b/src/corelib/global/qflags.h
@@ -184,12 +184,16 @@ typedef QFlags<Enum> Flags;
#endif
#define Q_DECLARE_OPERATORS_FOR_FLAGS(Flags) \
+[[maybe_unused]] \
constexpr inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) noexcept \
{ return QFlags<Flags::enum_type>(f1) | f2; } \
+[[maybe_unused]] \
constexpr inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept \
{ return f2 | f1; } \
+[[maybe_unused]] \
constexpr inline QFlags<Flags::enum_type> operator&(Flags::enum_type f1, Flags::enum_type f2) noexcept \
{ return QFlags<Flags::enum_type>(f1) & f2; } \
+[[maybe_unused]] \
constexpr inline QFlags<Flags::enum_type> operator&(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept \
{ return f2 & f1; } \
constexpr inline void operator+(Flags::enum_type f1, Flags::enum_type f2) noexcept = delete; \
@@ -210,6 +214,7 @@ constexpr inline void operator-(Flags::enum_type f1, int f2) noexcept = delete;
#if __cplusplus > 201702L // assume compilers don't warn if in C++17 mode
// in C++20 mode, provide user-defined operators to override the deprecated operations:
# define Q_DECLARE_MIXED_ENUM_OPERATOR(op, Ret, LHS, RHS) \
+ [[maybe_unused]] \
constexpr inline Ret operator op (LHS lhs, RHS rhs) noexcept \
{ return static_cast<Ret>(qToUnderlying(lhs) op qToUnderlying(rhs)); } \
/* end */
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index 0d76bbec41..d5c448094f 100644
--- a/src/corelib/global/qlogging.cpp
+++ b/src/corelib/global/qlogging.cpp
@@ -902,7 +902,7 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
if (info.isEmpty())
return info;
- int pos;
+ qsizetype pos;
// Skip trailing [with XXX] for templates (gcc), but make
// sure to not affect Objective-C message names.
@@ -949,7 +949,7 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
info.truncate(++pos);
if (info.at(pos - 1) == ')') {
- if (info.indexOf(operator_call) == pos - (int)strlen(operator_call))
+ if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)))
break;
// this function returns a pointer to a function
@@ -972,19 +972,19 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
if (pos > -1) {
switch (info.at(pos)) {
case ')':
- if (info.indexOf(operator_call) == pos - (int)strlen(operator_call) + 1)
+ if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)) + 1)
pos -= 2;
break;
case '<':
- if (info.indexOf(operator_lessThan) == pos - (int)strlen(operator_lessThan) + 1)
+ if (info.indexOf(operator_lessThan) == pos - qsizetype(strlen(operator_lessThan)) + 1)
--pos;
break;
case '>':
- if (info.indexOf(operator_greaterThan) == pos - (int)strlen(operator_greaterThan) + 1)
+ if (info.indexOf(operator_greaterThan) == pos - qsizetype(strlen(operator_greaterThan)) + 1)
--pos;
break;
case '=': {
- int operatorLength = (int)strlen(operator_lessThanEqual);
+ auto operatorLength = qsizetype(strlen(operator_lessThanEqual));
if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1)
pos -= 2;
else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1)
@@ -1028,7 +1028,7 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
break;
// find the matching close
- int end = pos;
+ qsizetype end = pos;
templatecount = 1;
--pos;
while (pos && templatecount) {
@@ -1193,7 +1193,7 @@ void QMessagePattern::setPattern(const QString &pattern)
tokens[i] = qthreadptrTokenC;
else if (lexeme.startsWith(QLatin1String(timeTokenC))) {
tokens[i] = timeTokenC;
- int spaceIdx = lexeme.indexOf(QChar::fromLatin1(' '));
+ qsizetype spaceIdx = lexeme.indexOf(QChar::fromLatin1(' '));
if (spaceIdx > 0)
timeArgs.append(lexeme.mid(spaceIdx + 1, lexeme.length() - spaceIdx - 2));
else
diff --git a/src/corelib/global/qnumeric.cpp b/src/corelib/global/qnumeric.cpp
index 63055a0b61..8d83ab5392 100644
--- a/src/corelib/global/qnumeric.cpp
+++ b/src/corelib/global/qnumeric.cpp
@@ -349,4 +349,35 @@ Q_CORE_EXPORT quint64 qFloatDistance(double a, double b)
This can be faster than calling the version with only variable arguments.
*/
+template <typename T> static constexpr T max = std::numeric_limits<T>::max();
+template <typename T> static constexpr T min = std::numeric_limits<T>::min();
+
+static_assert(qt_saturate<short>(max<unsigned>) == max<short>);
+static_assert(qt_saturate<int>(max<unsigned>) == max<int>);
+static_assert(qt_saturate<qint64>(max<unsigned>) == qint64(max<unsigned>));
+
+static_assert(qt_saturate<short>(max<int>) == max<short>);
+static_assert(qt_saturate<unsigned>(max<int>) == unsigned(max<int>));
+static_assert(qt_saturate<qint64>(max<int>) == qint64(max<int>));
+
+static_assert(qt_saturate<short>(max<qint64>) == max<short>);
+static_assert(qt_saturate<int>(max<qint64>) == max<int>);
+static_assert(qt_saturate<unsigned>(max<qint64>) == max<unsigned>);
+static_assert(qt_saturate<quint64>(max<qint64>) == quint64(max<qint64>));
+
+static_assert(qt_saturate<short>(max<quint64>) == max<short>);
+static_assert(qt_saturate<int>(max<quint64>) == max<int>);
+static_assert(qt_saturate<unsigned>(max<quint64>) == max<unsigned>);
+static_assert(qt_saturate<qint64>(max<quint64>) == max<qint64>);
+
+static_assert(qt_saturate<short>(min<int>) == min<short>);
+static_assert(qt_saturate<qint64>(min<int>) == qint64(min<int>));
+static_assert(qt_saturate<unsigned>(min<int>) == 0);
+static_assert(qt_saturate<quint64>(min<int>) == 0);
+
+static_assert(qt_saturate<short>(min<qint64>) == min<short>);
+static_assert(qt_saturate<int>(min<qint64>) == min<int>);
+static_assert(qt_saturate<unsigned>(min<qint64>) == 0);
+static_assert(qt_saturate<quint64>(min<qint64>) == 0);
+
QT_END_NAMESPACE
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h
index 823a1812de..9957377667 100644
--- a/src/corelib/global/qnumeric_p.h
+++ b/src/corelib/global/qnumeric_p.h
@@ -267,6 +267,41 @@ template <auto V2, typename T> bool mul_overflow(T v1, T *r)
}
#endif // Q_CLANG_QDOC
+/*
+ Safely narrows \a x to \c{To}. Let \c L be
+ \c{std::numeric_limit<To>::min()} and \c H be \c{std::numeric_limit<To>::max()}.
+
+ If \a x is less than L, returns L. If \a x is greater than H,
+ returns H. Otherwise, returns \c{To(x)}.
+*/
+template <typename To, typename From>
+static constexpr auto qt_saturate(From x)
+{
+ static_assert(std::is_integral_v<To>);
+ static_assert(std::is_integral_v<From>);
+
+ [[maybe_unused]]
+ constexpr auto Lo = (std::numeric_limits<To>::min)();
+ constexpr auto Hi = (std::numeric_limits<To>::max)();
+
+ if constexpr (std::is_signed_v<From> == std::is_signed_v<To>) {
+ // same signedness, we can accept regular integer conversion rules
+ return x < Lo ? Lo :
+ x > Hi ? Hi :
+ /*else*/ To(x);
+ } else {
+ if constexpr (std::is_signed_v<From>) { // ie. !is_signed_v<To>
+ if (x < From{0})
+ return To{0};
+ }
+
+ // from here on, x >= 0
+ using FromU = std::make_unsigned_t<From>;
+ using ToU = std::make_unsigned_t<To>;
+ return FromU(x) > ToU(Hi) ? Hi : To(x); // assumes Hi >= 0
+ }
+}
+
QT_END_NAMESPACE
#endif // QNUMERIC_P_H
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index a038f125cb..01340828c2 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -1913,7 +1913,8 @@ bool QDir::isEmpty(Filters filters) const
Returns a list of the root directories on this system.
On Windows this returns a list of QFileInfo objects containing "C:/",
- "D:/", etc. On other operating systems, it returns a list containing
+ "D:/", etc. This does not return drives with ejectable media that are empty.
+ On other operating systems, it returns a list containing
just one root directory (i.e. "/").
\sa root(), rootPath()
diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h
index 778ed8ce23..da6e73caf6 100644
--- a/src/corelib/io/qfilesystemwatcher_win_p.h
+++ b/src/corelib/io/qfilesystemwatcher_win_p.h
@@ -140,7 +140,10 @@ public:
Q_DECLARE_TYPEINFO(QFileSystemWatcherPathKey, Q_RELOCATABLE_TYPE);
-inline size_t qHash(const QFileSystemWatcherPathKey &key) { return qHash(key.toCaseFolded()); }
+inline size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed = 0)
+{
+ return qHash(key.toCaseFolded(), seed);
+}
class QWindowsFileSystemWatcherEngineThread : public QThread
{
diff --git a/src/corelib/io/qlockfile.h b/src/corelib/io/qlockfile.h
index aa5ad5e772..ad58ba727d 100644
--- a/src/corelib/io/qlockfile.h
+++ b/src/corelib/io/qlockfile.h
@@ -43,9 +43,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qscopedpointer.h>
-#if __has_include(<chrono>)
-# include <chrono>
-#endif
+#include <chrono>
QT_BEGIN_NAMESPACE
@@ -66,7 +64,6 @@ public:
void setStaleLockTime(int);
int staleLockTime() const;
-#if __has_include(<chrono>)
bool tryLock(std::chrono::milliseconds timeout) { return tryLock(int(timeout.count())); }
void setStaleLockTime(std::chrono::milliseconds value) { setStaleLockTime(int(value.count())); }
@@ -75,7 +72,6 @@ public:
{
return std::chrono::milliseconds(staleLockTime());
}
-#endif
bool isLocked() const;
bool getLockInfo(qint64 *pid, QString *hostname, QString *appname) const;
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index 7633b7420c..395b426cf4 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -310,8 +310,8 @@ public:
void swap(QAppleLogActivity &other)
{
- qSwap(activity, other.activity);
- qSwap(state, other.state);
+ activity.swap(other.activity);
+ std::swap(state, other.state);
}
private:
@@ -368,7 +368,7 @@ public:
void swap(QMacNotificationObserver &other) noexcept
{
- qSwap(observer, other.observer);
+ qt_ptr_swap(observer, other.observer);
}
void remove();
@@ -418,9 +418,9 @@ public:
void swap(QMacKeyValueObserver &other) noexcept
{
- qSwap(object, other.object);
- qSwap(keyPath, other.keyPath);
- qSwap(callback, other.callback);
+ qt_ptr_swap(object, other.object);
+ qt_ptr_swap(keyPath, other.keyPath);
+ callback.swap(other.callback);
}
private:
diff --git a/src/corelib/kernel/qdeadlinetimer.h b/src/corelib/kernel/qdeadlinetimer.h
index 0720a32b56..2437e9a4b2 100644
--- a/src/corelib/kernel/qdeadlinetimer.h
+++ b/src/corelib/kernel/qdeadlinetimer.h
@@ -52,9 +52,7 @@
#include <limits>
-#if __has_include(<chrono>)
-# include <chrono>
-#endif
+#include <chrono>
QT_BEGIN_NAMESPACE
@@ -120,7 +118,6 @@ public:
QDeadlineTimer &operator-=(qint64 msecs)
{ *this = *this + (-msecs); return *this; }
-#if __has_include(<chrono>) || defined(Q_CLANG_QDOC)
template <class Clock, class Duration>
QDeadlineTimer(std::chrono::time_point<Clock, Duration> deadline_,
Qt::TimerType type_ = Qt::CoarseTimer) : t2(0)
@@ -178,7 +175,6 @@ public:
template <class Rep, class Period>
friend QDeadlineTimer operator+=(QDeadlineTimer &dt, std::chrono::duration<Rep, Period> value)
{ return dt = dt + value; }
-#endif
private:
qint64 t1;
@@ -192,7 +188,7 @@ public:
QPair<qint64, unsigned> _q_data() const { return qMakePair(t1, t2); }
};
-#if __has_include(<chrono>) && (defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || (defined(Q_CC_MSVC) && Q_CC_MSVC >= 1900))
+#if defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || (defined(Q_CC_MSVC) && Q_CC_MSVC >= 1900)
// We know for these OS/compilers that the std::chrono::steady_clock uses the same
// reference time as QDeadlineTimer
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index eeccbd9093..26f3a0178d 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -43,6 +43,7 @@
#include "qmetatype.h"
#undef QT_QMETATYPE_BC_COMPAT
#include "qmetatype_p.h"
+#include "qobject.h"
#include "qobjectdefs.h"
#include "qdatetime.h"
#include "qbytearray.h"
@@ -393,6 +394,7 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte
\value QStringList QStringList
\value QVariantMap QVariantMap
\value QVariantHash QVariantHash
+ \value QVariantPair QVariantPair
\value QIcon QIcon
\value QPen QPen
\value QLineF QLineF
@@ -3011,6 +3013,13 @@ static const QtPrivate::QMetaTypeInterface *interfaceForType(int typeId)
}
/*!
+ \fn QMetaType::QMetaType()
+ \since 6.0
+
+ Constructs a default, invalid, QMetaType object.
+*/
+
+/*!
\fn QMetaType::QMetaType(int typeId)
\since 5.0
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 2a341b870a..6584754be9 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -363,7 +363,7 @@ public:
QByteArrayList = 49, QObjectStar = 39, SChar = 40,
Void = 43,
Nullptr = 51,
- QVariantMap = 8, QVariantList = 9, QVariantHash = 28,
+ QVariantMap = 8, QVariantList = 9, QVariantHash = 28, QVariantPair = 58,
QCborSimpleType = 52, QCborValue = 53, QCborArray = 54, QCborMap = 55,
Char16 = 56, Char32 = 57,
@@ -1905,10 +1905,9 @@ public:
#if defined (Q_CC_CLANG)
if (name.find("anonymous ") != std::string_view::npos)
return normalizeType(begin, end);
-#else
+#endif
if (name.find("unnamed ") != std::string_view::npos)
return normalizeType(begin, end);
-#endif
while (begin < end) {
if (*begin == ' ') {
if (last == ',' || last == '>' || last == '<' || last == '*' || last == '&') {
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 06778dcde4..c93ce8cf2e 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -56,9 +56,7 @@
#include <QtCore/qobject_impl.h>
#include <QtCore/qbindingstorage.h>
-#if __has_include(<chrono>)
-# include <chrono>
-#endif
+#include <chrono>
QT_BEGIN_NAMESPACE
@@ -150,13 +148,11 @@ public:
void moveToThread(QThread *thread);
int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
-#if __has_include(<chrono>)
Q_ALWAYS_INLINE
int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer)
{
return startTimer(int(time.count()), timerType);
}
-#endif
void killTimer(int id);
template<typename T>
diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp
index 3dbbe75fc4..6dc73fa1cf 100644
--- a/src/corelib/kernel/qsharedmemory.cpp
+++ b/src/corelib/kernel/qsharedmemory.cpp
@@ -178,6 +178,12 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
\endlist
+ Qt for iOS comes with support for POSIX shared memory out of the box.
+ With Qt for \macos an additional configure flag must be added when
+ building Qt to enable the feature. To enable the feature pass
+ \c {-feature-ipc_posix} Note that the pre-built Qt libraries for
+ \macos available through the Qt installer do not include this feature.
+
\endlist
Remember to lock the shared memory with lock() before reading from
diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h
index 2b262f6311..7e6404b2c5 100644
--- a/src/corelib/kernel/qtimer.h
+++ b/src/corelib/kernel/qtimer.h
@@ -47,9 +47,7 @@
#include <QtCore/qbasictimer.h> // conceptual inheritance
#include <QtCore/qobject.h>
-#if __has_include(<chrono>)
-# include <chrono>
-#endif
+#include <chrono>
QT_BEGIN_NAMESPACE
@@ -181,7 +179,6 @@ Q_SIGNALS:
void timeout(QPrivateSignal);
public:
-#if __has_include(<chrono>) || defined(Q_QDOC)
void setInterval(std::chrono::milliseconds value)
{
setInterval(int(value.count()));
@@ -211,7 +208,6 @@ public:
{
start(int(value.count()));
}
-#endif
protected:
void timerEvent(QTimerEvent *) override;
@@ -228,7 +224,6 @@ private:
static void singleShotImpl(int msec, Qt::TimerType timerType,
const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj);
-#if __has_include(<chrono>)
static Qt::TimerType defaultTypeFor(std::chrono::milliseconds interval)
{ return defaultTypeFor(int(interval.count())); }
@@ -238,7 +233,6 @@ private:
singleShotImpl(int(interval.count()),
timerType, receiver, slotObj);
}
-#endif
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 2844f09949..74d064af6e 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -1105,7 +1105,7 @@ void QVariant::clear()
/*!
\fn QVariant::Type QVariant::nameToType(const char *name)
- \deprecated [6.0] Use \c QMetaType.fromName(name).id() instead
+ \deprecated [6.0] Use \c QMetaType::fromName(name).id() instead
Converts the string representation of the storage type given in \a
name, to its enum representation.
@@ -1426,8 +1426,13 @@ QString QVariant::toString() const
}
/*!
- Returns the variant as a QMap<QString, QVariant> if the variant
- has type() \l QMetaType::QVariantMap; otherwise returns an empty map.
+ Returns the variant as a QVariantMap if the variant has type() \l
+ QMetaType::QVariantMap. If it doesn't, QVariant will attempt to
+ convert the type to a map and then return it. This will succeed for
+ any type that has registered a converter to QVariantMap or which was
+ declared as a associative container using
+ \l{Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE}. If none of those
+ conditions are true, this function will return an empty map.
\sa canConvert(), convert()
*/
@@ -1977,9 +1982,13 @@ qreal QVariant::toReal(bool *ok) const
}
/*!
- Returns the variant as a QVariantList if the variant has userType()
- \l QMetaType::QVariantList or \l QMetaType::QStringList; otherwise returns
- an empty list.
+ Returns the variant as a QVariantList if the variant has userType() \l
+ QMetaType::QVariantList. If it doesn't, QVariant will attempt to convert
+ the type to a list and then return it. This will succeed for any type that
+ has registered a converter to QVariantList or which was declared as a
+ sequential container using \l{Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE}. If
+ none of those conditions are true, this function will return an empty
+ list.
\sa canConvert(), convert()
*/
diff --git a/src/corelib/platform/android/qandroidextras.cpp b/src/corelib/platform/android/qandroidextras.cpp
index 9087a6a6ac..3a8a8e9343 100644
--- a/src/corelib/platform/android/qandroidextras.cpp
+++ b/src/corelib/platform/android/qandroidextras.cpp
@@ -153,6 +153,7 @@ QAndroidBinder QAndroidParcelPrivate::readBinder() const
/*!
\class QAndroidParcel
+ \inheaderfile QtCore/private/qandroidextras_p.h
\preliminary
\inmodule QtCore
\brief Wraps the most important methods of Android Parcel class.
@@ -269,6 +270,7 @@ QJniObject QAndroidParcel::handle() const
/*!
\class QAndroidBinder
+ \inheaderfile QtCore/private/qandroidextras_p.h
\preliminary
\inmodule QtCore
\brief Wraps the most important methods of Android Binder class.
@@ -406,6 +408,7 @@ QJniObject QAndroidBinder::handle() const
/*!
\class QAndroidServiceConnection
+ \inheaderfile QtCore/private/qandroidextras_p.h
\preliminary
\inmodule QtCore
\brief Wraps the most important methods of Android ServiceConnection class.
@@ -529,6 +532,7 @@ public:
/*!
\class QAndroidActivityResultReceiver
+ \inheaderfile QtCore/private/qandroidextras_p.h
\preliminary
\inmodule QtCore
\since 6.2
@@ -624,6 +628,7 @@ public:
/*!
\class QAndroidService
+ \inheaderfile QtCore/private/qandroidextras_p.h
\preliminary
\inmodule QtCore
\brief Wraps the most important methods of Android Service class.
@@ -693,6 +698,7 @@ QAndroidBinder* QAndroidService::onBind(const QAndroidIntent &/*intent*/)
/*!
\class QAndroidIntent
+ \inheaderfile QtCore/private/qandroidextras_p.h
\preliminary
\inmodule QtCore
\brief Wraps the most important methods of Android Intent class.
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index 825a431820..adf2a8de9a 100644
--- a/src/corelib/text/qbytearray.cpp
+++ b/src/corelib/text/qbytearray.cpp
@@ -41,6 +41,7 @@
#include "qbytearray.h"
#include "qbytearraymatcher.h"
+#include "qendian.h"
#include "private/qtools_p.h"
#include "qhashfunctions.h"
#include "qlist.h"
@@ -532,67 +533,212 @@ quint16 qChecksum(QByteArrayView data, Qt::ChecksumType standard)
The default value is -1, which specifies zlib's default
compression.
-//![compress-limit-note]
- \note The maximum size of data that this function can consume is limited by
- what the platform's \c{unsigned long} can represent (a Zlib limitation).
- That means that data > 4GiB can be compressed and decompressed on a 64-bit
- Unix system, but not on a 64-bit Windows system. Portable code should
- therefore avoid using qCompress()/qUncompress() to compress more than 4GiB
- of input.
-//![compress-limit-note]
-
\sa qUncompress(const QByteArray &data)
*/
-/*! \relates QByteArray
+/*!
+ \fn QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
+ \relates QByteArray
\overload
Compresses the first \a nbytes of \a data at compression level
\a compressionLevel and returns the compressed data in a new byte array.
-
- \include qbytearray.cpp compress-limit-note
*/
#ifndef QT_NO_COMPRESS
+using CompressSizeHint_t = quint32; // 32-bit BE, historically
+
+enum class ZLibOp : bool { Compression, Decompression };
+
+Q_DECL_COLD_FUNCTION
+static const char *zlibOpAsString(ZLibOp op)
+{
+ switch (op) {
+ case ZLibOp::Compression: return "qCompress";
+ case ZLibOp::Decompression: return "qUncompress";
+ }
+ Q_UNREACHABLE();
+ return nullptr;
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray zlibError(ZLibOp op, const char *what)
+{
+ qWarning("%s: %s", zlibOpAsString(op), what);
+ return QByteArray();
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray dataIsNull(ZLibOp op)
+{
+ return zlibError(op, "Data is null");
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray lengthIsNegative(ZLibOp op)
+{
+ return zlibError(op, "Input length is negative");
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray tooMuchData(ZLibOp op)
+{
+ return zlibError(op, "Not enough memory");
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray invalidCompressedData()
+{
+ return zlibError(ZLibOp::Decompression, "Input data is corrupted");
+}
+
+Q_DECL_COLD_FUNCTION
+static QByteArray unexpectedZlibError(ZLibOp op, int err, const char *msg)
+{
+ qWarning("%s unexpected zlib error: %s (%d)",
+ zlibOpAsString(op),
+ msg ? msg : "",
+ err);
+ return QByteArray();
+}
+
+template <typename Init, typename ProcessChunk, typename Deinit>
+static QByteArray xxflate(ZLibOp op, QArrayDataPointer<char> out, QByteArrayView input,
+ Init init,
+ ProcessChunk processChunk,
+ Deinit deinit)
+{
+ if (out.data() == nullptr) // allocation failed
+ return tooMuchData(op);
+ qsizetype capacity = out.allocatedCapacity();
+
+ const auto initalSize = out.size;
+
+ z_stream zs = {};
+ zs.next_in = reinterpret_cast<uchar *>(const_cast<char *>(input.data())); // 1980s C API...
+ if (const int err = init(&zs); err != Z_OK)
+ return unexpectedZlibError(op, err, zs.msg);
+ const auto sg = qScopeGuard([&] { deinit(&zs); });
+
+ using ZlibChunkSize_t = decltype(zs.avail_in);
+ static_assert(!std::is_signed_v<ZlibChunkSize_t>);
+ static_assert(std::is_same_v<ZlibChunkSize_t, decltype(zs.avail_out)>);
+ constexpr auto MaxChunkSize = std::numeric_limits<ZlibChunkSize_t>::max();
+ [[maybe_unused]]
+ constexpr auto MaxStatisticsSize = std::numeric_limits<decltype(zs.total_out)>::max();
+
+ size_t inputLeft = size_t(input.size());
+
+ int res;
+ do {
+ Q_ASSERT(out.freeSpaceAtBegin() == 0); // ensure prepend optimization stays out of the way
+ Q_ASSERT(capacity == out.allocatedCapacity());
+
+ if (zs.avail_out == 0) {
+ Q_ASSERT(size_t(out.size) - initalSize > MaxStatisticsSize || // total_out overflow
+ size_t(out.size) - initalSize == zs.total_out);
+ Q_ASSERT(out.size <= capacity);
+
+ qsizetype avail_out = capacity - out.size;
+ if (avail_out == 0) {
+ out->reallocateAndGrow(QArrayData::GrowsAtEnd, 1); // grow to next natural capacity
+ if (out.data() == nullptr) // reallocation failed
+ return tooMuchData(op);
+ capacity = out.allocatedCapacity();
+ avail_out = capacity - out.size;
+ }
+ zs.next_out = reinterpret_cast<uchar *>(out.data()) + out.size;
+ zs.avail_out = size_t(avail_out) > size_t(MaxChunkSize) ? MaxChunkSize
+ : ZlibChunkSize_t(avail_out);
+ out.size += zs.avail_out;
+
+ Q_ASSERT(zs.avail_out > 0);
+ }
+
+ if (zs.avail_in == 0) {
+ // zs.next_in is kept up-to-date by processChunk(), so nothing to do
+ zs.avail_in = inputLeft > MaxChunkSize ? MaxChunkSize : ZlibChunkSize_t(inputLeft);
+ inputLeft -= zs.avail_in;
+ }
+
+ res = processChunk(&zs, inputLeft);
+ } while (res == Z_OK);
+
+ switch (res) {
+ case Z_STREAM_END:
+ out.size -= zs.avail_out;
+ Q_ASSERT(size_t(out.size) - initalSize > MaxStatisticsSize || // total_out overflow
+ size_t(out.size) - initalSize == zs.total_out);
+ Q_ASSERT(out.size <= out.allocatedCapacity());
+ out.data()[out.size] = '\0';
+ return QByteArray(std::move(out));
+
+ case Z_MEM_ERROR:
+ return tooMuchData(op);
+
+ case Z_BUF_ERROR:
+ Q_UNREACHABLE(); // cannot happen - we supply a buffer that can hold the result,
+ // or else error out early
+
+ case Z_DATA_ERROR: // can only happen on decompression
+ Q_ASSERT(op == ZLibOp::Decompression);
+ return invalidCompressedData();
+
+ default:
+ return unexpectedZlibError(op, res, zs.msg);
+ }
+}
+
QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
{
+ constexpr qsizetype HeaderSize = sizeof(CompressSizeHint_t);
if (nbytes == 0) {
- return QByteArray(4, '\0');
- }
- if (!data) {
- qWarning("qCompress: Data is null");
- return QByteArray();
+ return QByteArray(HeaderSize, '\0');
}
+ if (!data)
+ return dataIsNull(ZLibOp::Compression);
+
+ if (nbytes < 0)
+ return lengthIsNegative(ZLibOp::Compression);
+
if (compressionLevel < -1 || compressionLevel > 9)
compressionLevel = -1;
- ulong len = nbytes + nbytes / 100 + 13;
- QByteArray bazip;
- int res;
- do {
- bazip.resize(len + 4);
- res = ::compress2((uchar*)bazip.data()+4, &len, data, nbytes, compressionLevel);
-
- switch (res) {
- case Z_OK:
- bazip.resize(len + 4);
- bazip[0] = (nbytes & 0xff000000) >> 24;
- bazip[1] = (nbytes & 0x00ff0000) >> 16;
- bazip[2] = (nbytes & 0x0000ff00) >> 8;
- bazip[3] = (nbytes & 0x000000ff);
- break;
- case Z_MEM_ERROR:
- qWarning("qCompress: Z_MEM_ERROR: Not enough memory");
- bazip.resize(0);
- break;
- case Z_BUF_ERROR:
- len *= 2;
- break;
+ QArrayDataPointer out = [&] {
+ constexpr qsizetype SingleAllocLimit = 256 * 1024; // the maximum size for which we use
+ // zlib's compressBound() to guarantee
+ // the output buffer size is sufficient
+ // to hold result
+ qsizetype capacity = HeaderSize;
+ if (nbytes < SingleAllocLimit) {
+ // use maximum size
+ capacity += compressBound(uLong(nbytes)); // cannot overflow (both times)!
+ return QArrayDataPointer{QTypedArrayData<char>::allocate(capacity)};
}
- } while (res == Z_BUF_ERROR);
- return bazip;
+ // for larger buffers, assume it compresses optimally, and
+ // grow geometrically from there:
+ constexpr qsizetype MaxCompressionFactor = 1024; // max theoretical factor is 1032
+ // cf. http://www.zlib.org/zlib_tech.html,
+ // but use a nearby power-of-two (faster)
+ capacity += std::max(qsizetype(compressBound(uLong(SingleAllocLimit))),
+ nbytes / MaxCompressionFactor);
+ return QArrayDataPointer{QTypedArrayData<char>::allocate(capacity, QArrayData::Grow)};
+ }();
+
+ if (out.data() == nullptr) // allocation failed
+ return tooMuchData(ZLibOp::Compression);
+
+ qToBigEndian(qt_saturate<CompressSizeHint_t>(nbytes), out.data());
+ out.size = HeaderSize;
+
+ return xxflate(ZLibOp::Compression, std::move(out), {data, nbytes},
+ [=] (z_stream *zs) { return deflateInit(zs, compressionLevel); },
+ [] (z_stream *zs, size_t inputLeft) {
+ return deflate(zs, inputLeft ? Z_NO_FLUSH : Z_FINISH);
+ },
+ [] (z_stream *zs) { deflateEnd(zs); });
}
#endif
@@ -614,98 +760,63 @@ QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
data that was compressed using zlib, you first need to prepend a four
byte header to the byte array containing the data. The header must
contain the expected length (in bytes) of the uncompressed data,
- expressed as an unsigned, big-endian, 32-bit integer.
+ expressed as an unsigned, big-endian, 32-bit integer. This number is
+ just a hint for the initial size of the output buffer size,
+ though. If the indicated size is too small to hold the result, the
+ output buffer size will still be increased until either the output
+ fits or the system runs out of memory. So, despite the 32-bit
+ header, this function, on 64-bit platforms, can produce more than
+ 4GiB of output.
-//![uncompress-limit-note]
- \note The maximum size of data that this function can produce is limited by
- what the platform's \c{unsigned long} can represent (a Zlib limitation).
- That means that data > 4GiB can be compressed and decompressed on a 64-bit
- Unix system, but not on a 64-bit Windows system. Portable code should
- therefore avoid using qCompress()/qUncompress() to compress more than 4GiB
- of input.
-//![uncompress-limit-note]
+ \note In Qt versions prior to Qt 6.5, more than 2GiB of data
+ worked unreliably; in Qt versions prior to Qt 6.0, not at all.
\sa qCompress()
*/
#ifndef QT_NO_COMPRESS
-static QByteArray invalidCompressedData()
-{
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
-}
-
/*! \relates QByteArray
\overload
Uncompresses the first \a nbytes of \a data and returns a new byte
array with the uncompressed data.
-
- \include qbytearray.cpp uncompress-limit-note
*/
QByteArray qUncompress(const uchar* data, qsizetype nbytes)
{
- if (!data) {
- qWarning("qUncompress: Data is null");
- return QByteArray();
- }
- if (nbytes <= 4) {
- if (nbytes < 4 || (data[0]!=0 || data[1]!=0 || data[2]!=0 || data[3]!=0))
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
- }
- size_t expectedSize = size_t((data[0] << 24) | (data[1] << 16) |
- (data[2] << 8) | (data[3] ));
- size_t len = qMax(expectedSize, 1ul);
- constexpr size_t maxPossibleSize = MaxAllocSize - sizeof(QByteArray::Data);
- if (Q_UNLIKELY(len >= maxPossibleSize)) {
- // QByteArray does not support that huge size anyway.
- return invalidCompressedData();
- }
+ if (!data)
+ return dataIsNull(ZLibOp::Decompression);
- QByteArray::DataPointer d(QByteArray::Data::allocate(len));
- if (Q_UNLIKELY(d.data() == nullptr))
- return invalidCompressedData();
+ if (nbytes < 0)
+ return lengthIsNegative(ZLibOp::Decompression);
- forever {
- const auto alloc = len;
- int res = ::uncompress((uchar*)d.data(), reinterpret_cast<uLongf*>(&len),
- data+4, nbytes-4);
-
- switch (res) {
- case Z_OK: {
- Q_ASSERT(len <= alloc);
- Q_UNUSED(alloc);
- d.data()[len] = '\0';
- d.size = len;
- return QByteArray(d);
- }
+ constexpr qsizetype HeaderSize = sizeof(CompressSizeHint_t);
+ if (nbytes < HeaderSize)
+ return invalidCompressedData();
- case Z_MEM_ERROR:
- qWarning("qUncompress: Z_MEM_ERROR: Not enough memory");
- return QByteArray();
-
- case Z_BUF_ERROR:
- static_assert(maxPossibleSize <= (std::numeric_limits<decltype(len)>::max)() / 2,
- "oops, next line may overflow");
- len *= 2;
- if (Q_UNLIKELY(len >= maxPossibleSize)) {
- // QByteArray does not support that huge size anyway.
- return invalidCompressedData();
- } else {
- // grow the block
- d->reallocate(d->allocatedCapacity()*2, QArrayData::Grow);
- if (Q_UNLIKELY(d.data() == nullptr))
- return invalidCompressedData();
- }
- continue;
+ const auto expectedSize = qFromBigEndian<CompressSizeHint_t>(data);
+ if (nbytes == HeaderSize) {
+ if (expectedSize != 0)
+ return invalidCompressedData();
+ return QByteArray();
+ }
- case Z_DATA_ERROR:
- qWarning("qUncompress: Z_DATA_ERROR: Input data is corrupted");
- return QByteArray();
- }
+ constexpr auto MaxDecompressedSize = size_t(MaxByteArraySize);
+ if constexpr (MaxDecompressedSize < std::numeric_limits<CompressSizeHint_t>::max()) {
+ if (expectedSize > MaxDecompressedSize)
+ return tooMuchData(ZLibOp::Decompression);
}
+
+ // expectedSize may be truncated, so always use at least nbytes
+ // (larger by at most 1%, according to zlib docs)
+ qsizetype capacity = std::max(qsizetype(expectedSize), // cannot overflow!
+ nbytes);
+
+ QArrayDataPointer d(QTypedArrayData<char>::allocate(capacity, QArrayData::KeepSize));
+ return xxflate(ZLibOp::Decompression, std::move(d), {data + HeaderSize, nbytes - HeaderSize},
+ [] (z_stream *zs) { return inflateInit(zs); },
+ [] (z_stream *zs, size_t) { return inflate(zs, Z_NO_FLUSH); },
+ [] (z_stream *zs) { inflateEnd(zs); });
}
#endif
diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp
index 40d34ddfeb..5566d44449 100644
--- a/src/corelib/text/qlocale_win.cpp
+++ b/src/corelib/text/qlocale_win.cpp
@@ -634,9 +634,13 @@ QVariant QSystemLocalePrivate::uiLanguages()
#if QT_CONFIG(cpp_winrt) && !defined(Q_CC_CLANG)
using namespace winrt;
using namespace Windows::System::UserProfile;
- auto languages = GlobalizationPreferences::Languages();
- for (const auto &lang : languages)
- result << QString::fromStdString(winrt::to_string(lang));
+ QT_TRY {
+ auto languages = GlobalizationPreferences::Languages();
+ for (const auto &lang : languages)
+ result << QString::fromStdString(winrt::to_string(lang));
+ } QT_CATCH(...) {
+ // pass, just fall back to WIN32 API implementation
+ }
if (!result.isEmpty())
return result; // else just fall back to WIN32 API implementation
#endif // QT_CONFIG(cpp_winrt) && !defined(Q_CC_CLANG)
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 6ec93835b4..a8365e8aef 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -2890,6 +2890,14 @@ QString &QString::append(const QString &str)
}
/*!
+ \fn QString &QString::append(QStringView v)
+ \overload append()
+ \since 6.0
+
+ Appends the given string view \a v to this string and returns the result.
+*/
+
+/*!
\overload append()
\since 5.0
@@ -6763,6 +6771,7 @@ QString QString::vasprintf(const char *cformat, va_list ap)
int precision = -1; // -1 means unspecified
if (*c == '.') {
++c;
+ precision = 0;
if (qIsDigit(*c)) {
precision = parse_field_width(c);
} else if (*c == '*') { // can't parse this in another function, not portably, at least
@@ -8833,8 +8842,8 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size)
\c{const char *} instead of QString. This includes the copy
constructor, the assignment operator, the comparison operators,
and various other functions such as \l{QString::insert()}{insert()},
- \l{QString::replace()}{replace()}, and \l{QString::indexOf()}{indexOf()}.
- These functions are usually optimized to avoid constructing a
+ \l{QString::append()}{append()}, and \l{QString::prepend()}{prepend()}.
+ Some of these functions are optimized to avoid constructing a
QString object for the \c{const char *} data. For example,
assuming \c str is a QString,
@@ -8847,6 +8856,12 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size)
because it doesn't construct four temporary QString objects and
make a deep copy of the character data.
+ However, that is not true for all QString member functions that take
+ \c{const char *} and therefore applications should assume a temporary will
+ be created, such as in
+
+ \snippet code/src_corelib_text_qstring.cpp 4bis
+
Applications that define \l QT_NO_CAST_FROM_ASCII (as explained
in the QString documentation) don't have access to QString's
\c{const char *} API. To provide an efficient way of specifying
diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp
index b72ac6f515..5045137fd5 100644
--- a/src/corelib/text/qstringconverter.cpp
+++ b/src/corelib/text/qstringconverter.cpp
@@ -218,7 +218,7 @@ static inline const uchar *simdFindNonAscii(const uchar *src, const uchar *end,
#ifdef __AVX2__
// do 32 characters at a time
// (this is similar to simdTestMask in qstring.cpp)
- const __m256i mask = _mm256_set1_epi8(0x80);
+ const __m256i mask = _mm256_set1_epi8(char(0x80));
for ( ; end - src >= 32; src += 32) {
__m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src));
if (_mm256_testz_si256(mask, data))
diff --git a/src/corelib/text/qstringlist.cpp b/src/corelib/text/qstringlist.cpp
index 07a419423a..f0d385184d 100644
--- a/src/corelib/text/qstringlist.cpp
+++ b/src/corelib/text/qstringlist.cpp
@@ -120,25 +120,7 @@ QT_BEGIN_NAMESPACE
\section1 Iterating Over the Strings
- To iterate over a list, you can either use index positions or
- QList's Java-style and STL-style iterator types:
-
- Indexing:
-
- \snippet qstringlist/main.cpp 1
-
- Java-style iterator:
-
- \snippet qstringlist/main.cpp 2
-
- STL-style iterator:
-
- \snippet qstringlist/main.cpp 3
-
- The QStringListIterator class is simply a type definition for
- QListIterator<QString>. QStringList also provide the
- QMutableStringListIterator class which is a type definition for
- QMutableListIterator<QString>.
+ See \l {Iterating over Containers}.
\section1 Manipulating the Strings
diff --git a/src/corelib/thread/qatomic.cpp b/src/corelib/thread/qatomic.cpp
index 9956314322..986b12f797 100644
--- a/src/corelib/thread/qatomic.cpp
+++ b/src/corelib/thread/qatomic.cpp
@@ -433,14 +433,21 @@
Atomic test-and-set.
+ \note If you use this function in a loop, consider using the overload with the
+ additional \c{T &currentValue} argument instead, which avoids the extra load() on
+ failure.
+
If the current value of this QAtomicInteger is the \a expectedValue,
the test-and-set functions assign the \a newValue to this
QAtomicInteger and return true. If the values are \e not the same,
this function does nothing and returns \c false.
+//![memory-order-relaxed]
This function uses \e relaxed \l {QAtomicInteger#Memory
ordering}{memory ordering} semantics, leaving the compiler and
processor to freely reorder memory accesses.
+//![memory-order-relaxed]
+
*/
/*!
@@ -448,15 +455,21 @@
Atomic test-and-set.
+ \note If you use this function in a loop, consider using the overload with the
+ additional \c{T &currentValue} argument instead, which avoids the extra load() on
+ failure.
+
If the current value of this QAtomicInteger is the \a expectedValue,
the test-and-set functions assign the \a newValue to this
QAtomicInteger and return true. If the values are \e not the same,
this function does nothing and returns \c false.
+//![memory-order-acquire]
This function uses \e acquire \l {QAtomicInteger#Memory
ordering}{memory ordering} semantics, which ensures that memory
access following the atomic operation (in program order) may not
be re-ordered before the atomic operation.
+//![memory-order-acquire]
*/
/*!
@@ -464,15 +477,21 @@
Atomic test-and-set.
+ \note If you use this function in a loop, consider using the overload with the
+ additional \c{T &currentValue} argument instead, which avoids the extra load() on
+ failure.
+
If the current value of this QAtomicInteger is the \a expectedValue,
the test-and-set functions assign the \a newValue to this
QAtomicInteger and return true. If the values are \e not the same,
this function does nothing and returns \c false.
+//![memory-order-release]
This function uses \e release \l {QAtomicInteger#Memory
ordering}{memory ordering} semantics, which ensures that memory
access before the atomic operation (in program order) may not be
re-ordered after the atomic operation.
+//![memory-order-release]
*/
/*!
@@ -480,15 +499,78 @@
Atomic test-and-set.
+ \note If you use this function in a loop, consider using the overload with the
+ additional \c{T &currentValue} argument instead, which avoids the extra load() on
+ failure.
+
If the current value of this QAtomicInteger is the \a expectedValue,
the test-and-set functions assign the \a newValue to this
QAtomicInteger and return true. If the values are \e not the same,
this function does nothing and returns \c false.
+//![memory-order-ordered]
This function uses \e ordered \l {QAtomicInteger#Memory
ordering}{memory ordering} semantics, which ensures that memory
access before and after the atomic operation (in program order)
may not be re-ordered.
+//![memory-order-ordered]
+
+*/
+
+/*!
+ \fn template <typename T> bool QAtomicInteger<T>::testAndSetRelaxed(T expectedValue, T newValue, T &currentValue)
+ \since 5.3
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInteger is the \a expectedValue, the
+ test-and-set functions assign the \a newValue to this QAtomicInteger and
+ return \c true. If the values are \e not the same, the functions load the
+ current value of this QAtomicInteger into \a currentValue and return \c false.
+
+ \include qatomic.cpp memory-order-relaxed
+*/
+
+/*!
+ \fn template <typename T> bool QAtomicInteger<T>::testAndSetAcquire(T expectedValue, T newValue, T &currentValue)
+ \since 5.3
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInteger is the \a expectedValue, the
+ test-and-set functions assign the \a newValue to this QAtomicInteger and
+ return \c true. If the values are \e not the same, the functions load the
+ current value of this QAtomicInteger into \a currentValue and return \c false.
+
+ \include qatomic.cpp memory-order-acquire
+*/
+
+/*!
+ \fn template <typename T> bool QAtomicInteger<T>::testAndSetRelease(T expectedValue, T newValue, T &currentValue)
+ \since 5.3
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInteger is the \a expectedValue, the
+ test-and-set functions assign the \a newValue to this QAtomicInteger and
+ return \c true. If the values are \e not the same, the functions loads the
+ current value of this QAtomicInteger into \a currentValue and return \c false.
+
+ \include qatomic.cpp memory-order-release
+*/
+
+/*!
+ \fn template <typename T> bool QAtomicInteger<T>::testAndSetOrdered(T expectedValue, T newValue, T &currentValue)
+ \since 5.3
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInteger is the \a expectedValue, the
+ test-and-set functions assign the \a newValue to this QAtomicInteger and
+ return \c true. If the values are \e not the same, it loads the current
+ value of this QAtomicInteger into \a currentValue and return \c false.
+
+ \include qatomic.cpp memory-order-ordered
*/
/*!
diff --git a/src/corelib/thread/qatomic.h b/src/corelib/thread/qatomic.h
index 2080167d2c..d04f82cff2 100644
--- a/src/corelib/thread/qatomic.h
+++ b/src/corelib/thread/qatomic.h
@@ -106,6 +106,11 @@ public:
bool testAndSetRelease(T expectedValue, T newValue);
bool testAndSetOrdered(T expectedValue, T newValue);
+ bool testAndSetRelaxed(T expectedValue, T newValue, T &currentValue);
+ bool testAndSetAcquire(T expectedValue, T newValue, T &currentValue);
+ bool testAndSetRelease(T expectedValue, T newValue, T &currentValue);
+ bool testAndSetOrdered(T expectedValue, T newValue, T &currentValue);
+
static constexpr bool isFetchAndStoreNative();
static constexpr bool isFetchAndStoreWaitFree();
diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp
index ae6c45d385..6b35ed1eb8 100644
--- a/src/corelib/thread/qfutureinterface.cpp
+++ b/src/corelib/thread/qfutureinterface.cpp
@@ -120,6 +120,14 @@ void QFutureInterfaceBase::cancel()
return;
switch_from_to(d->state, suspendingOrSuspended, Canceled);
+
+ // Cancel the continuations chain
+ QFutureInterfaceBasePrivate *next = d->continuationData;
+ while (next) {
+ next->continuationState = QFutureInterfaceBasePrivate::Canceled;
+ next = next->continuationData;
+ }
+
d->waitCondition.wakeAll();
d->pausedWaitCondition.wakeAll();
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled));
@@ -769,16 +777,19 @@ void QFutureInterfaceBase::setContinuation(std::function<void(const QFutureInter
{
QMutexLocker lock(&d->continuationMutex);
- if (continuationFutureData)
- continuationFutureData->parentData = d;
-
// If the state is ready, run continuation immediately,
// otherwise save it for later.
if (isFinished()) {
lock.unlock();
func(*this);
- } else {
+ lock.relock();
+ }
+ // Unless the continuation has been cleaned earlier, we have to
+ // store the move-only continuation, to guarantee that the associated
+ // future's data stays alive.
+ if (d->continuationState != QFutureInterfaceBasePrivate::Cleaned) {
d->continuation = std::move(func);
+ d->continuationData = continuationFutureData;
}
}
@@ -792,34 +803,32 @@ void QFutureInterfaceBase::cleanContinuation()
// copies of this, so that the allocated memory can be freed.
QMutexLocker lock(&d->continuationMutex);
d->continuation = nullptr;
+ d->continuationState = QFutureInterfaceBasePrivate::Cleaned;
}
void QFutureInterfaceBase::runContinuation() const
{
QMutexLocker lock(&d->continuationMutex);
if (d->continuation) {
- auto fn = std::exchange(d->continuation, nullptr);
+ // Save the continuation in a local function, to avoid calling
+ // a null std::function below, in case cleanContinuation() is
+ // called from some other thread right after unlock() below.
+ auto fn = std::move(d->continuation);
lock.unlock();
fn(*this);
+
+ lock.relock();
+ // Unless the continuation has been cleaned earlier, we have to
+ // store the move-only continuation, to guarantee that the associated
+ // future's data stays alive.
+ if (d->continuationState != QFutureInterfaceBasePrivate::Cleaned)
+ d->continuation = std::move(fn);
}
}
bool QFutureInterfaceBase::isChainCanceled() const
{
- if (isCanceled())
- return true;
-
- auto parent = d->parentData;
- while (parent) {
- // If the future is in Canceled state because it had an exception, we want to
- // continue checking the chain of parents for cancellation, otherwise if the exception
- // is handeled inside the chain, it won't be interrupted even though cancellation has
- // been requested.
- if ((parent->state.loadRelaxed() & Canceled) && !parent->m_exceptionStore.hasException())
- return true;
- parent = parent->parentData;
- }
- return false;
+ return isCanceled() || d->continuationState == QFutureInterfaceBasePrivate::Canceled;
}
void QFutureInterfaceBase::setLaunchAsync(bool value)
diff --git a/src/corelib/thread/qfutureinterface_p.h b/src/corelib/thread/qfutureinterface_p.h
index 287972ba50..651aa853a5 100644
--- a/src/corelib/thread/qfutureinterface_p.h
+++ b/src/corelib/thread/qfutureinterface_p.h
@@ -175,7 +175,10 @@ public:
QThreadPool *m_pool = nullptr;
// Wrapper for continuation
std::function<void(const QFutureInterfaceBase &)> continuation;
- QFutureInterfaceBasePrivate *parentData = nullptr;
+ QFutureInterfaceBasePrivate *continuationData = nullptr;
+
+ enum ContinuationState : quint8 { Default, Canceled, Cleaned };
+ std::atomic<ContinuationState> continuationState { Default };
RefCount refCount = 1;
QAtomicInt state; // reads and writes can happen unprotected, both must be atomic
diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h
index 3e861ca0cb..beb68ccc02 100644
--- a/src/corelib/thread/qmutex.h
+++ b/src/corelib/thread/qmutex.h
@@ -44,10 +44,8 @@
#include <QtCore/qatomic.h>
#include <new>
-#if __has_include(<chrono>)
-# include <chrono>
-# include <limits>
-#endif
+#include <chrono>
+#include <limits>
class tst_QMutex;
@@ -66,7 +64,6 @@ class QMutex;
class QRecursiveMutex;
class QMutexPrivate;
-#if __has_include(<chrono>)
namespace QtPrivate
{
template<class Rep, class Period>
@@ -92,7 +89,6 @@ namespace QtPrivate
return ms < maxInt ? int(ms) : maxInt;
}
}
-#endif
class Q_CORE_EXPORT QBasicMutex
{
diff --git a/src/corelib/thread/qpromise.h b/src/corelib/thread/qpromise.h
index 3dcb13f99a..d55ea1a4cd 100644
--- a/src/corelib/thread/qpromise.h
+++ b/src/corelib/thread/qpromise.h
@@ -77,6 +77,7 @@ public:
d.cancel();
finish(); // required to finalize the state
}
+ d.cleanContinuation();
}
// Core QPromise APIs
diff --git a/src/corelib/time/qdatetime.h b/src/corelib/time/qdatetime.h
index d0d7e1c47f..722b66a9d2 100644
--- a/src/corelib/time/qdatetime.h
+++ b/src/corelib/time/qdatetime.h
@@ -229,18 +229,25 @@ class QDateTimePrivate;
class Q_CORE_EXPORT QDateTime
{
struct ShortData {
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- quintptr status : 8;
-#endif
#if QT_VERSION >= QT_VERSION_CHECK(7,0,0)
+# if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ qint64 status : 8;
+# endif
qint64 msecs : 56;
+
+# if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ qint64 status : 8;
+# endif
#else
+# if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ quintptr status : 8;
+# endif
// note: this is only 24 bits on 32-bit systems...
qintptr msecs : sizeof(void *) * 8 - 8;
-#endif
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+# if Q_BYTE_ORDER == Q_BIG_ENDIAN
quintptr status : 8;
+# endif
#endif
};
diff --git a/src/corelib/tools/qlist.qdoc b/src/corelib/tools/qlist.qdoc
index 4e92e2c047..e366a30324 100644
--- a/src/corelib/tools/qlist.qdoc
+++ b/src/corelib/tools/qlist.qdoc
@@ -153,21 +153,7 @@
support \c operator==(). These requirements are documented on a
per-function basis.
- Like the other container classes, QList provides \l{Java-style iterators}
- (QListIterator and QMutableListIterator) and \l{STL-style iterators}
- (QList::const_iterator and QList::iterator). In practice, iterators are
- handy when working with generic algorithms provided by \l{generic
- algorithms}{Qt} and the C++ standard library. \l{Java-style iterators} are
- provided for backwards compatibility, prefer \l{STL-style iterators} when
- writing C++ code.
-
- \note Iterators over a QList, and references to individual elements
- within one, cannot be relied on to remain valid when any non-const method
- of the QList is called. Accessing such an iterator or reference after
- the call to a non-const method leads to undefined behavior. When stability
- for iterator-like functionality is required, you should use indexes instead
- of iterators as they are not tied to QList's internal state and thus do
- not get invalidated.
+ For iterating over the items, see \l {Iterating over Containers}.
In addition to QList, Qt also provides QVarLengthArray, a very
low-level class with little functionality that is optimized for
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index 59070c947c..5daf24189b 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -359,6 +359,7 @@ public:
if (!d)
return T();
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
// TODO: improve. There is no need of copying all the
// elements (the one to be removed can be skipped).
detach();
@@ -400,6 +401,7 @@ public:
T &operator[](const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
detach();
auto i = d->m.find(key);
if (i == d->m.end())
@@ -669,6 +671,7 @@ public:
iterator find(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.find(key));
}
@@ -687,6 +690,7 @@ public:
iterator lowerBound(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.lower_bound(key));
}
@@ -700,6 +704,7 @@ public:
iterator upperBound(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.upper_bound(key));
}
@@ -713,6 +718,7 @@ public:
iterator insert(const Key &key, const T &value)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
// TODO: improve. In case of assignment, why copying first?
detach();
return iterator(d->m.insert_or_assign(key, value).first);
@@ -722,6 +728,7 @@ public:
{
// TODO: improve. In case of assignment, why copying first?
typename Map::const_iterator dpos;
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key`/`value` alive across the detach
if (!d || d.isShared()) {
auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0;
detach();
@@ -789,6 +796,7 @@ public:
QPair<iterator, iterator> equal_range(const Key &akey)
{
+ const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
detach();
auto result = d->m.equal_range(akey);
return {iterator(result.first), iterator(result.second)};
@@ -986,15 +994,15 @@ public:
if (!d)
return 0;
- // TODO: improve. Copy over only the elements not to be removed.
- detach();
-
// key and value may belong to this map. As such, we need to copy
// them to ensure they stay valid throughout the iteration below
// (which may destroy them)
const Key keyCopy = key;
const T valueCopy = value;
+ // TODO: improve. Copy over only the elements not to be removed.
+ detach();
+
size_type result = 0;
const auto &keyCompare = d->m.key_comp();
@@ -1024,6 +1032,8 @@ public:
if (!d)
return T();
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
+
// TODO: improve. There is no need of copying all the
// elements (the one to be removed can be skipped).
detach();
@@ -1361,6 +1371,7 @@ public:
iterator find(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.find(key));
}
@@ -1379,6 +1390,8 @@ public:
iterator find(const Key &key, const T &value)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach
+
detach();
auto range = d->m.equal_range(key);
@@ -1411,6 +1424,7 @@ public:
iterator lowerBound(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.lower_bound(key));
}
@@ -1424,6 +1438,7 @@ public:
iterator upperBound(const Key &key)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
detach();
return iterator(d->m.upper_bound(key));
}
@@ -1437,6 +1452,7 @@ public:
iterator insert(const Key &key, const T &value)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach
detach();
// note that std::multimap inserts at the end of an equal_range for a key,
// QMultiMap at the beginning.
@@ -1446,6 +1462,7 @@ public:
iterator insert(const_iterator pos, const Key &key, const T &value)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach
typename Map::const_iterator dpos;
if (!d || d.isShared()) {
auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0;
@@ -1484,6 +1501,8 @@ public:
iterator replace(const Key &key, const T &value)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach
+
// TODO: improve. No need of copying and then overwriting.
detach();
@@ -1503,6 +1522,7 @@ public:
QPair<iterator, iterator> equal_range(const Key &akey)
{
+ const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
detach();
auto result = d->m.equal_range(akey);
return {iterator(result.first), iterator(result.second)};
diff --git a/src/corelib/tools/qmap.qdoc b/src/corelib/tools/qmap.qdoc
index a14a3bdb09..f9eed72d67 100644
--- a/src/corelib/tools/qmap.qdoc
+++ b/src/corelib/tools/qmap.qdoc
@@ -238,6 +238,15 @@
Returns an STL map equivalent to this QMap.
*/
+/*! \fn template <class Key, class T> std::map<Key, T> QMap<Key, T>::toStdMap() &&
+
+ \overload
+ \since 6.0
+
+ \note Calling this function will leave this QMap in the partially-formed state, in which
+ the only valid operations are destruction or assignment of a new value.
+*/
+
/*! \fn template <class Key, class T> bool QMap<Key, T>::operator==(const QMap<Key, T> &lhs, const QMap<Key, T> &rhs)
Returns \c true if \a lhs is equal to \a rhs; otherwise returns
diff --git a/src/corelib/tools/qtaggedpointer.h b/src/corelib/tools/qtaggedpointer.h
index 68074cc43d..b60fc424f4 100644
--- a/src/corelib/tools/qtaggedpointer.h
+++ b/src/corelib/tools/qtaggedpointer.h
@@ -108,11 +108,30 @@ public:
return !isNull();
}
- QTaggedPointer &operator=(T *other) noexcept
+#ifdef Q_QDOC
+ QTaggedPointer &operator=(T *other) noexcept;
+#else
+ // Disables the usage of `ptr = {}`, which would go through this operator
+ // (rather than using the implicitly-generated assignment operator).
+ // The operators have different semantics: the ones here leave the tag intact,
+ // the implicitly-generated one overwrites it.
+ template <typename U,
+ std::enable_if_t<std::is_convertible_v<U *, T *>, bool> = false>
+ QTaggedPointer &operator=(U *other) noexcept
+ {
+ T *otherT = other;
+ d = reinterpret_cast<quintptr>(otherT) | (d & tagMask());
+ return *this;
+ }
+
+ template <typename U,
+ std::enable_if_t<std::is_null_pointer_v<U>, bool> = false>
+ QTaggedPointer &operator=(U) noexcept
{
- d = reinterpret_cast<quintptr>(other) | (d & tagMask());
+ d = reinterpret_cast<quintptr>(static_cast<T *>(nullptr)) | (d & tagMask());
return *this;
}
+#endif
static constexpr Tag maximumTag() noexcept
{