[gcc r16-8412] libstdc++: Change meaning of strided_slice::extent per P3982R2
Tomasz Kaminski
tkaminsk@gcc.gnu.org
Thu Apr 2 07:49:01 GMT 2026
https://gcc.gnu.org/g:e920613db52adece7e3de5f2a2812247c72782f6
commit r16-8412-ge920613db52adece7e3de5f2a2812247c72782f6
Author: Tomasz Kamiński <tkaminsk@redhat.com>
Date: Mon Jan 26 12:20:48 2026 +0100
libstdc++: Change meaning of strided_slice::extent per P3982R2
This patch implements the changes suggested in P3982R2 (and PL007 NB comment)
for C++26, but changing the strided_slice::extent to indicate number of
elements (extent) in the produced (output) mdspan, instead of input.
libstdc++-v3/ChangeLog:
* include/std/mdspan (__mdspan::__static_slice_extent)
(__mdspan::__dynamic_slice_extent): Return unmodified extent
value for strided_slice.
(__mdspan::__substrides_generic, __mdspan::__substrides_standardized):
Multipliy stride, if more than one element is requested.
(__mdspan::__canonical_range_slice): Define.
(__mdspan::__slice_cast): Use __canonical_range_slice for range_slice
and two elements tuples.
(__mdspan::__check_inrange_index): Define.
(__mdspan::__check_valid_slice): Validate if slice.offset +
(slice.extent - 1) * slice.stride fits into extent of given
dimension. Check stride if slice.extent > 1.
* testsuite/23_containers/mdspan/submdspan/canonical_slices.cc:
Add test for range_slice.
* testsuite/23_containers/mdspan/submdspan/canonical_slices_neg.cc:
Add tests validating new conditions.
* testsuite/23_containers/mdspan/submdspan/selections/testcases.h:
Adjusted for change of meaing of strided_slice::extent.
* testsuite/23_containers/mdspan/submdspan/subextents.cc:
Adjusted for change of meaing of strided_slice::extent. And expanded
range_slice tests.
* testsuite/23_containers/mdspan/submdspan/subextents_neg.cc:
Adjusted for change of meaing of strided_slice::extent.
* testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc:
Adjust test for stride value.
Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
Diff:
---
libstdc++-v3/include/std/mdspan | 199 ++++++++++++++-------
.../mdspan/submdspan/canonical_slices.cc | 160 +++++++++++++----
.../mdspan/submdspan/canonical_slices_neg.cc | 33 ++++
.../mdspan/submdspan/selections/testcases.h | 12 +-
.../23_containers/mdspan/submdspan/subextents.cc | 90 ++++++----
.../mdspan/submdspan/subextents_neg.cc | 6 +-
.../mdspan/submdspan/submdspan_neg.cc | 2 +-
7 files changed, 363 insertions(+), 139 deletions(-)
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index 7f02b3460546..5b80de2ca619 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -1001,10 +1001,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return _Extent;
else if constexpr (same_as<_Slice, constant_wrapper<_IndexType(0)>>)
return 0;
- else if constexpr (__is_constant_wrapper<typename _Slice::extent_type>
- && __is_constant_wrapper<typename _Slice::stride_type>)
- return 1 + ((typename _Slice::extent_type{}) - 1)
- / (typename _Slice::stride_type{});
+ else if constexpr (__is_constant_wrapper<typename _Slice::extent_type>)
+ return _Slice::extent_type::value;
else
return dynamic_extent;
}
@@ -1014,7 +1012,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__dynamic_slice_extent(const _Extents& __exts, _Slice __slice)
{
if constexpr (__is_strided_slice<_Slice>)
- return __slice.extent == 0 ? 0 : 1 + (__slice.extent - 1) / __slice.stride;
+ return __slice.extent;
else
return __exts.extent(_K);
}
@@ -1128,7 +1126,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
auto __stride = [&__mapping](size_t __k, auto __slice) -> _IndexType
{
if constexpr (__is_strided_slice<decltype(__slice)>)
- if (__slice.stride < __slice.extent)
+ if (__slice.extent > 1)
return __mapping.stride(__k) * __slice.stride;
return __mapping.stride(__k);
};
@@ -1173,7 +1171,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
size_t __krev = _SubTrait::_S_idx(__k);
if constexpr (__is_strided_slice<decltype(__slice)>)
{
- if (__slice.stride < __slice.extent)
+ if (__slice.extent > 1)
__ret[__krev] = __stride * __slice.stride;
else
__ret[__krev] = __stride;
@@ -3293,6 +3291,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __mdspan::__index_type_cast<_IndexType>(std::move(__slice));
}
+ template<typename _IndexType,
+ typename _OffsetType, typename _SpanType, typename _StrideType>
+ constexpr auto
+ __canonical_range_slice(_OffsetType __offset, _SpanType __span,
+ _StrideType __stride)
+ {
+ if constexpr (is_same_v<_SpanType, constant_wrapper<_IndexType(0)>>
+ || is_same_v<_StrideType, constant_wrapper<_IndexType(1)>>)
+ return strided_slice{
+ .offset = __offset,
+ .extent = __span,
+ .stride = cw<_IndexType(1)>
+ };
+ else if constexpr (__is_constant_wrapper<_StrideType>)
+ {
+ static_assert(_StrideType::value > 0);
+ if constexpr (__is_constant_wrapper<_SpanType>)
+ return strided_slice{
+ .offset = __offset,
+ .extent = cw<_IndexType(1 + (_SpanType::value - 1) / _StrideType::value)>,
+ .stride = __stride
+ };
+ else
+ return strided_slice{
+ .offset = __offset,
+ .extent = _IndexType(__span > 0 ? 1 + (__span - 1) / _StrideType::value : 0),
+ .stride = __stride
+ };
+ }
+ else if (__span == 0 || __stride == 1)
+ return strided_slice{
+ .offset = __offset,
+ .extent = _IndexType(__span),
+ .stride = _IndexType(1)
+ };
+ else
+ {
+ __glibcxx_assert(__stride > 0);
+ return strided_slice{
+ .offset = __offset,
+ .extent = _IndexType(1 + (__span - 1) / __stride),
+ .stride = __stride
+ };
+ }
+ }
+
template<typename _IndexType, typename _Slice>
constexpr auto
__slice_cast(_Slice&& __slice)
@@ -3303,52 +3347,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
else if constexpr (is_convertible_v<_SliceType, _IndexType>)
return __mdspan::__canonical_index<_IndexType>(std::move(__slice));
else if constexpr (__is_strided_slice<_SliceType>)
- {
- auto __extent
- = __mdspan::__canonical_index<_IndexType>(std::move(__slice.extent));
- auto __offset
- = __mdspan::__canonical_index<_IndexType>(std::move(__slice.offset));
- if constexpr (is_same_v<decltype(__extent),
- constant_wrapper<_IndexType(0)>>)
- return strided_slice{
- .offset = __offset,
- .extent = __extent,
- .stride = cw<_IndexType(1)>
- };
- else
- return strided_slice{
- .offset = __offset,
- .extent = __extent,
- .stride
- = __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride))
- };
- }
+ return strided_slice{
+ .offset = __mdspan::__canonical_index<_IndexType>(std::move(__slice.offset)),
+ .extent = __mdspan::__canonical_index<_IndexType>(std::move(__slice.extent)),
+ .stride = __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride))
+ };
else if constexpr (__is_range_slice<_SliceType>)
{
auto __first
= __mdspan::__canonical_index<_IndexType>(std::move(__slice.first));
auto __last
= __mdspan::__canonical_index<_IndexType>(std::move(__slice.last));
- auto __stride
- = __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride));
- return __mdspan::__slice_cast<_IndexType>(
- strided_slice{__first, __last - __first, __stride});
+ return __mdspan::__canonical_range_slice<_IndexType>(
+ __first,
+ __mdspan::__canonical_index<_IndexType>(__last - __first),
+ __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride)));
}
else
{
auto [__sbegin, __send] = std::move(__slice);
- auto __offset
+ auto __cbegin
= __mdspan::__canonical_index<_IndexType>(std::move(__sbegin));
- auto __end
+ auto __cend
= __mdspan::__canonical_index<_IndexType>(std::move(__send));
- return strided_slice{
- .offset = __offset,
- .extent = __mdspan::__canonical_index<_IndexType>(__end - __offset),
- .stride = cw<_IndexType(1)>
- };
+ auto __cspan
+ = __mdspan::__canonical_index<_IndexType>(__cend - __cbegin);
+ return __mdspan::__canonical_range_slice<_IndexType>(
+ __cbegin, __cspan, cw<_IndexType(1)>);
}
}
+ template<typename _IndexType, size_t _Extent, typename _OIndexType>
+ constexpr void
+ __check_inrange_index(const extents<_IndexType, _Extent>& __ext,
+ const _OIndexType& __idx)
+ {
+ if constexpr (__is_constant_wrapper<_OIndexType>
+ && _Extent != dynamic_extent)
+ {
+ static_assert(_OIndexType::value >= 0);
+ static_assert(std::cmp_less(_OIndexType::value, _Extent));
+ }
+ else
+ __glibcxx_assert(__idx < __ext.extent(0));
+ }
+
template<typename _IndexType, size_t _Extent, typename _OIndexType>
constexpr void
__check_valid_index(const extents<_IndexType, _Extent>& __ext,
@@ -3362,7 +3405,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
else
__glibcxx_assert(__idx <= __ext.extent(0));
-}
+ }
template<typename _IndexType, size_t _Extent, typename _Slice>
constexpr void
@@ -3371,34 +3414,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
if constexpr (__is_strided_slice<_Slice>)
{
+ __mdspan::__check_valid_index(__ext, __slice.extent);
// DEVIATION: For empty slices, P3663r3 does not allow us to check
// that this is less than or equal to the k-th extent (at runtime).
// We're only allowed to check if __slice.offset, __slice.extent
// are constant wrappers and __ext is a static extent.
- __mdspan::__check_valid_index(__ext, __slice.offset);
- __mdspan::__check_valid_index(__ext, __slice.extent);
-
- if constexpr (__is_constant_wrapper<typename _Slice::extent_type>
- && __is_constant_wrapper<typename _Slice::stride_type>)
- static_assert(_Slice::stride_type::value > 0);
- else
- __glibcxx_assert(__slice.extent == 0 || __slice.stride > 0);
-
- if constexpr (__is_constant_wrapper<typename _Slice::offset_type>
- && __is_constant_wrapper<typename _Slice::extent_type>
- && _Extent != dynamic_extent)
- static_assert(std::cmp_greater_equal(
- _Extent - _Slice::offset_type::value,
- _Slice::extent_type::value));
+ if constexpr (is_same_v<typename _Slice::extent_type,
+ constant_wrapper<_IndexType(0)>>)
+ __mdspan::__check_valid_index(__ext, __slice.offset);
+ else if constexpr (is_same_v<typename _Slice::extent_type,
+ constant_wrapper<_IndexType(1)>>)
+ __mdspan::__check_inrange_index(__ext, __slice.offset);
+ else if constexpr (__is_constant_wrapper<typename _Slice::extent_type>)
+ {
+ __mdspan::__check_inrange_index(__ext, __slice.offset);
+ if constexpr (__is_constant_wrapper<typename _Slice::stride_type>)
+ static_assert(_Slice::stride_type::value > 0);
+ else
+ __glibcxx_assert(__slice.stride > 0);
+
+ if constexpr (_Extent != dynamic_extent
+ && __is_constant_wrapper<typename _Slice::offset_type>)
+ static_assert(std::cmp_greater_equal(
+ _Extent - _Slice::offset_type::value,
+ _Slice::extent_type::value));
+ if constexpr (_Extent != dynamic_extent
+ && __is_constant_wrapper<typename _Slice::stride_type>)
+ static_assert(std::cmp_greater(
+ _Extent,
+ (_Slice::extent_type::value - 1) * _Slice::stride_type::value));
+
+ if constexpr (_Extent != dynamic_extent
+ && __is_constant_wrapper<typename _Slice::offset_type>
+ && __is_constant_wrapper<typename _Slice::stride_type>)
+ static_assert(std::cmp_greater(
+ _Extent - _Slice::offset_type::value,
+ (_Slice::extent_type::value - 1) * _Slice::stride_type::value));
+ else
+ __glibcxx_assert(std::cmp_greater(
+ __ext.extent(0) - __slice.offset,
+ (_Slice::extent_type::value - 1) * __slice.stride));
+ }
+ else if constexpr (is_same_v<typename _Slice::stride_type,
+ constant_wrapper<_IndexType(1)>>)
+ {
+ __mdspan::__check_valid_index(__ext, __slice.offset);
+ __glibcxx_assert(std::cmp_greater_equal(
+ __ext.extent(0) - __slice.offset,
+ __slice.extent));
+ }
+ else if (__slice.extent == 0)
+ __mdspan::__check_valid_index(__ext, __slice.offset);
else
- __glibcxx_assert(__ext.extent(0) - __slice.offset
- >= __slice.extent);
+ {
+ __glibcxx_assert(__slice.offset < __ext.extent(0));
+ __glibcxx_assert(__slice.extent == 1 || __slice.stride > 0);
+ __glibcxx_assert(__slice.extent == 1 || std::cmp_greater(
+ __ext.extent(0) - __slice.offset,
+ (__slice.extent - 1) * __slice.stride));
+ }
}
- else if constexpr (__is_constant_wrapper<_Slice>
- && _Extent != dynamic_extent)
- static_assert(std::cmp_less(_Slice::value, _Extent));
- else if constexpr (convertible_to<_Slice, _IndexType>)
- __glibcxx_assert(__slice < __ext.extent(0));
+ else if constexpr (!is_same_v<_Slice, full_extent_t>)
+ __mdspan::__check_inrange_index(__ext, __slice);
}
template<typename _Extents, typename... _Slices>
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc
index 5ca123eee506..7e6a0791af7d 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices.cc
@@ -114,90 +114,184 @@ test_pair_all()
{
test_pair<std::pair>();
test_pair<std::tuple>();
+ test_pair<std::range_slice>();
test_pair<Range>();
return true;
}
+template<template<typename, typename, typename> typename Triple>
constexpr bool
-test_strided_slice(auto exts, auto co, auto ce, auto cs)
+test_triple(auto exts, auto ce, auto cf, auto cl, auto cs)
{
using IndexType = decltype(exts)::index_type;
- auto coffset = std::cw<IndexType{co.value}>;
+ auto coffset = std::cw<IndexType{cf.value}>;
auto cextent = std::cw<IndexType{ce.value}>;
auto cstride = std::cw<IndexType{cs.value}>;
- auto raw_ccc = std::strided_slice{co, ce, cs};
+ auto raw_ccc = Triple{cf, cl, cs};
auto [ccc] = std::canonical_slices(exts, raw_ccc);
assert_same(ccc.offset, coffset);
assert_same(ccc.extent, cextent);
assert_same(ccc.stride, cstride);
- auto raw_dcc = std::strided_slice{co.value, ce, cs};
+ auto raw_dcc = Triple{cf.value, cl, cs};
auto [dcc] = std::canonical_slices(exts, raw_dcc);
assert_same(dcc.offset, coffset.value);
- assert_same(dcc.extent, cextent);
+ assert_same(dcc.extent, cextent.value);
assert_same(dcc.stride, cstride);
- auto raw_cdc = std::strided_slice{co, ce.value, cs};
+ auto raw_cdc = Triple{cf, cl.value, cs};
auto [cdc] = std::canonical_slices(exts, raw_cdc);
assert_same(cdc.offset, coffset);
assert_same(cdc.extent, cextent.value);
assert_same(cdc.stride, cstride);
- auto raw_ccd = std::strided_slice{co, ce, cs.value};
+ auto raw_ccd = Triple{cf, cl, cs.value};
auto [ccd] = std::canonical_slices(exts, raw_ccd);
assert_same(ccd.offset, coffset);
- assert_same(ccd.extent, cextent);
+ assert_same(ccd.extent, cextent.value);
assert_same(ccd.stride, cstride.value);
return true;
}
+template<template<typename, typename, typename> typename Triple>
constexpr bool
-test_strided_slice()
+test_triple_zero_extent(auto exts, auto cf, auto cs)
{
- auto run = [](auto exts)
+ using IndexType = typename decltype(exts)::index_type;
+ auto raw_ccc = Triple{cf, cf, cs};
+ auto [ccc] = std::canonical_slices(exts, raw_ccc);
+ assert_same(ccc.stride, std::cw<IndexType{1}>);
+
+ auto raw_ccd = Triple{cf, cf, cs.value};
+ auto [ccd] = std::canonical_slices(exts, raw_ccd);
+ assert_same(ccd.stride, std::cw<IndexType{1}>);
+
+ auto raw_cdd = Triple{cf, cf.value, cs.value};
+ auto [cdd] = std::canonical_slices(exts, raw_cdd);
+ assert_same(cdd.stride, IndexType(1));
+
+ auto raw_dcd = Triple{cf.value, cf, cs.value};
+ auto [dcd] = std::canonical_slices(exts, raw_dcd);
+ assert_same(dcd.stride, IndexType(1));
+
+ auto raw_ddd = Triple{cf.value, cf.value, cs.value};
+ auto [ddd] = std::canonical_slices(exts, raw_ddd);
+ assert_same(cdd.stride, IndexType(1));
+
+ if constexpr (decltype(cs)::value > 0)
{
- auto cs = std::cw<uint8_t{9}>;
- test_strided_slice(exts, std::cw<uint8_t{2}>, std::cw<uint8_t{3}>, cs);
- test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{5}>, cs);
- };
+ auto cstride = std::cw<IndexType(cs.value)>;
+
+ auto raw_cdc = Triple{cf, cf.value, cs};
+ auto [cdc] = std::canonical_slices(exts, raw_cdc);
+ assert_same(cdc.stride, cstride);
+
+ auto raw_dcc = Triple{cf.value, cf, cs};
+ auto [dcc] = std::canonical_slices(exts, raw_dcc);
+ assert_same(dcc.stride, cstride);
+
+ auto raw_ddc = Triple{cf.value, cf.value, cs};
+ auto [ddc] = std::canonical_slices(exts, raw_ddc);
+ assert_same(cdc.stride, cstride);
+ }
+ return true;
+}
+
+template<template<typename, typename, typename> typename Triple>
+constexpr bool
+test_triple()
+{
+ auto run = [](auto exts) {
+ test_triple<Triple>(exts, std::cw<uint8_t{5}>,
+ std::cw<uint8_t{0}>, std::cw<uint8_t{5}>, std::cw<uint8_t{1}>);
+ test_triple<Triple>(exts, std::cw<uint8_t{3}>,
+ std::cw<uint8_t{0}>, std::cw<uint8_t{5}>, std::cw<uint8_t{2}>);
+ test_triple<Triple>(exts, std::cw<uint8_t{2}>,
+ std::cw<uint8_t{1}>, std::cw<uint8_t{5}>, std::cw<uint8_t{3}>);
+ test_triple<Triple>(exts, std::cw<uint8_t{1}>,
+ std::cw<uint8_t{1}>, std::cw<uint8_t{5}>, std::cw<uint8_t{9}>);
+
+ test_triple_zero_extent<Triple>(exts,
+ std::cw<uint8_t{0}>, std::cw<uint8_t{9}>);
+ test_triple_zero_extent<Triple>(exts,
+ std::cw<uint8_t{0}>, std::cw<uint8_t{0}>);
+ test_triple_zero_extent<Triple>(exts,
+ std::cw<uint8_t{5}>, std::cw<uint8_t{9}>);
+ test_triple_zero_extent<Triple>(exts,
+ std::cw<uint8_t{5}>, std::cw<uint8_t{0}>);
+ };
run(std::extents<int, 5>{});
run(std::extents<int, dyn>{5});
+
+ test_triple_zero_extent<Triple>(std::extents<int, 0>{},
+ std::cw<uint8_t{0}>, std::cw<uint8_t{9}>);
+ test_triple_zero_extent<Triple>(std::extents<int, dyn>{0},
+ std::cw<uint8_t{0}>, std::cw<uint8_t{0}>);
+
return true;
}
constexpr bool
-test_strided_slice_zero_extent(auto exts, auto cs)
+test_triple_all()
{
- using IndexType = typename decltype(exts)::index_type;
- auto c0 = std::cw<uint8_t{0}>;
- auto raw_ccc = std::strided_slice{c0, c0, cs};
- auto [ccc] = std::canonical_slices(exts, raw_ccc);
- assert_same(ccc.stride, std::cw<IndexType{1}>);
-
- auto raw_ccd = std::strided_slice{c0, c0, cs.value};
- auto [ccd] = std::canonical_slices(exts, raw_ccd);
- assert_same(ccd.stride, std::cw<IndexType{1}>);
+ test_triple<std::range_slice>();
return true;
}
constexpr bool
-test_strided_slice_zero_extent(auto exts)
+test_strided_slice(auto exts, auto co, auto ce, auto cs)
{
- test_strided_slice_zero_extent(exts, std::cw<uint8_t{0}>);
- test_strided_slice_zero_extent(exts, std::cw<uint8_t{9}>);
+ using IndexType = decltype(exts)::index_type;
+
+ auto coffset = std::cw<IndexType{co.value}>;
+ auto cextent = std::cw<IndexType{ce.value}>;
+ auto cstride = std::cw<IndexType{cs.value}>;
+
+ auto raw_ccc = std::strided_slice{co, ce, cs};
+ auto [ccc] = std::canonical_slices(exts, raw_ccc);
+ assert_same(ccc.offset, coffset);
+ assert_same(ccc.extent, cextent);
+ assert_same(ccc.stride, cstride);
+
+ auto raw_dcc = std::strided_slice{co.value, ce, cs};
+ auto [dcc] = std::canonical_slices(exts, raw_dcc);
+ assert_same(dcc.offset, coffset.value);
+ assert_same(dcc.extent, cextent);
+ assert_same(dcc.stride, cstride);
+
+ auto raw_cdc = std::strided_slice{co, ce.value, cs};
+ auto [cdc] = std::canonical_slices(exts, raw_cdc);
+ assert_same(cdc.offset, coffset);
+ assert_same(cdc.extent, cextent.value);
+ assert_same(cdc.stride, cstride);
+
+ auto raw_ccd = std::strided_slice{co, ce, cs.value};
+ auto [ccd] = std::canonical_slices(exts, raw_ccd);
+ assert_same(ccd.offset, coffset);
+ assert_same(ccd.extent, cextent);
+ assert_same(ccd.stride, cstride.value);
return true;
}
constexpr bool
-test_strided_slice_zero_extent()
+test_strided_slice()
{
- test_strided_slice_zero_extent(std::extents<int, 0>{});
- test_strided_slice_zero_extent(std::extents<int, dyn>{0});
- test_strided_slice_zero_extent(std::extents<int, 5>{});
- test_strided_slice_zero_extent(std::extents<int, dyn>{5});
+ auto run = [](auto exts)
+ {
+ auto cs = std::cw<uint8_t{1}>;
+ test_strided_slice(exts, std::cw<uint8_t{2}>, std::cw<uint8_t{2}>, std::cw<uint8_t{2}>);
+ test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{5}>, std::cw<uint8_t{1}>);
+ test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{0}>, std::cw<uint8_t{1}>);
+ test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{0}>, std::cw<uint8_t{3}>);
+ test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{0}>, std::cw<uint8_t{0}>);
+ test_strided_slice(exts, std::cw<uint8_t{0}>, std::cw<uint8_t{0}>, std::cw<uint8_t{9}>);
+ };
+
+ run(std::extents<int, 5>{});
+ run(std::extents<int, dyn>{5});
return true;
}
@@ -206,8 +300,8 @@ test_all()
{
test_scalar();
test_pair_all();
+ test_triple_all();
test_strided_slice();
- test_strided_slice_zero_extent();
return true;
}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices_neg.cc
index 6dbfd5e8a1b8..3923d5393b9e 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/canonical_slices_neg.cc
@@ -112,6 +112,7 @@ template<typename Offset, typename Extent, typename Stride, typename Extents>
constexpr auto i8_6 = int8_t{6};
constexpr auto c_i8_6 = std::cw<int8_t{6}>;
constexpr auto c2 = std::cw<2>;
+constexpr auto c3 = std::cw<3>;
constexpr auto c4 = std::cw<4>;
static_assert(test_over2(i8_6, 0, 1, dyn_uexts)); // { dg-error "expansion of" }
@@ -122,6 +123,14 @@ static_assert(test_over2(0, c_i8_6, 1, dyn_uexts)); // { dg-error "expansion of
static_assert(test_over2(c2, 4, 1, dyn_uexts)); // { dg-error "expansion of" }
static_assert(test_over2(2, c4, 1, dyn_uexts)); // { dg-error "expansion of" }
static_assert(test_over2(c2, c4, 1, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 3, 2, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 3, c2, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c3, 2, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 3, 2, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c3, 2, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c3, c2, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 3, c2, dyn_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c3, c2, dyn_uexts)); // { dg-error "expansion of" }
static_assert(test_over2(i8_6, 0, 1, dyn_sexts)); // { dg-error "expansion of" }
static_assert(test_over2(0, i8_6, 1, dyn_sexts)); // { dg-error "expansion of" }
@@ -131,6 +140,14 @@ static_assert(test_over2(0, c_i8_6, 1, dyn_sexts)); // { dg-error "expansion of
static_assert(test_over2(c2, 4, 1, dyn_sexts)); // { dg-error "expansion of" }
static_assert(test_over2(2, c4, 1, dyn_sexts)); // { dg-error "expansion of" }
static_assert(test_over2(c2, c4, 1, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 3, 2, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 3, c2, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c3, 2, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 3, 2, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c3, 2, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c3, c2, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 3, c2, dyn_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c3, c2, dyn_sexts)); // { dg-error "expansion of" }
static_assert(test_over2(i8_6, 0, 1, sta_uexts)); // { dg-error "expansion of" }
static_assert(test_over2(0, i8_6, 1, sta_uexts)); // { dg-error "expansion of" }
@@ -140,6 +157,14 @@ static_assert(test_over2(0, c_i8_6, 1, sta_uexts)); // { dg-error "expansion of
static_assert(test_over2(c2, 4, 1, sta_uexts)); // { dg-error "expansion of" }
static_assert(test_over2(2, c4, 1, sta_uexts)); // { dg-error "expansion of" }
static_assert(test_over2(c2, c4, 1, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 3, 2, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 3, c2, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c3, 2, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 3, 2, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c3, 2, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c3, c2, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 3, c2, sta_uexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c3, c2, sta_uexts)); // { dg-error "from here" }
static_assert(test_over2(i8_6, 0, 1, sta_sexts)); // { dg-error "expansion of" }
static_assert(test_over2(0, i8_6, 1, sta_sexts)); // { dg-error "expansion of" }
@@ -149,6 +174,14 @@ static_assert(test_over2(0, c_i8_6, 1, sta_sexts)); // { dg-error "expansion of
static_assert(test_over2(c2, 4, 1, sta_sexts)); // { dg-error "expansion of" }
static_assert(test_over2(2, c4, 1, sta_sexts)); // { dg-error "expansion of" }
static_assert(test_over2(c2, c4, 1, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 3, 2, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, 3, c2, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c3, 2, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 3, 2, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c3, 2, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(2, c3, c2, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, 3, c2, sta_sexts)); // { dg-error "expansion of" }
+static_assert(test_over2(c2, c3, c2, sta_sexts)); // { dg-error "from here" }
// Checks the precondition: offset + extent <= exts.extent(0) for unsigned
// index_type when offset + extent overflows.
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h
index d7b751d700c0..eade9017e039 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h
@@ -292,10 +292,10 @@ template<typename Layout>
check_selection<Layout>(exts, collapse{}, s, collapse{});
};
+ check(std::strided_slice(0, 1, 2));
check(std::strided_slice(0, 2, 2));
- check(std::strided_slice(0, 3, 2));
- check(std::strided_slice(1, 3, 2));
- check(std::strided_slice(1, std::cw<3>, std::cw<2>));
+ check(std::strided_slice(1, 2, 2));
+ check(std::strided_slice(1, std::cw<2>, std::cw<2>));
return true;
}
@@ -303,9 +303,9 @@ template<typename Layout>
constexpr bool
test_strided_box_selection(auto exts)
{
- auto s0 = std::strided_slice(0, 3, 2);
- auto s1 = std::strided_slice(1, 4, 2);
- auto s2 = std::strided_slice(0, 7, 3);
+ auto s0 = std::strided_slice(0, 2, 2);
+ auto s1 = std::strided_slice(1, 2, 2);
+ auto s2 = std::strided_slice(0, 3, 3);
check_selection<Layout>(exts, s0, s1, s2);
return true;
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc
index 464b253ff4d8..379fb79dfc23 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc
@@ -21,7 +21,7 @@ test_from_full_extent()
template<template<typename, typename> typename Pair, template<int> typename Cw>
constexpr bool
- test_from_tuple()
+ test_from_pair()
{
auto exts = std::extents<int, 3, 5, 7>{};
auto s0 = Cw<1>{};
@@ -29,22 +29,22 @@ template<template<typename, typename> typename Pair, template<int> typename Cw>
auto s2 = Pair{Cw<1>{}, 4};
auto sub_exts = std::subextents(exts, s0, s1, s2);
VERIFY(sub_exts.rank() == 2);
- VERIFY(sub_exts.static_extent(0) == size_t(get<1>(s1) - get<0>(s1)));
+ VERIFY(sub_exts.static_extent(0) == 1);
VERIFY(sub_exts.static_extent(1) == dyn);
- VERIFY(std::cmp_equal(sub_exts.extent(1), get<1>(s2) - get<0>(s2)));
+ VERIFY(std::cmp_equal(sub_exts.extent(1), 3));
return true;
}
template<template<int> typename Cw>
constexpr bool
- test_from_tuple_all()
+ test_from_pair_all()
{
- test_from_tuple<std::tuple, Cw>();
- test_from_tuple<std::pair, Cw>();
+ test_from_pair<std::tuple, Cw>();
+ test_from_pair<std::pair, Cw>();
+ test_from_pair<std::range_slice, Cw>();
return true;
}
-
template<typename Int>
void
test_from_int_like_as_scalar()
@@ -104,45 +104,57 @@ template<template<int> typename Cw>
VERIFY(sub_exts.rank() == 2);
VERIFY(sub_exts.static_extent(0) == dyn);
VERIFY(sub_exts.extent(0) == 2);
- VERIFY(sub_exts.static_extent(1) == dyn);
- VERIFY(sub_exts.extent(1) == 2);
+ VERIFY(sub_exts.static_extent(1) == 2);
}
{
// selected = 1 x [1, 3] x [1, 4, 7, 10]
auto s0 = 1;
- auto s1 = std::strided_slice{1, Cw<4>{}, 2};
- auto s2 = std::strided_slice{1, Cw<10>{}, Cw<3>{}};
+ auto s1 = std::strided_slice{1, Cw<2>{}, 2};
+ auto s2 = std::strided_slice{1, Cw<4>{}, Cw<3>{}};
auto sub_exts = std::subextents(exts, s0, s1, s2);
VERIFY(sub_exts.rank() == 2);
- VERIFY(sub_exts.static_extent(0) == dyn);
- VERIFY(sub_exts.extent(0) == 2);
+ VERIFY(sub_exts.static_extent(0) == 2);
VERIFY(sub_exts.static_extent(1) == 4);
}
{
// selected = [0, 2] x [1, 3] x [0, 3, 6]
- auto s0 = std::strided_slice(0, 3, 2);
- auto s1 = std::strided_slice(1, 4, 2);
- auto s2 = std::strided_slice(0, 7, 3);
+ auto s0 = std::strided_slice(0, 2, 2);
+ auto s1 = std::strided_slice(1, 2, 2);
+ auto s2 = std::strided_slice(0, 3, 3);
auto sub_exts = std::subextents(exts, s0, s1, s2);
VERIFY(sub_exts.rank() == 3);
VERIFY(sub_exts.extent(0) == 2);
VERIFY(sub_exts.extent(1) == 2);
VERIFY(sub_exts.extent(2) == 3);
}
+
+ {
+ // selected = [0] x [1] x [2]
+ auto s0 = std::strided_slice(0, 1, 99);
+ auto s1 = std::strided_slice(1, 1, 99);
+ auto s2 = std::strided_slice(2, 1, 99);
+ auto sub_exts = std::subextents(exts, s0, s1, s2);
+ VERIFY(sub_exts.rank() == 3);
+ VERIFY(sub_exts.extent(0) == 1);
+ VERIFY(sub_exts.extent(1) == 1);
+ VERIFY(sub_exts.extent(2) == 1);
+ }
+
return true;
}
-template<template<int> typename Cw>
+template<template<typename, typename, typename> class Triple,
+ template<int> typename Cw>
constexpr bool
- test_from_range_slice()
+ test_from_triple()
{
auto exts = std::extents<int, 5, 7, 11>{};
{
auto s0 = 1;
- auto s1 = std::range_slice{0, 0, 0};
- auto s2 = std::range_slice{Cw<1>{}, Cw<1>{}, 0};
+ auto s1 = Triple{0, 0, 0};
+ auto s2 = Triple{Cw<1>{}, Cw<1>{}, 0};
auto sub_exts = std::subextents(exts, s0, s1, s2);
VERIFY(sub_exts.rank() == 2);
VERIFY(sub_exts.static_extent(0) == dyn);
@@ -152,8 +164,8 @@ template<template<int> typename Cw>
{
auto s0 = 1;
- auto s1 = std::range_slice{0, 2, Cw<1>{}};
- auto s2 = std::range_slice{1, Cw<3>{}};
+ auto s1 = Triple{0, 2, Cw<1>{}};
+ auto s2 = Triple{1, Cw<3>{}, Cw<1>{}};
auto sub_exts = std::subextents(exts, s0, s1, s2);
VERIFY(sub_exts.rank() == 2);
VERIFY(sub_exts.static_extent(0) == dyn);
@@ -164,8 +176,8 @@ template<template<int> typename Cw>
{
auto s0 = 1;
- auto s1 = std::range_slice{0, 2, Cw<1>{}};
- auto s2 = std::range_slice{Cw<1>{}, Cw<3>{}, 1};
+ auto s1 = Triple{0, 2, Cw<1>{}};
+ auto s2 = Triple{Cw<1>{}, Cw<3>{}, 1};
auto sub_exts = std::subextents(exts, s0, s1, s2);
VERIFY(sub_exts.rank() == 2);
VERIFY(sub_exts.static_extent(0) == dyn);
@@ -177,8 +189,8 @@ template<template<int> typename Cw>
{
// selected = 1 x [1, 3] x [1, 4, 7, 10]
auto s0 = 1;
- auto s1 = std::range_slice{1, Cw<5>{}, 2};
- auto s2 = std::range_slice{1, Cw<11>{}, Cw<3>{}};
+ auto s1 = Triple{1, Cw<5>{}, 2};
+ auto s2 = Triple{1, Cw<11>{}, Cw<3>{}};
auto sub_exts = std::subextents(exts, s0, s1, s2);
VERIFY(sub_exts.rank() == 2);
VERIFY(sub_exts.static_extent(0) == dyn);
@@ -190,8 +202,8 @@ template<template<int> typename Cw>
{
// selected = 1 x [1, 3] x [1, 4, 7, 10]
auto s0 = 1;
- auto s1 = std::range_slice{1, Cw<5>{}, 2};
- auto s2 = std::range_slice{Cw<1>{}, Cw<11>{}, Cw<3>{}};
+ auto s1 = Triple{1, Cw<5>{}, 2};
+ auto s2 = Triple{Cw<1>{}, Cw<11>{}, Cw<3>{}};
auto sub_exts = std::subextents(exts, s0, s1, s2);
VERIFY(sub_exts.rank() == 2);
VERIFY(sub_exts.static_extent(0) == dyn);
@@ -201,18 +213,26 @@ template<template<int> typename Cw>
{
// selected = [0, 2] x [1, 3] x [0, 3, 6]
- auto s0 = std::range_slice(0, 3, 2);
- auto s1 = std::range_slice(1, 5, 2);
- auto s2 = std::range_slice(0, 7, 3);
+ auto s0 = Triple{0, 3, 2};
+ auto s1 = Triple{1, 5, 2};
+ auto s2 = Triple{0, 7, 3};
auto sub_exts = std::subextents(exts, s0, s1, s2);
VERIFY(sub_exts.rank() == 3);
VERIFY(sub_exts.extent(0) == 2);
VERIFY(sub_exts.extent(1) == 2);
VERIFY(sub_exts.extent(2) == 3);
}
+
return true;
}
+template<template<int> typename Cw>
+ constexpr bool
+ test_from_triple_all()
+ {
+ test_from_triple<std::range_slice, Cw>();
+ return true;
+ }
template<int Value>
using CW = std::constant_wrapper<Value, int>;
@@ -224,14 +244,14 @@ constexpr bool
test_all()
{
test_from_full_extent();
- test_from_tuple_all<CW>();
- test_from_tuple_all<IC>();
+ test_from_pair_all<CW>();
+ test_from_pair_all<IC>();
test_from_const_int<CW>();
test_from_const_int<IC>();
test_from_strided_slice<CW>();
test_from_strided_slice<IC>();
- test_from_range_slice<CW>();
- test_from_range_slice<IC>();
+ test_from_triple_all<CW>();
+ test_from_triple_all<IC>();
test_from_int_like_in_tuple<StructuralInt>();
return true;
}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents_neg.cc
index c81a1383e3cb..5b11424680df 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents_neg.cc
@@ -19,7 +19,7 @@ constexpr bool
test_invalid_stride_zero()
{
auto exts = std::extents(3, 5, 7);
- auto s = std::strided_slice{0, 1, 0};
+ auto s = std::strided_slice{0, 2, 0};
auto sub_exts = std::subextents(exts, 1, s, 2); // { dg-error "expansion of" }
return true;
}
@@ -34,9 +34,9 @@ test_out_of_bounds(const Slice& slice)
return true;
}
static_assert(test_out_of_bounds(std::strided_slice{0, 6, 1})); // { dg-error "expansion of" }
-static_assert(test_out_of_bounds(std::strided_slice{0, 7, 2})); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds(std::strided_slice{0, 4, 2})); // { dg-error "expansion of" }
static_assert(test_out_of_bounds(std::strided_slice{1, 6, 1})); // { dg-error "expansion of" }
-static_assert(test_out_of_bounds(std::strided_slice{1, 6, 2})); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds(std::strided_slice{1, 4, 2})); // { dg-error "expansion of" }
static_assert(test_out_of_bounds(std::tuple{1, 6})); // { dg-error "expansion of" }
static_assert(test_out_of_bounds(std::tuple{std::cw<1>, std::cw<6>})); // { dg-error "expansion of" }
static_assert(test_out_of_bounds(std::strided_slice{-1, 2, 1})); // { dg-error "expansion of" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc
index 39eb18cb03df..74fccc6f014b 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc
@@ -75,7 +75,7 @@ template<typename Layout>
constexpr bool
test_strided_slice_zero()
{
- check_slice_range<Layout>(1, std::strided_slice{1, 1, 0}, 2); // { dg-error "expansion of" }
+ check_slice_range<Layout>(1, std::strided_slice{1, 2, 0}, 2); // { dg-error "expansion of" }
return true;
}
static_assert(test_strided_slice_zero<std::layout_left>()); // { dg-error "expansion of" }
More information about the Libstdc++-cvs
mailing list