0

Do not allow dynamic_extent for count argument in two=arg subspan().

Allows some significant branch avoidance in cases where the compiler did
not have a fixed value for comparison at the cost of a small break with
what std::span allows (basically, allowing a sentinel value that means
"arg not present" as an explicit argument).

-- Fix one test that relied on this behavior.

Change-Id: Idaeb1c3019333d6fdfd317a1349290fac5c5f848
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6282431
Reviewed-by: David Benjamin <davidben@chromium.org>
Reviewed-by: Peter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1424693}
This commit is contained in:
Tom Sepez
2025-02-25 11:42:44 -08:00
committed by Chromium LUCI CQ
parent d9df495795
commit 1c8da0f656
2 changed files with 11 additions and 23 deletions
base/containers
components/autofill/core/browser/foundations

@ -227,6 +227,8 @@
// Differences from [span.sub]:
// - As in [span.cons], `size_t` parameters are changed to
// `StrictNumeric<size_type>`.
// - There are separate overloads for one-arg and two-arg forms of subspan,
// and the two-arg form does not accept dynamic_extent as a count.
// - For convenience, provides `span::split_at()` to split a single span into
// two at a given offset.
// - For convenience, provides `span::take_first[_elem]()` to remove the first
@ -730,16 +732,10 @@ class GSL_POINTER span {
}
constexpr auto subspan(StrictNumeric<size_type> offset,
StrictNumeric<size_type> count) const {
CHECK_LE(size_type{offset}, extent);
const size_type remaining = extent - size_type{offset};
if (count == dynamic_extent) {
// SAFETY: `data()` points to at least `extent` elements, so `offset`
// specifies a valid element index or the past-the-end index, and
// `remaining` cannot index past-the-end elements.
return UNSAFE_BUFFERS(
span<element_type>(data() + size_type{offset}, remaining));
}
CHECK_LE(size_type{count}, remaining);
DCHECK(size_type{count} != dynamic_extent)
<< "base does not allow dynamic_extent in two-arg subspan()";
CHECK(size_type{offset} <= size() &&
size_type{count} <= size() - size_type{offset});
// SAFETY: `data()` points to at least `extent` elements, so `offset`
// specifies a valid element index or the past-the-end index, and `count` is
// no larger than the number of remaining valid elements.
@ -1170,16 +1166,10 @@ class GSL_POINTER span<ElementType, dynamic_extent, InternalPtrType> {
}
constexpr auto subspan(StrictNumeric<size_type> offset,
StrictNumeric<size_type> count) const {
CHECK_LE(size_type{offset}, size());
const size_type remaining = size() - size_type{offset};
if (count == dynamic_extent) {
// SAFETY: `data()` points to at least `size()` elements, so `offset`
// specifies a valid element index or the past-the-end index, and
// `remaining` cannot index past-the-end elements.
return UNSAFE_BUFFERS(
span<element_type>(data() + size_type{offset}, remaining));
}
CHECK_LE(size_type{count}, remaining);
DCHECK(size_type{count} != dynamic_extent)
<< "base does not allow dynamic_extent in two-arg subspan()";
CHECK(size_type{offset} <= size() &&
size_type{count} <= size() - size_type{offset});
// SAFETY: `data()` points to at least `size()` elements, so `offset`
// specifies a valid element index or the past-the-end index, and `count` is
// no larger than the number of remaining valid elements.

@ -492,9 +492,7 @@ class FormForestTestWithMockedTree : public FormForestTest {
if (f.begin >= source.fields().size()) {
continue;
}
if (f.begin + f.count > source.fields().size()) {
f.count = base::dynamic_extent;
}
f.count = std::min(f.count, source.fields().size() - f.begin);
std::ranges::copy(base::span(source.fields()).subspan(f.begin, f.count),
std::back_inserter(fields));
}