From 67f840a23295ad5d202005fc4913857d2da3edf5 Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Fri, 5 Feb 2021 13:47:42 +0100 Subject: QtPositioning: refactor QGeoAreaMonitorInfo The following changes were implemented for the class: - Use QExplicitlySharedDataPointer for private d-ptr instead of QSharedDataPointer, so that we can have more control over the sharing behavior. - Implement move-constructor and move-assignment operator. The moved-from object is left in partially-formed state. Such behavior is documented. - Use Q_DECLARE_SHARED to declare the typeinfo as Q_RELOCATABLE_TYPE and provide a free swap() overload. - Provide a qHash() overload. - Provide a QTest::toString() overload. Task-number: QTBUG-90491 Change-Id: I8d89dff15d92e6643cf405700db73dc636d38b77 Reviewed-by: Alex Blasche --- src/positioning/qgeoareamonitorinfo.cpp | 63 +++++++++++++++++++++- src/positioning/qgeoareamonitorinfo.h | 27 +++++++++- tests/auto/qgeoareamonitor/tst_qgeoareamonitor.cpp | 27 +++++++++- 3 files changed, 112 insertions(+), 5 deletions(-) diff --git a/src/positioning/qgeoareamonitorinfo.cpp b/src/positioning/qgeoareamonitorinfo.cpp index 5d39dee2..fd0f3283 100644 --- a/src/positioning/qgeoareamonitorinfo.cpp +++ b/src/positioning/qgeoareamonitorinfo.cpp @@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE \inmodule QtPositioning \since 5.2 \ingroup QtPositioning-positioning + \ingroup shared \brief The QGeoAreaMonitorInfo class describes the parameters of an area or region to be monitored for proximity. @@ -127,6 +128,17 @@ QGeoAreaMonitorInfo::QGeoAreaMonitorInfo(const QGeoAreaMonitorInfo &other) { } +/*! + \fn QGeoAreaMonitorInfo::QGeoAreaMonitorInfo(QGeoAreaMonitorInfo &&other) noexcept + \since 6.2 + + Constructs a QGeoAreaMonitorInfo object by moving from \a other. + + Note that a moved-from QGeoAreaMonitorInfo can only be destroyed or + assigned to. The effect of calling other functions than the destructor + or one of the assignment operators is undefined. +*/ + /*! Destructor */ @@ -134,6 +146,8 @@ QGeoAreaMonitorInfo::~QGeoAreaMonitorInfo() { } +QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QGeoAreaMonitorInfoPrivate) + /*! Assigns \a other to this QGeoAreaMonitorInfo object and returns a reference to this QGeoAreaMonitorInfo object. @@ -144,6 +158,18 @@ QGeoAreaMonitorInfo &QGeoAreaMonitorInfo::operator=(const QGeoAreaMonitorInfo &o return *this; } +/*! + \fn QGeoAreaMonitorInfo &QGeoAreaMonitorInfo::operator=(QGeoAreaMonitorInfo &&other) noexcept + \since 6.2 + + Move-assigns \a other to this QGeoAreaMonitorInfo object and returns a + reference to this QGeoAreaMonitorInfo object. + + Note that a moved-from QGeoAreaMonitorInfo can only be destroyed or + assigned to. The effect of calling other functions than the destructor + or one of the assignment operators is undefined. +*/ + /*! Returns true if all of this object's values are the same as those of \a other. @@ -181,8 +207,10 @@ QString QGeoAreaMonitorInfo::name() const */ void QGeoAreaMonitorInfo::setName(const QString &name) { - if (d->name != name) + if (d->name != name) { + d.detach(); d->name = name; + } } /*! @@ -223,6 +251,7 @@ QGeoShape QGeoAreaMonitorInfo::area() const */ void QGeoAreaMonitorInfo::setArea(const QGeoShape &newShape) { + d.detach(); d->shape = newShape; } @@ -249,6 +278,7 @@ QDateTime QGeoAreaMonitorInfo::expiration() const */ void QGeoAreaMonitorInfo::setExpiration(const QDateTime &expiry) { + d.detach(); d->expiry = expiry; } @@ -281,6 +311,7 @@ bool QGeoAreaMonitorInfo::isPersistent() const */ void QGeoAreaMonitorInfo::setPersistent(bool isPersistent) { + d.detach(); d->persistent = isPersistent; } @@ -302,9 +333,21 @@ QVariantMap QGeoAreaMonitorInfo::notificationParameters() const */ void QGeoAreaMonitorInfo::setNotificationParameters(const QVariantMap ¶meters) { + d.detach(); d->notificationParameters = parameters; } +/*! + \internal +*/ +void QGeoAreaMonitorInfo::detach() +{ + if (d) + d.detach(); + else + d = new QGeoAreaMonitorInfoPrivate; +} + #ifndef QT_NO_DATASTREAM /*! @@ -376,4 +419,22 @@ QDebug operator<<(QDebug dbg, const QGeoAreaMonitorInfo &monitor) #endif +size_t qHash(const QGeoAreaMonitorInfo &key, size_t seed) noexcept +{ + return qHashMulti(seed, key.d->uid); +} + +namespace QTest +{ + +char *toString(const QGeoAreaMonitorInfo &info) +{ + QString result; + QDebug dbg(&result); + dbg << info; + return qstrdup(qPrintable(result)); +} + +} // namespace QTest + QT_END_NAMESPACE diff --git a/src/positioning/qgeoareamonitorinfo.h b/src/positioning/qgeoareamonitorinfo.h index ae65d2c7..1374ebdf 100644 --- a/src/positioning/qgeoareamonitorinfo.h +++ b/src/positioning/qgeoareamonitorinfo.h @@ -42,7 +42,8 @@ #include #include -#include +#include +#include #include QT_BEGIN_NAMESPACE @@ -55,15 +56,27 @@ Q_POSITIONING_EXPORT QDataStream &operator<<(QDataStream &, const QGeoAreaMonito Q_POSITIONING_EXPORT QDataStream &operator>>(QDataStream &, QGeoAreaMonitorInfo &); #endif +Q_POSITIONING_EXPORT size_t qHash(const QGeoAreaMonitorInfo &key, size_t seed = 0) noexcept; +namespace QTest +{ +Q_POSITIONING_EXPORT char *toString(const QGeoAreaMonitorInfo &info); +} // namespace QTest + class QGeoAreaMonitorInfoPrivate; +QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QGeoAreaMonitorInfoPrivate, Q_POSITIONING_EXPORT) + class Q_POSITIONING_EXPORT QGeoAreaMonitorInfo { public: explicit QGeoAreaMonitorInfo(const QString &name = QString()); QGeoAreaMonitorInfo(const QGeoAreaMonitorInfo &other); + QGeoAreaMonitorInfo(QGeoAreaMonitorInfo &&other) noexcept = default; ~QGeoAreaMonitorInfo(); QGeoAreaMonitorInfo &operator=(const QGeoAreaMonitorInfo &other); + QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QGeoAreaMonitorInfo) + + void swap(QGeoAreaMonitorInfo &other) noexcept { d.swap(other.d); } bool operator==(const QGeoAreaMonitorInfo &other) const; bool operator!=(const QGeoAreaMonitorInfo &other) const; @@ -85,19 +98,29 @@ public: QVariantMap notificationParameters() const; void setNotificationParameters(const QVariantMap ¶meters); + + void detach(); + private: - QSharedDataPointer d; + QExplicitlySharedDataPointer d; + friend class QGeoAreaMonitorInfoPrivate; #ifndef QT_NO_DATASTREAM friend Q_POSITIONING_EXPORT QDataStream &operator<<(QDataStream &, const QGeoAreaMonitorInfo &); friend Q_POSITIONING_EXPORT QDataStream &operator>>(QDataStream &, QGeoAreaMonitorInfo &); #endif + friend Q_POSITIONING_EXPORT size_t qHash(const QGeoAreaMonitorInfo &key, size_t seed) noexcept; + friend Q_POSITIONING_EXPORT char *QTest::toString(const QGeoAreaMonitorInfo& info); }; +Q_DECLARE_SHARED(QGeoAreaMonitorInfo) + #ifndef QT_NO_DEBUG_STREAM Q_POSITIONING_EXPORT QDebug operator<<(QDebug, const QGeoAreaMonitorInfo &); #endif QT_END_NAMESPACE +Q_DECLARE_METATYPE(QGeoAreaMonitorInfo) + #endif // QGEOAREAMONITORINFO_H diff --git a/tests/auto/qgeoareamonitor/tst_qgeoareamonitor.cpp b/tests/auto/qgeoareamonitor/tst_qgeoareamonitor.cpp index 914b35bd..16fe2149 100644 --- a/tests/auto/qgeoareamonitor/tst_qgeoareamonitor.cpp +++ b/tests/auto/qgeoareamonitor/tst_qgeoareamonitor.cpp @@ -52,8 +52,6 @@ QT_USE_NAMESPACE #define UPDATE_INTERVAL 200 -Q_DECLARE_METATYPE(QGeoAreaMonitorInfo) - QString tst_qgeoareamonitorinfo_debug; void tst_qgeoareamonitorinfo_messageHandler(QtMsgType type, @@ -237,6 +235,31 @@ private slots: delete obj; } + void tst_monitor_move_semantics() + { + QGeoAreaMonitorInfo info1("test"); + info1.setArea(QGeoCircle(QGeoCoordinate(1.0, 1.0), 100)); + info1.setExpiration(QDateTime::currentDateTimeUtc()); + QGeoAreaMonitorInfo infoCopy(info1); + + QGeoAreaMonitorInfo info2(std::move(info1)); + QCOMPARE(info2, infoCopy); + + QGeoAreaMonitorInfo info3; + info3.setName("name"); + info3.setArea(QGeoRectangle(QGeoCoordinate(1, 2), QGeoCoordinate(2, 1))); + info3.setPersistent(true); + infoCopy = info3; + + // check that (move)assigning to the moved-from object is ok + info1 = std::move(info3); + QCOMPARE(info1, infoCopy); + + // The moved-from object info3 will go out of scope and will be + // destroyed here, so we also implicitly check that moved-from object's + // destructor is called without any issues. + } + void tst_monitorValid() { QGeoAreaMonitorInfo mon; -- cgit v1.2.1