Skip to content

Commit 8117c34

Browse files
pkastingchromeos-ci-prod
authored andcommitted
Minor span API tweaks, part 1.
* Make CTAD deduce fixed-extent spans in more cases, matching std::span. * Tweak a few `std::convertible_to`s back to `std::is_convertible_v`, which is a slight behavior relaxation; this is primarily to match std::span so we never have weird edge-case conversion issues. * Be consistent about whether `constexpr` or `explicit` comes first. (Purely aesthetic.) * Make the array constructors take the type in a non-deduced context. This matches the std::span fix for https://cplusplus.github.io/LWG/issue3369 and ensures we won't regress as we tweak CTAD etc. * Remove `noexcept` on some constructors, again to match `std::span`. Unconditionally using `noexcept` isn't necessarily desirable, even though we disable exceptions. It can pessimize code (see https://16bpp.net/blog/post/noexcept-can-sometimes-help-or-hurt-performance/), and it's not advised by the Google Style Guide (see https://google.github.io/styleguide/cppguide.html#noexcept), which suggests only using it unconditionally on move constructors, and testing real performance otherwise. Bug: 364987728 Change-Id: I6e3060d4838b74388fc134055ac4a6d8a0354680 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5961259 Code-Coverage: [email protected] <[email protected]> Auto-Submit: Peter Kasting <[email protected]> Commit-Queue: Daniel Cheng <[email protected]> Reviewed-by: Daniel Cheng <[email protected]> Cr-Commit-Position: refs/heads/main@{#1374024} CrOS-Libchrome-Original-Commit: 594c8cc5372c4667579c5c6ca59a6f3f10be20ff
1 parent fbeed0b commit 8117c34

File tree

2 files changed

+38
-17
lines changed

2 files changed

+38
-17
lines changed

base/containers/span.h

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,27 @@ namespace base {
5252

5353
namespace internal {
5454

55+
// Exposition-only concept from [span.syn]
56+
template <typename T>
57+
concept IntegralConstantLike =
58+
std::is_integral_v<decltype(T::value)> &&
59+
!std::is_same_v<bool, std::remove_const_t<decltype(T::value)>> &&
60+
std::convertible_to<T, decltype(T::value)> &&
61+
std::equality_comparable_with<T, decltype(T::value)> &&
62+
std::bool_constant<T() == T::value>::value &&
63+
std::bool_constant<static_cast<decltype(T::value)>(T()) == T::value>::value;
64+
65+
// Exposition-only concept from [span.syn]
66+
template <typename T>
67+
inline constexpr size_t MaybeStaticExt = dynamic_extent;
68+
template <typename T>
69+
requires IntegralConstantLike<T>
70+
inline constexpr size_t MaybeStaticExt<T> = {T::value};
71+
5572
template <typename From, typename To>
5673
concept LegalDataConversion =
57-
std::convertible_to<std::remove_reference_t<From> (*)[],
58-
std::remove_reference_t<To> (*)[]>;
74+
std::is_convertible_v<std::remove_reference_t<From> (*)[],
75+
std::remove_reference_t<To> (*)[]>;
5976

6077
template <typename T, typename It>
6178
concept CompatibleIter = std::contiguous_iterator<It> &&
@@ -263,9 +280,6 @@ constexpr std::ostream& span_stream(std::ostream& l, span<T, N> r);
263280
// - operator<=>() comparator function.
264281
// - operator<<() printing function.
265282
//
266-
// Furthermore, all constructors and methods are marked noexcept due to the lack
267-
// of exceptions in Chromium.
268-
//
269283
// Due to the lack of class template argument deduction guides in C++14
270284
// appropriate make_span() utility functions are provided for historic reasons.
271285

@@ -302,9 +316,8 @@ class GSL_POINTER span {
302316
// valid range of the collection pointed to by the iterator.
303317
template <typename It>
304318
requires(internal::CompatibleIter<T, It>)
305-
UNSAFE_BUFFER_USAGE explicit constexpr span(
306-
It first,
307-
StrictNumeric<size_t> count) noexcept
319+
UNSAFE_BUFFER_USAGE constexpr explicit span(It first,
320+
StrictNumeric<size_t> count)
308321
: // The use of to_address() here is to handle the case where the
309322
// iterator `first` is pointing to the container's `end()`. In that
310323
// case we can not use the address returned from the iterator, or
@@ -347,8 +360,8 @@ class GSL_POINTER span {
347360
template <typename It, typename End>
348361
requires(internal::CompatibleIter<T, It> &&
349362
std::sized_sentinel_for<End, It> &&
350-
!std::convertible_to<End, size_t>)
351-
UNSAFE_BUFFER_USAGE explicit constexpr span(It begin, End end) noexcept
363+
!std::is_convertible_v<End, size_t>)
364+
UNSAFE_BUFFER_USAGE constexpr explicit span(It begin, End end)
352365
// SAFETY: The caller must guarantee that the iterator and end sentinel
353366
// are part of the same allocation, in which case it is the number of
354367
// elements between the iterators and thus a valid size for the pointer to
@@ -364,7 +377,7 @@ class GSL_POINTER span {
364377
}
365378

366379
// NOLINTNEXTLINE(google-explicit-constructor)
367-
constexpr span(T (&arr)[N]) noexcept
380+
constexpr span(std::type_identity_t<T> (&arr)[N]) noexcept
368381
// SAFETY: The std::ranges::size() function gives the number of elements
369382
// pointed to by the std::ranges::data() function, which meets the
370383
// requirement of span.
@@ -884,8 +897,7 @@ class GSL_POINTER span<T, dynamic_extent, InternalPtrType> {
884897
// valid range of the collection pointed to by the iterator.
885898
template <typename It>
886899
requires(internal::CompatibleIter<T, It>)
887-
UNSAFE_BUFFER_USAGE constexpr span(It first,
888-
StrictNumeric<size_t> count) noexcept
900+
UNSAFE_BUFFER_USAGE constexpr span(It first, StrictNumeric<size_t> count)
889901
// The use of to_address() here is to handle the case where the iterator
890902
// `first` is pointing to the container's `end()`. In that case we can
891903
// not use the address returned from the iterator, or dereference it
@@ -921,8 +933,8 @@ class GSL_POINTER span<T, dynamic_extent, InternalPtrType> {
921933
template <typename It, typename End>
922934
requires(internal::CompatibleIter<T, It> &&
923935
std::sized_sentinel_for<End, It> &&
924-
!std::convertible_to<End, size_t>)
925-
UNSAFE_BUFFER_USAGE constexpr span(It begin, End end) noexcept
936+
!std::is_convertible_v<End, size_t>)
937+
UNSAFE_BUFFER_USAGE constexpr span(It begin, End end)
926938
// SAFETY: The caller must guarantee that the iterator and end sentinel
927939
// are part of the same allocation, in which case it is the number of
928940
// elements between the iterators and thus a valid size for the pointer to
@@ -939,7 +951,7 @@ class GSL_POINTER span<T, dynamic_extent, InternalPtrType> {
939951

940952
template <size_t N>
941953
// NOLINTNEXTLINE(google-explicit-constructor)
942-
constexpr span(T (&arr)[N]) noexcept
954+
constexpr span(std::type_identity_t<T> (&arr)[N]) noexcept
943955
// SAFETY: The std::ranges::size() function gives the number of elements
944956
// pointed to by the std::ranges::data() function, which meets the
945957
// requirement of span.
@@ -1364,7 +1376,8 @@ class GSL_POINTER span<T, dynamic_extent, InternalPtrType> {
13641376
// [span.deduct], deduction guides.
13651377
template <typename It, typename EndOrSize>
13661378
requires(std::contiguous_iterator<It>)
1367-
span(It, EndOrSize) -> span<std::remove_reference_t<std::iter_reference_t<It>>>;
1379+
span(It, EndOrSize) -> span<std::remove_reference_t<std::iter_reference_t<It>>,
1380+
internal::MaybeStaticExt<EndOrSize>>;
13681381

13691382
template <
13701383
typename R,

base/containers/span_unittest.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ namespace {
5656
std::is_same_v<decltype(span(v.begin(), v.size())), span<const int>>);
5757
static_assert(
5858
std::is_same_v<decltype(span(v.data(), v.size())), span<const int>>);
59+
static_assert(
60+
std::is_same_v<decltype(span(v.cbegin(),
61+
std::integral_constant<size_t, 0>())),
62+
span<const int, 0>>);
5963
}
6064

6165
{
@@ -66,6 +70,10 @@ namespace {
6670
std::is_same_v<decltype(span(v.begin(), v.size())), span<int>>);
6771
static_assert(
6872
std::is_same_v<decltype(span(v.data(), v.size())), span<int>>);
73+
static_assert(
74+
std::is_same_v<decltype(span(v.cbegin(),
75+
std::integral_constant<size_t, 0>())),
76+
span<const int, 0>>);
6977
}
7078

7179
{

0 commit comments

Comments
 (0)