Commit 7549a004 authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Commit Bot

[base] Implement LWG3101 - span's Container constructors need another constraint

This change implements LWG3101 [1], which disables span's Container
constructors when the extent is static. This change disables the
corresponding constructors appropriately and modifies base::make_span<N>
to call the two argument (data, size) constructor instead.

[1] https://wg21.link/LWG3101

Bug: 828324, 877931
Change-Id: If3e615ea26f2a051c0c650bed0789c9442ca47b2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1883569Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#710255}
parent 25476a00
......@@ -91,14 +91,7 @@ using EnableIfSpanCompatibleContainer =
template <typename Container, typename T, size_t Extent>
using EnableIfSpanCompatibleContainerAndSpanIsDynamic =
std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value &&
Extent == dynamic_extent,
bool>;
template <typename Container, typename T, size_t Extent>
using EnableIfSpanCompatibleContainerAndSpanIsStatic =
std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value &&
Extent != dynamic_extent,
bool>;
Extent == dynamic_extent>;
// A helper template for storing the size of a span. Spans with static extents
// don't require additional storage, since the extent itself is specified in the
......@@ -272,36 +265,22 @@ class span : public internal::ExtentStorage<Extent> {
// base::size().
template <
typename Container,
internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<Container&,
T,
Extent> = false>
typename =
internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<Container&,
T,
Extent>>
constexpr span(Container& container) noexcept
: span(base::data(container), base::size(container)) {}
template <
typename Container,
internal::EnableIfSpanCompatibleContainerAndSpanIsStatic<Container&,
T,
Extent> = false>
constexpr explicit span(Container& container) noexcept
: span(base::data(container), base::size(container)) {}
template <typename Container,
internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<
const Container&,
T,
Extent> = false>
typename = internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<
const Container&,
T,
Extent>>
constexpr span(const Container& container) noexcept
: span(base::data(container), base::size(container)) {}
template <
typename Container,
internal::EnableIfSpanCompatibleContainerAndSpanIsStatic<const Container&,
T,
Extent> = false>
constexpr explicit span(const Container& container) noexcept
: span(base::data(container), base::size(container)) {}
constexpr span(const span& other) noexcept = default;
// Conversions from spans of compatible types and extents: this allows a
......@@ -519,7 +498,7 @@ template <size_t N,
decltype(base::data(std::declval<Container&>()))>,
typename = internal::EnableIfSpanCompatibleContainer<Container&, T>>
constexpr span<T, N> make_span(Container& container) noexcept {
return span<T, N>(container);
return span<T, N>(data(container), size(container));
}
template <
......@@ -530,7 +509,7 @@ template <
decltype(base::data(std::declval<const Container&>()))>,
typename = internal::EnableIfSpanCompatibleContainer<const Container&, T>>
constexpr span<T, N> make_span(const Container& container) noexcept {
return span<T, N>(container);
return span<T, N>(data(container), size(container));
}
template <int&... ExplicitArgumentBarrier, typename T, size_t X>
......
......@@ -175,7 +175,7 @@ TEST(SpanTest, ConstructFromInitializerList) {
for (size_t i = 0; i < const_span.size(); ++i)
EXPECT_EQ(il.begin()[i], const_span[i]);
span<const int, 6> static_span(il);
span<const int, 6> static_span(il.begin(), il.end());
EXPECT_EQ(il.begin(), static_span.data());
EXPECT_EQ(il.size(), static_span.size());
......@@ -200,7 +200,7 @@ TEST(SpanTest, ConstructFromStdString) {
for (size_t i = 0; i < dynamic_span.size(); ++i)
EXPECT_EQ(str[i], dynamic_span[i]);
span<char, 6> static_span(str);
span<char, 6> static_span(data(str), str.size());
EXPECT_EQ(str.data(), static_span.data());
EXPECT_EQ(str.size(), static_span.size());
......@@ -218,7 +218,7 @@ TEST(SpanTest, ConstructFromConstContainer) {
for (size_t i = 0; i < const_span.size(); ++i)
EXPECT_EQ(vector[i], const_span[i]);
span<const int, 6> static_span(vector);
span<const int, 6> static_span(vector.data(), vector.size());
EXPECT_EQ(vector.data(), static_span.data());
EXPECT_EQ(vector.size(), static_span.size());
......@@ -243,7 +243,7 @@ TEST(SpanTest, ConstructFromContainer) {
for (size_t i = 0; i < dynamic_span.size(); ++i)
EXPECT_EQ(vector[i], dynamic_span[i]);
span<int, 6> static_span(vector);
span<int, 6> static_span(vector.data(), vector.size());
EXPECT_EQ(vector.data(), static_span.data());
EXPECT_EQ(vector.size(), static_span.size());
......@@ -282,7 +282,7 @@ TEST(SpanTest, ConvertNonConstPointerToConst) {
// due to CWG Defect 330:
// http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#330
span<int*, 3> static_non_const_pointer_span(vector);
span<int*, 3> static_non_const_pointer_span(vector.data(), vector.size());
EXPECT_THAT(static_non_const_pointer_span, Pointwise(Eq(), vector));
span<int* const, 3> static_const_pointer_span(static_non_const_pointer_span);
EXPECT_THAT(static_const_pointer_span,
......@@ -297,7 +297,7 @@ TEST(SpanTest, ConvertBetweenEquivalentTypes) {
EXPECT_EQ(int32_t_span.data(), converted_span.data());
EXPECT_EQ(int32_t_span.size(), converted_span.size());
span<int32_t, 5> static_int32_t_span(vector);
span<int32_t, 5> static_int32_t_span(vector.data(), vector.size());
span<int, 5> static_converted_span(static_int32_t_span);
EXPECT_EQ(static_int32_t_span.data(), static_converted_span.data());
EXPECT_EQ(static_int32_t_span.size(), static_converted_span.size());
......@@ -1111,7 +1111,7 @@ TEST(SpanTest, MakeSpanFromConstContainer) {
TEST(SpanTest, MakeStaticSpanFromConstContainer) {
const std::vector<int> vector = {-1, -2, -3, -4, -5};
span<const int, 5> expected_span(vector);
span<const int, 5> expected_span(vector.data(), vector.size());
auto made_span = make_span<5>(vector);
EXPECT_EQ(expected_span.data(), made_span.data());
EXPECT_EQ(expected_span.size(), made_span.size());
......@@ -1135,7 +1135,7 @@ TEST(SpanTest, MakeSpanFromContainer) {
TEST(SpanTest, MakeStaticSpanFromContainer) {
std::vector<int> vector = {-1, -2, -3, -4, -5};
span<int, 5> expected_span(vector);
span<int, 5> expected_span(vector.data(), vector.size());
auto made_span = make_span<5>(vector);
EXPECT_EQ(expected_span.data(), make_span<5>(vector).data());
EXPECT_EQ(expected_span.size(), make_span<5>(vector).size());
......@@ -1352,6 +1352,27 @@ TEST(SpanTest, Sort) {
EXPECT_THAT(array, ElementsAre(5, 4, 3, 2, 1));
}
TEST(SpanTest, SpanExtentConversions) {
// Statically checks that various conversions between spans of dynamic and
// static extent are possible or not.
static_assert(
!std::is_constructible<span<int, 0>, span<int>>::value,
"Error: static span should not be constructible from dynamic span");
static_assert(!std::is_constructible<span<int, 2>, span<int, 1>>::value,
"Error: static span should not be constructible from static "
"span with different extent");
static_assert(std::is_convertible<span<int, 0>, span<int>>::value,
"Error: static span should be convertible to dynamic span");
static_assert(std::is_convertible<span<int>, span<int>>::value,
"Error: dynamic span should be convertible to dynamic span");
static_assert(std::is_convertible<span<int, 2>, span<int, 2>>::value,
"Error: static span should be convertible to static span");
}
TEST(SpanTest, IteratorConversions) {
static_assert(std::is_convertible<span<int>::iterator,
span<int>::const_iterator>::value,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment