QSpan: don't detach Qt containers
When converting an implicitly-shared Qt container to QSpan, the QSpan ctor would call .data(), which detaches said Qt container (if it's not const). This is what must happen for mutable spans (QSpan<int>), but is not necessary for non-mutable spans (QSpan<const int>). Fix by copying the potential const from QSpan::element_type to the Range object in the resp. QSpan ctor. This makes a QSpan over a const element_type mark the range const before passing it to adl_data() (= member-data()). For a non-const element_type, nothing changes. [ChangeLog][QtCore][QSpan] No longer detaches implicitly-shared Qt containers converted to QSpan<const T, N>. Note that std::span<const T, N> will, however, detach such containers, so we recommend to use std::as_const() with implcitly-shared Qt containers, as always. Fixes: QTBUG-132133 Pick-to: 6.9 Change-Id: I9fdae20994d2c900bc5b45b44db3901d10f8838a Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
793309693a
commit
287234704b
@ -44,6 +44,10 @@ QT_END_INCLUDE_NAMESPACE
|
||||
|
||||
namespace QSpanPrivate {
|
||||
|
||||
template <typename From, typename To>
|
||||
std::conditional_t<std::is_const_v<From>, const To &, To &> // like [forward]/6.1 COPY_CONST
|
||||
const_propagated(To &in) { return in; }
|
||||
|
||||
template <typename T, std::size_t E> class QSpanBase;
|
||||
|
||||
template <typename T>
|
||||
@ -208,7 +212,7 @@ public:
|
||||
|
||||
template <typename Range, typename Base::template if_compatible_range<Range> = true>
|
||||
Q_IMPLICIT constexpr QSpanBase(Range &&r)
|
||||
: QSpanBase(QSpanPrivate::adl_data(r), // no forward<>() here (std doesn't have it, either)
|
||||
: QSpanBase(QSpanPrivate::adl_data(QSpanPrivate::const_propagated<T>(r)), // no forward<>() here (std doesn't have it, either)
|
||||
qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>()
|
||||
{}
|
||||
|
||||
@ -280,7 +284,7 @@ public:
|
||||
|
||||
template <typename Range, typename Base::template if_compatible_range<Range> = true>
|
||||
Q_IMPLICIT constexpr QSpanBase(Range &&r)
|
||||
: QSpanBase(QSpanPrivate::adl_data(r), // no forward<>() here (std doesn't have it, either)
|
||||
: QSpanBase(QSpanPrivate::adl_data(QSpanPrivate::const_propagated<T>(r)), // no forward<>() here (std doesn't have it, either)
|
||||
qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>()
|
||||
{}
|
||||
|
||||
|
@ -104,6 +104,7 @@
|
||||
\list
|
||||
\li QSpan is using the signed qsizetype as \c{size_type}
|
||||
whereas \c{std::span} uses \c{size_t}.
|
||||
\li (since Qt 6.9) \c{QSpan<const T>} doesn't detach Qt containers, \c{std::span} does.
|
||||
\li All QSpan constructors are implicit;
|
||||
many \c{std::span} ones are \c{explicit}.
|
||||
\li QSpan can be constructed from rvalue owning containers, \c{std::span} can not.
|
||||
|
@ -478,7 +478,6 @@ void tst_QSpan::constQSpansDontDetachQtContainers() const
|
||||
[[maybe_unused]] const QList copy = li;
|
||||
QVERIFY(!li.isDetached());
|
||||
[[maybe_unused]] QSpan<const int> cvspan = li; // should not detach (QTBUG-132133)
|
||||
QEXPECT_FAIL("", "QTBUG-132133", Continue);
|
||||
QVERIFY(!li.isDetached());
|
||||
[[maybe_unused]] QSpan<int> mvspan = li; // this _has_ to detach, though
|
||||
QVERIFY(li.isDetached());
|
||||
@ -489,7 +488,6 @@ void tst_QSpan::constQSpansDontDetachQtContainers() const
|
||||
[[maybe_unused]] const QList copy = li;
|
||||
QVERIFY(!li.isDetached());
|
||||
[[maybe_unused]] QSpan<const int, 4> cfspan = li; // should not detach (QTBUG-132133)
|
||||
QEXPECT_FAIL("", "QTBUG-132133", Continue);
|
||||
QVERIFY(!li.isDetached());
|
||||
[[maybe_unused]] QSpan<int, 4> mfspan = li; // this _has_ to detach, though
|
||||
QVERIFY(li.isDetached());
|
||||
|
Loading…
x
Reference in New Issue
Block a user