diff --git a/src/corelib/tools/qspan.h b/src/corelib/tools/qspan.h index d6ae2570ae3..2671ba374fe 100644 --- a/src/corelib/tools/qspan.h +++ b/src/corelib/tools/qspan.h @@ -433,6 +433,29 @@ public: [[nodiscard]] constexpr QSpan sliced(size_type pos) const { return subspan(pos); } [[nodiscard]] constexpr QSpan sliced(size_type pos, size_type n) const { return subspan(pos, n); } +private: + // [span.objectrep] + [[nodiscard]] friend + QSpan + as_bytes(QSpan s) noexcept + { + using R = QSpan; + return R{reinterpret_cast(s.data()), s.size_bytes()}; + } + + template + using if_mutable = std::enable_if_t, bool>; + +#ifndef Q_QDOC + template = true> +#endif + [[nodiscard]] friend + QSpan + as_writable_bytes(QSpan s) noexcept + { + using R = QSpan; + return R{reinterpret_cast(s.data()), s.size_bytes()}; + } }; // class QSpan // [span.deduct] diff --git a/src/corelib/tools/qspan.qdoc b/src/corelib/tools/qspan.qdoc index 6aaa386cafb..9b55b09bf75 100644 --- a/src/corelib/tools/qspan.qdoc +++ b/src/corelib/tools/qspan.qdoc @@ -647,3 +647,37 @@ \sa subspan(), first(QSpan::size_type), last(QSpan::size_type) */ +/*! + \fn template auto QSpan::as_bytes(QSpan s) + \since 6.8 + + Returns \a s as a \c{QSpan} whose size() is equal to + \c{s.size_bytes()}. + + If \c{E} is \c{std::dynamic_extent} then so is \c{E'}. + Otherwise, \c{E' = E * sizeof(T)}. + + \note \c{q20::dynamic_extent} is a C++17 backport of C++20's + \l{https://en.cppreference.com/w/cpp/container/span/dynamic_extent}{\c{std::dynamic_extent}}. + + \sa as_writable_bytes(), size_bytes() +*/ + +/*! + \fn template auto QSpan::as_writable_bytes(QSpan s) + \since 6.8 + + Returns \a s as a \c{QSpan} whose size() is equal to + \c{s.size_bytes()}. + + If \c{E} is \c{std::dynamic_extent} then so is \c{E'}. + Otherwise, \c{E' = E * sizeof(T)}. + + \note This function participates in overload resolution only if + \c{!std::is_const_v}. + + \note \c{q20::dynamic_extent} is a C++17 backport of C++20's + \l{https://en.cppreference.com/w/cpp/container/span/dynamic_extent}{\c{std::dynamic_extent}}. + + \sa as_bytes(), size_bytes() +*/ diff --git a/tests/auto/corelib/tools/qspan/tst_qspan.cpp b/tests/auto/corelib/tools/qspan/tst_qspan.cpp index 83ff252b099..c7456ac7f27 100644 --- a/tests/auto/corelib/tools/qspan/tst_qspan.cpp +++ b/tests/auto/corelib/tools/qspan/tst_qspan.cpp @@ -141,6 +141,9 @@ private: void from_variable_size_container_impl(C &&c) const; }; +template +const void *as_const_void(T *p) noexcept { return static_cast(p); } + #define RETURN_IF_FAILED() \ do { if (QTest::currentTestFailed()) return; } while (false) @@ -334,6 +337,8 @@ void tst_QSpan::from_container_impl(C &&c) const const auto c_data = QSpanPrivate::adl_data(c); using V = std::remove_reference_t>; + constexpr auto ExpectedBytesExtent + = ExpectedExtent == q20::dynamic_extent ? q20::dynamic_extent : ExpectedExtent * sizeof(V); { QSpan si = c; // CTAD static_assert(std::is_same_v>); @@ -344,6 +349,20 @@ void tst_QSpan::from_container_impl(C &&c) const check_nonempty_span(si, c_size); RETURN_IF_FAILED(); + auto bi = as_bytes(si); + static_assert(std::is_same_v>); + QCOMPARE_EQ(bi.size(), si.size_bytes()); + QCOMPARE_EQ(as_const_void(bi.data()), + as_const_void(si.data())); + + if constexpr (!std::is_const_v) { // e.g. std::initializer_list + auto wbi = as_writable_bytes(si); + static_assert(std::is_same_v>); + QCOMPARE_EQ(wbi.size(), si.size_bytes()); + QCOMPARE_EQ(as_const_void(wbi.data()), + as_const_void(si.data())); + } + QSpan sci = c; QCOMPARE_EQ(sci.size(), c_size); @@ -351,6 +370,12 @@ void tst_QSpan::from_container_impl(C &&c) const check_nonempty_span(sci, c_size); RETURN_IF_FAILED(); + + auto bci = as_bytes(sci); + static_assert(std::is_same_v>); + QCOMPARE_EQ(bci.size(), sci.size_bytes()); + QCOMPARE_EQ(as_const_void(bci.data()), + as_const_void(sci.data())); } { QSpan sci = std::as_const(c); // CTAD @@ -361,6 +386,12 @@ void tst_QSpan::from_container_impl(C &&c) const check_nonempty_span(sci, c_size); RETURN_IF_FAILED(); + + auto bci = as_bytes(sci); + static_assert(std::is_same_v>); + QCOMPARE_EQ(bci.size(), sci.size_bytes()); + QCOMPARE_EQ(as_const_void(bci.data()), + as_const_void(sci.data())); } }