QSpan: add as_(writable_)bytes
For std::span, these are free functions in namespace std and therefore work for anything implicitly convertible to std::span, incl. QSpan. But they're C++20, QSpan needs something for C++17 builds. By adding them as hidden friends for QSpan, we allow unqualifid calls to transparently resolve to the respective overload, ensuring source-compatibility between std:: and QSpan, and, eventually, a transition back to std::as_*_bytes. I considered the alternative to add these functions in the q20 namespace, but q20::as_bytes() would have to take QSpan, and QSpan is convertible from more types than std::span, so we wouldn't be able to guarantee that std::as_bytes(t) works for all T t for which q20::as_bytes(t) works, the fundamental guarantee for namespace qNN. [ChangeLog][QtCore][QSpan] Added std::span-style as_bytes() and as_writable_bytes() functions. Fixes: QTBUG-125489 Change-Id: Ia9a7560c7843e182892608178433be7349c825ba Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
71bc951870
commit
462c958a92
@ -433,6 +433,29 @@ public:
|
||||
[[nodiscard]] constexpr QSpan<T> sliced(size_type pos) const { return subspan(pos); }
|
||||
[[nodiscard]] constexpr QSpan<T> sliced(size_type pos, size_type n) const { return subspan(pos, n); }
|
||||
|
||||
private:
|
||||
// [span.objectrep]
|
||||
[[nodiscard]] friend
|
||||
QSpan<const std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>
|
||||
as_bytes(QSpan s) noexcept
|
||||
{
|
||||
using R = QSpan<const std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>;
|
||||
return R{reinterpret_cast<const std::byte *>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
using if_mutable = std::enable_if_t<!std::is_const_v<U>, bool>;
|
||||
|
||||
#ifndef Q_QDOC
|
||||
template <typename T2 = T, if_mutable<T2> = true>
|
||||
#endif
|
||||
[[nodiscard]] friend
|
||||
QSpan<std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>
|
||||
as_writable_bytes(QSpan s) noexcept
|
||||
{
|
||||
using R = QSpan<std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>;
|
||||
return R{reinterpret_cast<std::byte *>(s.data()), s.size_bytes()};
|
||||
}
|
||||
}; // class QSpan
|
||||
|
||||
// [span.deduct]
|
||||
|
@ -647,3 +647,37 @@
|
||||
\sa subspan(), first(QSpan<T,E>::size_type), last(QSpan<T,E>::size_type)
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T, size_t E> auto QSpan<T, E>::as_bytes(QSpan s)
|
||||
\since 6.8
|
||||
|
||||
Returns \a s as a \c{QSpan<const std::byte, E'>} 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 <typename T, size_t E> auto QSpan<T, E>::as_writable_bytes(QSpan s)
|
||||
\since 6.8
|
||||
|
||||
Returns \a s as a \c{QSpan<std::byte, E'>} 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<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_bytes(), size_bytes()
|
||||
*/
|
||||
|
@ -141,6 +141,9 @@ private:
|
||||
void from_variable_size_container_impl(C &&c) const;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const void *as_const_void(T *p) noexcept { return static_cast<const void *>(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<QSpanPrivate::range_reference_t<C>>;
|
||||
constexpr auto ExpectedBytesExtent
|
||||
= ExpectedExtent == q20::dynamic_extent ? q20::dynamic_extent : ExpectedExtent * sizeof(V);
|
||||
{
|
||||
QSpan si = c; // CTAD
|
||||
static_assert(std::is_same_v<decltype(si), QSpan<V, ExpectedExtent>>);
|
||||
@ -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<decltype(bi), QSpan<const std::byte, ExpectedBytesExtent>>);
|
||||
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<V>) { // e.g. std::initializer_list<int>
|
||||
auto wbi = as_writable_bytes(si);
|
||||
static_assert(std::is_same_v<decltype(wbi), QSpan<std::byte, ExpectedBytesExtent>>);
|
||||
QCOMPARE_EQ(wbi.size(), si.size_bytes());
|
||||
QCOMPARE_EQ(as_const_void(wbi.data()),
|
||||
as_const_void(si.data()));
|
||||
}
|
||||
|
||||
QSpan<const int> 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<decltype(bci), QSpan<const std::byte>>);
|
||||
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<decltype(bci), QSpan<const std::byte, ExpectedBytesExtent>>);
|
||||
QCOMPARE_EQ(bci.size(), sci.size_bytes());
|
||||
QCOMPARE_EQ(as_const_void(bci.data()),
|
||||
as_const_void(sci.data()));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user