diff --git a/src/corelib/tools/qshareddata.cpp b/src/corelib/tools/qshareddata.cpp index ffc13f7d695..2f8cf98230c 100644 --- a/src/corelib/tools/qshareddata.cpp +++ b/src/corelib/tools/qshareddata.cpp @@ -443,6 +443,10 @@ QT_BEGIN_NAMESPACE \since 4.4 \reentrant + \compares strong + \compareswith strong T* std::nullptr_t + \endcompareswith + QExplicitlySharedDataPointer\ makes writing your own explicitly shared classes easy. QExplicitlySharedDataPointer implements \l {thread-safe} reference counting, ensuring that adding @@ -520,8 +524,8 @@ QT_BEGIN_NAMESPACE \since 5.2 */ -/*! \fn template bool QExplicitlySharedDataPointer::operator==(const T* ptr, const QExplicitlySharedDataPointer& rhs) - Returns \c true if the \e{d pointer} of \a rhs is \a ptr. +/*! \fn template bool QExplicitlySharedDataPointer::operator==(const T* const &lhs, const QExplicitlySharedDataPointer& rhs) + Returns \c true if the \e{d pointer} of \a rhs is \a lhs. */ /*! \fn template bool QExplicitlySharedDataPointer::operator!=(const QExplicitlySharedDataPointer& lhs, const QExplicitlySharedDataPointer& rhs) @@ -529,8 +533,8 @@ QT_BEGIN_NAMESPACE \e{d pointer}. */ -/*! \fn template bool QExplicitlySharedDataPointer::operator!=(const T* ptr, const QExplicitlySharedDataPointer& rhs) - Returns \c true if the \e{d pointer} of \a rhs is \e not \a ptr. +/*! \fn template bool QExplicitlySharedDataPointer::operator!=(const T* const &lhs, const QExplicitlySharedDataPointer& rhs) + Returns \c true if the \e{d pointer} of \a rhs is \e not \a lhs. */ /*! \fn template QExplicitlySharedDataPointer::QExplicitlySharedDataPointer() diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h index a9d41803391..63b459ae001 100644 --- a/src/corelib/tools/qshareddata.h +++ b/src/corelib/tools/qshareddata.h @@ -134,21 +134,21 @@ public: typedef T Type; typedef T *pointer; - T &operator*() const { return *d; } - T *operator->() noexcept { return d; } - T *operator->() const noexcept { return d; } - explicit operator T *() { return d; } - explicit operator const T *() const noexcept { return d; } - T *data() const noexcept { return d; } - T *get() const noexcept { return d; } - const T *constData() const noexcept { return d; } - T *take() noexcept { return std::exchange(d, nullptr); } + T &operator*() const { return *(d.get()); } + T *operator->() noexcept { return d.get(); } + T *operator->() const noexcept { return d.get(); } + explicit operator T *() { return d.get(); } + explicit operator const T *() const noexcept { return d.get(); } + T *data() const noexcept { return d.get(); } + T *get() const noexcept { return d.get(); } + const T *constData() const noexcept { return d.get(); } + T *take() noexcept { return std::exchange(d, nullptr).get(); } void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); } Q_NODISCARD_CTOR QExplicitlySharedDataPointer() noexcept : d(nullptr) { } - ~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d; } + ~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d.get(); } Q_NODISCARD_CTOR explicit QExplicitlySharedDataPointer(T *data) noexcept : d(data) @@ -174,7 +174,7 @@ public: if (ptr != d) { if (ptr) ptr->ref.ref(); - T *old = std::exchange(d, ptr); + T *old = std::exchange(d, Qt::totally_ordered_wrapper(ptr)).get(); if (old && !old->ref.deref()) delete old; } @@ -182,7 +182,7 @@ public: QExplicitlySharedDataPointer &operator=(const QExplicitlySharedDataPointer &o) noexcept { - reset(o.d); + reset(o.d.get()); return *this; } QExplicitlySharedDataPointer &operator=(T *o) noexcept @@ -200,35 +200,36 @@ public: void swap(QExplicitlySharedDataPointer &other) noexcept { qt_ptr_swap(d, other.d); } -#define DECLARE_COMPARE_SET(T1, A1, T2, A2) \ - friend bool operator<(T1, T2) noexcept \ - { return std::less{}(A1, A2); } \ - friend bool operator<=(T1, T2) noexcept \ - { return !std::less{}(A2, A1); } \ - friend bool operator>(T1, T2) noexcept \ - { return std::less{}(A2, A1); } \ - friend bool operator>=(T1, T2) noexcept \ - { return !std::less{}(A1, A2); } \ - friend bool operator==(T1, T2) noexcept \ - { return A1 == A2; } \ - friend bool operator!=(T1, T2) noexcept \ - { return A1 != A2; } \ - - DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const QExplicitlySharedDataPointer &p2, p2.d) - DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, const T *ptr, ptr) - DECLARE_COMPARE_SET(const T *ptr, ptr, const QExplicitlySharedDataPointer &p2, p2.d) - DECLARE_COMPARE_SET(const QExplicitlySharedDataPointer &p1, p1.d, std::nullptr_t, nullptr) - DECLARE_COMPARE_SET(std::nullptr_t, nullptr, const QExplicitlySharedDataPointer &p2, p2.d) - -#undef DECLARE_COMPARE_SET - protected: T *clone(); private: + friend bool comparesEqual(const QExplicitlySharedDataPointer &lhs, + const QExplicitlySharedDataPointer &rhs) noexcept + { return lhs.d == rhs.d; } + friend Qt::strong_ordering + compareThreeWay(const QExplicitlySharedDataPointer &lhs, + const QExplicitlySharedDataPointer &rhs) noexcept + { return Qt::compareThreeWay(lhs.d, rhs.d); } + Q_DECLARE_STRONGLY_ORDERED(QExplicitlySharedDataPointer) + + friend bool comparesEqual(const QExplicitlySharedDataPointer &lhs, const T *rhs) noexcept + { return lhs.d == rhs; } + friend Qt::strong_ordering + compareThreeWay(const QExplicitlySharedDataPointer &lhs, const T *rhs) noexcept + { return Qt::compareThreeWay(lhs.d, rhs); } + Q_DECLARE_STRONGLY_ORDERED(QExplicitlySharedDataPointer, const T*) + + friend bool comparesEqual(const QExplicitlySharedDataPointer &lhs, std::nullptr_t) noexcept + { return lhs.d == nullptr; } + friend Qt::strong_ordering + compareThreeWay(const QExplicitlySharedDataPointer &lhs, std::nullptr_t) noexcept + { return Qt::compareThreeWay(lhs.d, nullptr); } + Q_DECLARE_STRONGLY_ORDERED(QExplicitlySharedDataPointer, std::nullptr_t) + void detach_helper(); - T *d; + Qt::totally_ordered_wrapper d; }; // Declared here and as Q_OUTOFLINE_TEMPLATE to work-around MSVC bug causing missing symbols at link time. @@ -251,7 +252,7 @@ Q_OUTOFLINE_TEMPLATE void QSharedDataPointer::detach_helper() template Q_INLINE_TEMPLATE T *QExplicitlySharedDataPointer::clone() { - return new T(*d); + return new T(*d.get()); } template @@ -260,8 +261,8 @@ Q_OUTOFLINE_TEMPLATE void QExplicitlySharedDataPointer::detach_helper() T *x = clone(); x->ref.ref(); if (!d->ref.deref()) - delete d; - d = x; + delete d.get(); + d.reset(x); } template @@ -309,7 +310,7 @@ template Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer, Q_ template<> QExplicitlySharedDataPointer::~QExplicitlySharedDataPointer() \ { \ if (d && !d->ref.deref()) \ - delete d; \ + delete d.get(); \ } QT_END_NAMESPACE diff --git a/src/dbus/qdbusunixfiledescriptor.cpp b/src/dbus/qdbusunixfiledescriptor.cpp index 943c593acb9..54f1ab2bfb4 100644 --- a/src/dbus/qdbusunixfiledescriptor.cpp +++ b/src/dbus/qdbusunixfiledescriptor.cpp @@ -89,9 +89,7 @@ public: QAtomicInt fd; }; -template<> inline -QExplicitlySharedDataPointer::~QExplicitlySharedDataPointer() -{ if (d && !d->ref.deref()) delete d; } +QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QDBusUnixFileDescriptorPrivate) /*! Constructs a QDBusUnixFileDescriptor without a wrapped file descriptor. diff --git a/src/network/access/qhttpheaders.cpp b/src/network/access/qhttpheaders.cpp index a4ec7b422db..e988f098b55 100644 --- a/src/network/access/qhttpheaders.cpp +++ b/src/network/access/qhttpheaders.cpp @@ -802,7 +802,7 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QHttpHeadersPrivate) template <> void QExplicitlySharedDataPointer::detach() { if (!d) { - d = new QHttpHeadersPrivate(); + d.reset(new QHttpHeadersPrivate()); d->ref.ref(); } else if (d->ref.loadRelaxed() != 1) { detach_helper(); diff --git a/tests/auto/corelib/tools/qexplicitlyshareddatapointer/CMakeLists.txt b/tests/auto/corelib/tools/qexplicitlyshareddatapointer/CMakeLists.txt index 280918e3025..ffbf8876c1d 100644 --- a/tests/auto/corelib/tools/qexplicitlyshareddatapointer/CMakeLists.txt +++ b/tests/auto/corelib/tools/qexplicitlyshareddatapointer/CMakeLists.txt @@ -14,4 +14,6 @@ endif() qt_internal_add_test(tst_qexplicitlyshareddatapointer SOURCES tst_qexplicitlyshareddatapointer.cpp + LIBRARIES + Qt::TestPrivate ) diff --git a/tests/auto/corelib/tools/qexplicitlyshareddatapointer/tst_qexplicitlyshareddatapointer.cpp b/tests/auto/corelib/tools/qexplicitlyshareddatapointer/tst_qexplicitlyshareddatapointer.cpp index 5e105a090a0..7fc25483d98 100644 --- a/tests/auto/corelib/tools/qexplicitlyshareddatapointer/tst_qexplicitlyshareddatapointer.cpp +++ b/tests/auto/corelib/tools/qexplicitlyshareddatapointer/tst_qexplicitlyshareddatapointer.cpp @@ -3,6 +3,8 @@ #include +#include + #include /*! @@ -24,11 +26,19 @@ private Q_SLOTS: void data() const; void reset() const; void swap() const; + void compareCompiles() const; + void compare() const; }; class MyClass : public QSharedData { public: + MyClass() = default; + MyClass(int v) : m_value(v) + { + ref.ref(); + }; + int m_value; void mutating() { } @@ -220,6 +230,41 @@ void tst_QExplicitlySharedDataPointer::swap() const QVERIFY(!p2.data()); } +void tst_QExplicitlySharedDataPointer::compareCompiles() const +{ + QTestPrivate::testAllComparisonOperatorsCompile>(); + QTestPrivate::testAllComparisonOperatorsCompile, + MyClass*>(); + QTestPrivate::testAllComparisonOperatorsCompile, + std::nullptr_t>(); +} + +void tst_QExplicitlySharedDataPointer::compare() const +{ + const QExplicitlySharedDataPointer ptr; + const QExplicitlySharedDataPointer ptr2; + QT_TEST_ALL_COMPARISON_OPS(ptr, nullptr, Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(ptr2, nullptr, Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(ptr, ptr2, Qt::strong_ordering::equal); + + const QExplicitlySharedDataPointer copy(ptr); + QT_TEST_ALL_COMPARISON_OPS(ptr, copy, Qt::strong_ordering::equal); + + MyClass* pointer = nullptr; + QT_TEST_ALL_COMPARISON_OPS(pointer, ptr, Qt::strong_ordering::equal); + + const QExplicitlySharedDataPointer pointer2(new MyClass()); + QT_TEST_ALL_COMPARISON_OPS(pointer, pointer2, Qt::strong_ordering::less); + + std::array myArray {MyClass(2), MyClass(1), MyClass(0)}; + const QExplicitlySharedDataPointer val0(&myArray[0]); + const QExplicitlySharedDataPointer val1(&myArray[1]); + QT_TEST_ALL_COMPARISON_OPS(val0, val1, Qt::strong_ordering::less); + QT_TEST_ALL_COMPARISON_OPS(val0, &myArray[1], Qt::strong_ordering::less); + QT_TEST_ALL_COMPARISON_OPS(val1, val0, Qt::strong_ordering::greater); + QT_TEST_ALL_COMPARISON_OPS(&myArray[1], val0, Qt::strong_ordering::greater); +} + QTEST_MAIN(tst_QExplicitlySharedDataPointer) #include "tst_qexplicitlyshareddatapointer.moc"