QSP/QWP: introduce owner_before, owner_equal, owner_hash
While at the moment we don't have aliasing support in QSharedPointer,
introduce owner-based comparisons and hashing. This also fulfills some
use cases in lieu of operator== for QWeakPointer (which got deprecated
by bb23a05905
).
I'm using C++26/P1901's spelling of owner_equal, instead of
Boost.SmartPtr's spelling (owner_equal*s*). Given the niche use case,
the lack of interoperability with Qt's own containers, as well as the
Standard comparison objects' semantics (std::owner_less,
std::owner_equal), I don't think we should be giving these a Qt-ish name
as it would be pretty useless.
[ChangeLog][QtCore][QSharedPointer] Added owner_before, owner_equal,
owner_hash.
[ChangeLog][QtCore][QWeakPointer] Added owner_before, owner_equal,
owner_hash.
Done-with: Fabian Kosmale <fabian.kosmale@qt.io>
Change-Id: I8b792ae79f14cd518ba4a006edaa17786a8352a0
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
1dcc14f2d0
commit
358745d7de
@ -710,6 +710,49 @@
|
|||||||
\snippet code/src_corelib_tools_qsharedpointer.cpp 7
|
\snippet code/src_corelib_tools_qsharedpointer.cpp 7
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn template <class T> template <class X> bool QSharedPointer<T>::owner_before(const QSharedPointer<X> &other) const noexcept
|
||||||
|
\fn template <class T> template <class X> bool QSharedPointer<T>::owner_before(const QWeakPointer<X> &other) const noexcept
|
||||||
|
\fn template <class T> template <class X> bool QWeakPointer<T>::owner_before(const QSharedPointer<X> &other) const noexcept
|
||||||
|
\fn template <class T> template <class X> bool QWeakPointer<T>::owner_before(const QWeakPointer<X> &other) const noexcept
|
||||||
|
\since 6.7
|
||||||
|
|
||||||
|
Returns \c true if and only if this smart pointer precedes \a other
|
||||||
|
in an implementation-defined owner-based ordering. The ordering is such
|
||||||
|
that two smart pointers are considered equivalent if they are both
|
||||||
|
empty or if they both own the same object (even if their apparent type
|
||||||
|
and pointer are different).
|
||||||
|
|
||||||
|
\sa owner_equal
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn template <class T> template <class X> bool QSharedPointer<T>::owner_equal(const QSharedPointer<X> &other) const noexcept
|
||||||
|
\fn template <class T> template <class X> bool QSharedPointer<T>::owner_equal(const QWeakPointer<X> &other) const noexcept
|
||||||
|
\fn template <class T> template <class X> bool QWeakPointer<T>::owner_equal(const QSharedPointer<X> &other) const noexcept
|
||||||
|
\fn template <class T> template <class X> bool QWeakPointer<T>::owner_equal(const QWeakPointer<X> &other) const noexcept
|
||||||
|
|
||||||
|
\since 6.7
|
||||||
|
|
||||||
|
Returns \c true if and only if this smart pointer and \a other
|
||||||
|
share ownership.
|
||||||
|
|
||||||
|
\sa owner_before, owner_hash
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn template <class T> size_t QSharedPointer<T>::owner_hash() const noexcept
|
||||||
|
\fn template <class T> size_t QWeakPointer<T>::owner_hash() const noexcept
|
||||||
|
|
||||||
|
\since 6.7
|
||||||
|
|
||||||
|
Returns a owner-based hash value for this smart pointer object.
|
||||||
|
Smart pointers that compare equal (as per \c{owner_equal}) will
|
||||||
|
have an identical owner-based hash.
|
||||||
|
|
||||||
|
\sa owner_equal
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn template <class T> QWeakPointer<T>::QWeakPointer()
|
\fn template <class T> QWeakPointer<T>::QWeakPointer()
|
||||||
|
|
||||||
|
@ -72,6 +72,19 @@ public:
|
|||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static inline QSharedPointer<T> create(Args &&... args);
|
static inline QSharedPointer<T> create(Args &&... args);
|
||||||
|
|
||||||
|
// owner-based comparisons
|
||||||
|
template <typename X>
|
||||||
|
bool owner_before(const QSharedPointer<X> &other) const noexcept;
|
||||||
|
template <typename X>
|
||||||
|
bool owner_before(const QWeakPointer<X> &other) const noexcept;
|
||||||
|
|
||||||
|
template <typename X>
|
||||||
|
bool owner_equal(const QSharedPointer<X> &other) const noexcept;
|
||||||
|
template <typename X>
|
||||||
|
bool owner_equal(const QWeakPointer<X> &other) const noexcept;
|
||||||
|
|
||||||
|
size_t owner_hash() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@ -108,6 +121,19 @@ public:
|
|||||||
|
|
||||||
QSharedPointer<T> toStrongRef() const;
|
QSharedPointer<T> toStrongRef() const;
|
||||||
QSharedPointer<T> lock() const;
|
QSharedPointer<T> lock() const;
|
||||||
|
|
||||||
|
// owner-based comparisons
|
||||||
|
template <typename X>
|
||||||
|
bool owner_before(const QWeakPointer<X> &other) const noexcept;
|
||||||
|
template <typename X>
|
||||||
|
bool owner_before(const QSharedPointer<X> &other) const noexcept;
|
||||||
|
|
||||||
|
template <typename X>
|
||||||
|
bool owner_equal(const QWeakPointer<X> &other) const noexcept;
|
||||||
|
template <typename X>
|
||||||
|
bool owner_equal(const QSharedPointer<X> &other) const noexcept;
|
||||||
|
|
||||||
|
size_t owner_hash() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
@ -444,6 +444,23 @@ public:
|
|||||||
#undef DECLARE_TEMPLATE_COMPARE_SET
|
#undef DECLARE_TEMPLATE_COMPARE_SET
|
||||||
#undef DECLARE_COMPARE_SET
|
#undef DECLARE_COMPARE_SET
|
||||||
|
|
||||||
|
template <typename X>
|
||||||
|
bool owner_before(const QSharedPointer<X> &other) const noexcept
|
||||||
|
{ return std::less<>()(d, other.d); }
|
||||||
|
template <typename X>
|
||||||
|
bool owner_before(const QWeakPointer<X> &other) const noexcept
|
||||||
|
{ return std::less<>()(d, other.d); }
|
||||||
|
|
||||||
|
template <typename X>
|
||||||
|
bool owner_equal(const QSharedPointer<X> &other) const noexcept
|
||||||
|
{ return d == other.d; }
|
||||||
|
template <typename X>
|
||||||
|
bool owner_equal(const QWeakPointer<X> &other) const noexcept
|
||||||
|
{ return d == other.d; }
|
||||||
|
|
||||||
|
size_t owner_hash() const noexcept
|
||||||
|
{ return std::hash<Data *>()(d); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_NODISCARD_CTOR
|
Q_NODISCARD_CTOR
|
||||||
explicit QSharedPointer(Qt::Initialization) {}
|
explicit QSharedPointer(Qt::Initialization) {}
|
||||||
@ -684,6 +701,23 @@ public:
|
|||||||
friend bool operator!=(std::nullptr_t, const QWeakPointer &p)
|
friend bool operator!=(std::nullptr_t, const QWeakPointer &p)
|
||||||
{ return !p.isNull(); }
|
{ return !p.isNull(); }
|
||||||
|
|
||||||
|
template <typename X>
|
||||||
|
bool owner_before(const QWeakPointer<X> &other) const noexcept
|
||||||
|
{ return std::less<>()(d, other.d); }
|
||||||
|
template <typename X>
|
||||||
|
bool owner_before(const QSharedPointer<X> &other) const noexcept
|
||||||
|
{ return std::less<>()(d, other.d); }
|
||||||
|
|
||||||
|
template <typename X>
|
||||||
|
bool owner_equal(const QWeakPointer<X> &other) const noexcept
|
||||||
|
{ return d == other.d; }
|
||||||
|
template <typename X>
|
||||||
|
bool owner_equal(const QSharedPointer<X> &other) const noexcept
|
||||||
|
{ return d == other.d; }
|
||||||
|
|
||||||
|
size_t owner_hash() const noexcept
|
||||||
|
{ return std::hash<Data *>()(d); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct QtPrivate::EnableInternalData;
|
friend struct QtPrivate::EnableInternalData;
|
||||||
template <class X> friend class QSharedPointer;
|
template <class X> friend class QSharedPointer;
|
||||||
|
@ -91,6 +91,7 @@ private slots:
|
|||||||
void invalidConstructs_data();
|
void invalidConstructs_data();
|
||||||
void invalidConstructs();
|
void invalidConstructs();
|
||||||
#endif
|
#endif
|
||||||
|
void ownerComparisons();
|
||||||
|
|
||||||
// let invalidConstructs be the last test, because it's the slowest;
|
// let invalidConstructs be the last test, because it's the slowest;
|
||||||
// add new tests above this block
|
// add new tests above this block
|
||||||
@ -2841,5 +2842,140 @@ void tst_QSharedPointer::overloads()
|
|||||||
weakOverloaded.test();
|
weakOverloaded.test();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QSharedPointer::ownerComparisons()
|
||||||
|
{
|
||||||
|
using SP = QSharedPointer<int>;
|
||||||
|
using WP = QWeakPointer<int>;
|
||||||
|
|
||||||
|
#define CHECK_EQ(a, b) \
|
||||||
|
do { \
|
||||||
|
QVERIFY(a.owner_equal(b)); \
|
||||||
|
QVERIFY(b.owner_equal(a)); \
|
||||||
|
QVERIFY(!a.owner_before(b)); \
|
||||||
|
QVERIFY(!b.owner_before(a)); \
|
||||||
|
QVERIFY(a.owner_hash() == b.owner_hash()); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define CHECK_NOT_EQ(a, b) \
|
||||||
|
do { \
|
||||||
|
QVERIFY(!a.owner_equal(b)); \
|
||||||
|
QVERIFY(!b.owner_equal(a)); \
|
||||||
|
QVERIFY(a.owner_before(b) || b.owner_before(a)); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
// null
|
||||||
|
{
|
||||||
|
SP sp1;
|
||||||
|
SP sp2;
|
||||||
|
WP wp1 = sp1;
|
||||||
|
WP wp2;
|
||||||
|
|
||||||
|
CHECK_EQ(sp1, sp1);
|
||||||
|
CHECK_EQ(sp1, sp2);
|
||||||
|
CHECK_EQ(sp1, wp1);
|
||||||
|
CHECK_EQ(sp2, wp2);
|
||||||
|
CHECK_EQ(wp1, wp1);
|
||||||
|
CHECK_EQ(wp1, wp2);
|
||||||
|
CHECK_EQ(wp2, wp2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// same owner
|
||||||
|
{
|
||||||
|
SP sp1 = SP::create(123);
|
||||||
|
SP sp2 = sp1;
|
||||||
|
WP wp1 = sp1;
|
||||||
|
SP wp2 = sp2;
|
||||||
|
|
||||||
|
CHECK_EQ(sp1, sp1);
|
||||||
|
CHECK_EQ(sp1, sp2);
|
||||||
|
CHECK_EQ(sp1, wp1);
|
||||||
|
CHECK_EQ(sp2, wp2);
|
||||||
|
CHECK_EQ(wp1, wp1);
|
||||||
|
CHECK_EQ(wp1, wp2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// owning vs null
|
||||||
|
{
|
||||||
|
SP sp1 = SP::create(123);
|
||||||
|
SP sp2;
|
||||||
|
WP wp1 = sp1;
|
||||||
|
WP wp2 = sp2;
|
||||||
|
|
||||||
|
CHECK_EQ(sp1, sp1);
|
||||||
|
CHECK_NOT_EQ(sp1, sp2);
|
||||||
|
CHECK_EQ(sp1, wp1);
|
||||||
|
CHECK_EQ(sp2, wp2);
|
||||||
|
CHECK_EQ(wp1, wp1);
|
||||||
|
CHECK_NOT_EQ(wp1, wp2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// different owners
|
||||||
|
{
|
||||||
|
SP sp1 = SP::create(123);
|
||||||
|
SP sp2 = SP::create(456);
|
||||||
|
WP wp1 = sp1;
|
||||||
|
WP wp2 = sp2;
|
||||||
|
|
||||||
|
CHECK_EQ(sp1, sp1);
|
||||||
|
CHECK_NOT_EQ(sp1, sp2);
|
||||||
|
CHECK_EQ(sp1, wp1);
|
||||||
|
CHECK_EQ(sp2, wp2);
|
||||||
|
CHECK_EQ(wp1, wp1);
|
||||||
|
CHECK_NOT_EQ(wp1, wp2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset vs. null
|
||||||
|
{
|
||||||
|
SP sp1 = SP::create(123);
|
||||||
|
SP sp2;
|
||||||
|
WP wp1 = sp1;
|
||||||
|
WP wp2;
|
||||||
|
|
||||||
|
CHECK_EQ(sp1, sp1);
|
||||||
|
CHECK_NOT_EQ(sp1, sp2);
|
||||||
|
CHECK_EQ(sp1, wp1);
|
||||||
|
CHECK_NOT_EQ(sp1, wp2);
|
||||||
|
CHECK_EQ(wp1, wp1);
|
||||||
|
CHECK_NOT_EQ(wp1, wp2);
|
||||||
|
|
||||||
|
sp1.reset();
|
||||||
|
|
||||||
|
CHECK_EQ(sp1, sp1);
|
||||||
|
CHECK_EQ(sp1, sp2);
|
||||||
|
CHECK_NOT_EQ(sp1, wp1);
|
||||||
|
CHECK_EQ(sp2, wp2);
|
||||||
|
CHECK_EQ(wp1, wp1);
|
||||||
|
CHECK_NOT_EQ(wp1, wp2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// expired weak pointers
|
||||||
|
{
|
||||||
|
WP wp1 = SP::create(123);
|
||||||
|
WP wp2;
|
||||||
|
|
||||||
|
CHECK_EQ(wp1, wp1);
|
||||||
|
CHECK_NOT_EQ(wp1, wp2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
WP wp1 = SP::create(123);
|
||||||
|
WP wp2 = wp1;
|
||||||
|
|
||||||
|
CHECK_EQ(wp1, wp1);
|
||||||
|
CHECK_EQ(wp1, wp2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
WP wp1 = SP::create(123);
|
||||||
|
WP wp2 = SP::create(456);
|
||||||
|
|
||||||
|
CHECK_EQ(wp1, wp1);
|
||||||
|
CHECK_EQ(wp2, wp2);
|
||||||
|
CHECK_NOT_EQ(wp1, wp2);
|
||||||
|
}
|
||||||
|
#undef CHECK_EQ
|
||||||
|
#undef CHECK_NOT_EQ
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QSharedPointer)
|
QTEST_MAIN(tst_QSharedPointer)
|
||||||
#include "tst_qsharedpointer.moc"
|
#include "tst_qsharedpointer.moc"
|
||||||
|
Loading…
Reference in New Issue
Block a user