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
|
||||
*/
|
||||
|
||||
/*!
|
||||
\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()
|
||||
|
||||
|
@ -72,6 +72,19 @@ public:
|
||||
|
||||
template <typename... 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>
|
||||
@ -108,6 +121,19 @@ public:
|
||||
|
||||
QSharedPointer<T> toStrongRef() 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>
|
||||
|
@ -444,6 +444,23 @@ public:
|
||||
#undef DECLARE_TEMPLATE_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:
|
||||
Q_NODISCARD_CTOR
|
||||
explicit QSharedPointer(Qt::Initialization) {}
|
||||
@ -684,6 +701,23 @@ public:
|
||||
friend bool operator!=(std::nullptr_t, const QWeakPointer &p)
|
||||
{ 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:
|
||||
friend struct QtPrivate::EnableInternalData;
|
||||
template <class X> friend class QSharedPointer;
|
||||
|
@ -91,6 +91,7 @@ private slots:
|
||||
void invalidConstructs_data();
|
||||
void invalidConstructs();
|
||||
#endif
|
||||
void ownerComparisons();
|
||||
|
||||
// let invalidConstructs be the last test, because it's the slowest;
|
||||
// add new tests above this block
|
||||
@ -2841,5 +2842,140 @@ void tst_QSharedPointer::overloads()
|
||||
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)
|
||||
#include "tst_qsharedpointer.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user