Skip to content

Commit 5345f0b

Browse files
pkastingchromeos-ci-prod
authored and
chromeos-ci-prod
committed
Slight span helper improvements.
* Use CTAD rather than `make_span()` in some span helpers. * Combine two `make_span()` overrides into one that better matches the actual span constructors, to make further removal more mechanical. * Add a few constraints that were already checked by underlying helpers, but not by those that called them; won't change what compiles, but hopefully will make errors give the underlying issue sooner. * Stop supporting rvalue arrays for as_writable_byte_span(). It doesn't make much sense to want a writable span created from an rvalue, and we don't really support it elsewhere. * Fix oversight in SpanReader deduction guide that didn't support raw_spans. Bug: 364987728 Change-Id: If8b7f151fee4b5416cce8f3d6e66e83c30bf1741 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5962112 Auto-Submit: Peter Kasting <[email protected]> Commit-Queue: Peter Kasting <[email protected]> Reviewed-by: danakj <[email protected]> Code-Coverage: [email protected] <[email protected]> Cr-Commit-Position: refs/heads/main@{#1375433} CrOS-Libchrome-Original-Commit: 866b397d72d22bbc587896fd98c9a281cc915580
1 parent 31922e7 commit 5345f0b

File tree

4 files changed

+35
-53
lines changed

4 files changed

+35
-53
lines changed

base/containers/span.h

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ concept LegalDataConversion =
7474
std::is_convertible_v<std::remove_reference_t<From> (*)[],
7575
std::remove_reference_t<To> (*)[]>;
7676

77+
// Akin to `std::constructible_from<span, T>`, but meant to be used in a
78+
// type-deducing context where we don't know what args would be deduced;
79+
// `std::constructible_from` can't be directly used in such a case since the
80+
// type parameters must be fully-specified (e.g. `span<int>`), requiring us to
81+
// have that knowledge already.
82+
template <typename T>
83+
concept SpanConstructibleFrom = requires(const T& t) { span(t); };
84+
7785
template <typename T, typename It>
7886
concept CompatibleIter = std::contiguous_iterator<It> &&
7987
LegalDataConversion<std::iter_reference_t<It>, T>;
@@ -1488,42 +1496,20 @@ auto as_writable_chars(span<T, X, InternalPtrType> s) noexcept {
14881496
span<char, N>(reinterpret_cast<char*>(s.data()), s.size_bytes()));
14891497
}
14901498

1491-
// Type-deducing helper for constructing a span.
1492-
//
1493-
// # Safety
1494-
// The contiguous iterator `it` must point to the first element of at least
1495-
// `size` many elements or Undefined Behaviour may result as the span may give
1496-
// access beyond the bounds of the collection pointed to by `it`.
1497-
template <int&... ExplicitArgumentBarrier, typename It>
1498-
UNSAFE_BUFFER_USAGE constexpr auto make_span(
1499-
It it,
1500-
StrictNumeric<size_t> size) noexcept {
1501-
using T = std::remove_reference_t<std::iter_reference_t<It>>;
1502-
// SAFETY: The caller guarantees that `it` is the first of at least `size`
1503-
// many elements.
1504-
return UNSAFE_BUFFERS(span<T>(it, size));
1505-
}
1506-
15071499
// Type-deducing helper for constructing a span.
15081500
// Deprecated: Use CTAD (i.e. use `span()` directly without template arguments).
15091501
// TODO(crbug.com/341907909): Remove.
15101502
//
1511-
// # Checks
1512-
// The function CHECKs that `it <= end` and will terminate otherwise.
1513-
//
1514-
// # Safety
1515-
// The contiguous iterator `it` and its end sentinel `end` must be for the same
1516-
// allocation or Undefined Behaviour may result as the span may give access
1517-
// beyond the bounds of the collection pointed to by `it`.
1518-
template <int&... ExplicitArgumentBarrier,
1519-
typename It,
1520-
typename End,
1521-
typename = std::enable_if_t<!std::is_convertible_v<End, size_t>>>
1522-
UNSAFE_BUFFER_USAGE constexpr auto make_span(It it, End end) noexcept {
1523-
using T = std::remove_reference_t<std::iter_reference_t<It>>;
1524-
// SAFETY: The caller guarantees that `it` and `end` are iterators of the
1525-
// same allocation.
1526-
return UNSAFE_BUFFERS(span<T>(it, end));
1503+
// SAFETY: `it` must point to the first of a (possibly-empty) series of
1504+
// contiguous valid elements. If `end_or_size` is a size, the series must
1505+
// contain at least that many valid elements; if it is an iterator or sentinel,
1506+
// it must refer to the same allocation, and all elements in the range [it,
1507+
// end_or_size) must be valid. Otherwise, the span will allow access to invalid
1508+
// elements, resulting in UB.
1509+
template <int&... ExplicitArgumentBarrier, typename It, typename EndOrSize>
1510+
requires(std::contiguous_iterator<It>)
1511+
UNSAFE_BUFFER_USAGE constexpr auto make_span(It it, EndOrSize end_or_size) {
1512+
return UNSAFE_BUFFERS(span(it, end_or_size));
15271513
}
15281514

15291515
// make_span utility function that deduces both the span's value_type and extent
@@ -1533,6 +1519,7 @@ UNSAFE_BUFFER_USAGE constexpr auto make_span(It it, End end) noexcept {
15331519
// Deprecated: Use CTAD (i.e. use `span()` directly without template arguments).
15341520
// TODO(crbug.com/341907909): Remove.
15351521
template <int&... ExplicitArgumentBarrier, typename Container>
1522+
requires(internal::SpanConstructibleFrom<Container>)
15361523
constexpr auto make_span(Container&& container) noexcept {
15371524
return span(std::forward<Container>(container));
15381525
}
@@ -1664,9 +1651,9 @@ constexpr span<const uint8_t, N> byte_span_with_nul_from_cstring(
16641651
// or vector-like objects holding other scalar types, prior to passing them
16651652
// into an API that requires byte spans.
16661653
template <int&... ExplicitArgumentBarrier, typename Spannable>
1667-
requires requires(const Spannable& arg) { make_span(arg); }
1654+
requires(internal::SpanConstructibleFrom<Spannable>)
16681655
constexpr auto as_byte_span(const Spannable& arg) {
1669-
return as_bytes(make_span(arg));
1656+
return as_bytes(span(arg));
16701657
}
16711658

16721659
template <int&... ExplicitArgumentBarrier, typename T, size_t N>
@@ -1681,26 +1668,20 @@ constexpr span<const uint8_t, N * sizeof(T)> as_byte_span(
16811668
// or vector-like objects holding other scalar types, prior to passing them
16821669
// into an API that requires mutable byte spans.
16831670
template <int&... ExplicitArgumentBarrier, typename Spannable>
1684-
requires requires(Spannable&& arg) {
1685-
make_span(arg);
1686-
requires !std::is_const_v<typename decltype(make_span(arg))::element_type>;
1687-
}
1671+
requires(internal::SpanConstructibleFrom<Spannable> &&
1672+
!std::is_const_v<typename decltype(span(
1673+
std::declval<Spannable>()))::element_type>)
16881674
constexpr auto as_writable_byte_span(Spannable&& arg) {
1689-
return as_writable_bytes(make_span(std::forward<Spannable>(arg)));
1675+
return as_writable_bytes(span(std::forward<Spannable>(arg)));
16901676
}
16911677

16921678
// This overload for arrays preserves the compile-time size N of the array in
16931679
// the span type signature span<uint8_t, N>.
16941680
template <int&... ExplicitArgumentBarrier, typename T, size_t N>
1681+
requires(!std::is_const_v<T>)
16951682
constexpr span<uint8_t, N * sizeof(T)> as_writable_byte_span(
16961683
T (&arr LIFETIME_BOUND)[N]) {
1697-
return as_writable_bytes(make_span(arr));
1698-
}
1699-
1700-
template <int&... ExplicitArgumentBarrier, typename T, size_t N>
1701-
constexpr span<uint8_t, N * sizeof(T)> as_writable_byte_span(
1702-
T (&&arr LIFETIME_BOUND)[N]) {
1703-
return as_writable_bytes(make_span(arr));
1684+
return as_writable_bytes(span(arr));
17041685
}
17051686

17061687
namespace internal {

base/containers/span_nocompile.nc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ void StdSetConversionDisallowed() {
9393
span<int> span1(set.begin(), 0u); // expected-error {{no matching constructor for initialization of 'span<int>'}}
9494
span<int> span2(set.begin(), set.end()); // expected-error {{no matching constructor for initialization of 'span<int>'}}
9595
span<int> span3(set); // expected-error {{no matching constructor for initialization of 'span<int>'}}
96-
auto span4 = make_span(set.begin(), 0u); // expected-error@*:* {{no matching constructor for initialization of 'span<T>' (aka 'span<const int>')}}
97-
auto span5 = make_span(set.begin(), set.end()); // expected-error@*:* {{no matching constructor for initialization of 'span<T>' (aka 'span<const int>')}}
98-
auto span6 = make_span(set); // expected-error@*:* {{no viable constructor or deduction guide for deduction of template arguments of 'span'}}
96+
auto span4 = make_span(set.begin(), 0u); // expected-error@*:* {{no matching function for call to 'make_span'}}
97+
auto span5 = make_span(set.begin(), set.end()); // expected-error@*:* {{no matching function for call to 'make_span'}}
98+
auto span6 = make_span(set); // expected-error@*:* {{no matching function for call to 'make_span'}}
9999
}
100100

101101
// Static views of spans with static extent must not exceed the size.

base/containers/span_reader.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,8 @@ class SpanReader {
281281
size_t original_size_;
282282
};
283283

284-
template <class T, size_t N>
285-
SpanReader(span<T, N>) -> SpanReader<T>;
284+
template <typename T, size_t N, typename InternalPtrType>
285+
SpanReader(span<T, N, InternalPtrType>) -> SpanReader<T>;
286286

287287
} // namespace base
288288

base/containers/span_unittest.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1940,15 +1940,16 @@ TEST(SpanTest, AsWritableByteSpan) {
19401940
EXPECT_EQ(byte_span.data(), reinterpret_cast<uint8_t*>(kMutVec.data()));
19411941
EXPECT_EQ(byte_span.size(), kMutVec.size() * sizeof(int));
19421942
}
1943-
// Rvalue input.
1943+
// Result can be passed as rvalue.
19441944
{
1945+
int kMutArray[] = {2, 3, 5, 7, 11, 13};
19451946
[](auto byte_span) {
19461947
static_assert(
19471948
std::is_same_v<decltype(byte_span), span<uint8_t, 6u * sizeof(int)>>);
19481949
EXPECT_EQ(byte_span.size(), 6u * sizeof(int));
19491950
// Little endian puts the low bits in the first byte.
19501951
EXPECT_EQ(byte_span[0u], 2);
1951-
}(as_writable_byte_span({2, 3, 5, 7, 11, 13}));
1952+
}(as_writable_byte_span(kMutArray));
19521953
}
19531954
}
19541955

0 commit comments

Comments
 (0)