Skip to content

Commit

Permalink
QSpan: add missing slice() and chop()
Browse files Browse the repository at this point in the history
When 9bf68a4 and
8f68bd9 added action versions of the
sliced() transformation to QString/QByteArray and the string views,
QSpan, which also has sliced(), was forgotten.

Add slice(), and since QSpan recently gained chopped(), also add
chop() (which the other Qt classes had for ages).

These functions only make sense on variable-sized spans, so constrain
them. I don't want these functions to be templates, because
subspan-ish functions that return fixed-size spans (e.g. last<10>())
take numbers as template arguments, and that's possible here, too, but
wrong. So in C++20, use a requires clause that allows to constrain a
non-template, so users won't be tempted to pass template arguments.

OTOH, I don't want stuff to accidentally compile in C++17 mode (these
functions do compile, but are unable to meet their preconditions,
unless you pass 0) and then hit a runtime error, or SFINAE out in
C++20, so I need to support C++17 constraints, too. Used a macro to
paper over the difference.

Documentation will come as a follow-up, since this author is still
fighting qdoc there, and the Qt 6.9 feature freeze is looming.

[ChangeLog][QtCore][QSpan] Added slice() and chop(), being in-place
versions of sliced() and chopped(), resp.

Fixes: QTBUG-131672
Change-Id: I5832744584549c19e5e25ef8215484874f77af02
Reviewed-by: Ivan Solovev <[email protected]>
  • Loading branch information
marcmutz committed Dec 5, 2024
1 parent 43e166b commit 7b00975
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
21 changes: 21 additions & 0 deletions src/corelib/tools/qspan.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,27 @@ class QSpan
[[nodiscard]] constexpr QSpan<T> sliced(size_type pos, size_type n) const { return subspan(pos, n); }
[[nodiscard]] constexpr QSpan<T> chopped(size_type n) const { verify(0, n); return first(size() - n); }

#ifdef __cpp_concepts
# define QT_ONLY_IF_DYNAMIC_SPAN(DECL) \
DECL requires(E == q20::dynamic_extent)
#else
# define QT_ONLY_IF_DYNAMIC_SPAN(DECL) \
template <size_t M = E, typename = std::enable_if_t<M == q20::dynamic_extent>> DECL
#endif
QT_ONLY_IF_DYNAMIC_SPAN(
constexpr void slice(size_type pos)
)
{ *this = sliced(pos); }
QT_ONLY_IF_DYNAMIC_SPAN(
constexpr void slice(size_type pos, size_type n)
)
{ *this = sliced(pos, n); }
QT_ONLY_IF_DYNAMIC_SPAN(
constexpr void chop(size_type n)
)
{ *this = chopped(n); }
#undef QT_ONLY_IF_DYNAMIC_SPAN

private:
// [span.objectrep]
[[nodiscard]] friend
Expand Down
23 changes: 22 additions & 1 deletion tests/auto/corelib/tools/qspan/tst_qspan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ private Q_SLOTS:
void fromInitList() const;

private:
template <typename T, std::size_t N, typename S, std::size_t M>
void check_identical(QSpan<T, N> lhs, QSpan<S, M> rhs) const;
template <typename T, std::size_t N>
void check_nonempty_span(QSpan<T, N>, qsizetype expectedSize) const;
template <typename T, std::size_t N>
Expand Down Expand Up @@ -191,6 +193,13 @@ void tst_QSpan::zeroExtentSpansMaintainADataPointer() const
check_empty_span_incl_subspans(sdci);
}

template<typename T, std::size_t N, typename S, std::size_t M>
void tst_QSpan::check_identical(QSpan<T, N> lhs, QSpan<S, M> rhs) const
{
QCOMPARE_EQ(lhs.data(), rhs.data());
QCOMPARE_EQ(lhs.size(), rhs.size());
}

template <typename T, std::size_t N>
void tst_QSpan::check_nonempty_span(QSpan<T, N> s, qsizetype expectedSize) const
{
Expand Down Expand Up @@ -220,7 +229,19 @@ void tst_QSpan::check_nonempty_span(QSpan<T, N> s, qsizetype expectedSize) const
QCOMPARE_EQ(std::addressof(s.back()), std::addressof(*s.crbegin()));
QCOMPARE_EQ(std::addressof(s.back()), std::addressof(s[s.size() - 1]));

// ### more?
if constexpr (N == q20::dynamic_extent) {
auto sc = s;
sc.chop(1);
check_identical(sc, s.chopped(1));

auto ss = s;
ss.slice(1);
check_identical(ss, s.sliced(1));

auto s2 = s;
s2.slice(0, 1);
check_identical(s2, s.sliced(0, 1));
}

if (expectedSize == 1) {
// don't run into Mandates: Offset >= Extent
Expand Down

0 comments on commit 7b00975

Please sign in to comment.