This patch implements the changes suggested in 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.
Futhermore, it expands the slice cannonicalization to support
triples (types that decompose into tree elements via structured
binding) in addition to pairs, where third element is interpreted
as stride value. This depends on support of packs inside structured
binding (__cpp_structured_bindings >= 202411L) for types other
that range_slice specializations, that is handled specially.
libstdc++-v3/ChangeLog:
* include/std/mdspan (__mdspan::__static_slice_extent)
(__mdspan::__dynamic_slice_extent): Return unmodified extent
value for strided_slice.
(__mdspan::__substrides_generic, __substrides_standardized):
Use multiplieds stride, if more than one element is requested.
(__mdspan::__canonical_range_slice): Define.
(__mdspan::__slice_cast): Use __canonical_range_slice for types
types that destructure into tree elements (including range_slice).
(__mdspan::__check_inrange_index): Define.
(__mdspan::__check_valid_slice): Validate if slice.offset +
(slice.extent - 1) * slice.stride fits into extent of given
dimension.
*
testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc:
Add test for range_slice and other triples.
*
testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_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/submdspan_extents.cc:
Likewise.
* testsuite/23_containers/mdspan/submdspan/submdspan_extents_neg.cc:
Likewise.
---
libstdc++-v3/include/std/mdspan | 207 +++++++++++++-----
.../mdspan/submdspan/selections/testcases.h | 12 +-
.../submdspan_canonicalize_slices.cc | 170 +++++++++++---
.../submdspan_canonicalize_slices_neg.cc | 33 +++
.../mdspan/submdspan/submdspan_extents.cc | 16 +-
.../mdspan/submdspan/submdspan_extents_neg.cc | 4 +-
6 files changed, 333 insertions(+), 109 deletions(-)
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index 570c1c0bda8..15e5a86cc2b 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -995,10 +995,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;
}
@@ -1008,7 +1006,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);
}
@@ -1122,7 +1120,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);
};
@@ -1167,7 +1165,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;
@@ -3236,6 +3234,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)
@@ -3246,52 +3290,65 @@ _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
{
+#if __cpp_structured_bindings >= 202411L
+ auto [__sbegin, __send, ...__sstrides] = std::move(__slice);
+#else
auto [__sbegin, __send] = std::move(__slice);
- auto __offset
+#endif
+
+ 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);
+#if __cpp_structured_bindings >= 202411L
+ static_assert(sizeof...(__sstrides) <= 1u);
+ if constexpr (sizeof...(__sstrides) > 0u)
+ return __mdspan::__canonical_range_slice<_IndexType>(
+ __cbegin, __cspan,
+
__mdspan::__canonical_index<_IndexType>(std::move(__sstrides))...
+ );
+ else
+#endif
+ 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,
@@ -3305,7 +3362,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
else
__glibcxx_assert(__idx <= __ext.extent(0));
-}
+ }
template<typename _IndexType, size_t _Extent, typename _Slice>
constexpr void
@@ -3314,34 +3371,66 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
if constexpr (__is_strided_slice<_Slice>)
{
- // 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);
+ static_assert(_Slice::extent_type::value == 0 ||
_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));
+ // 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.
+ 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 (_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
- __glibcxx_assert(__ext.extent(0) - __slice.offset
- >= __slice.extent);
+ {
+ __mdspan::__check_valid_index(__ext, __slice.offset);
+ __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/selections/testcases.h
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h
index d7b751d700c..eade9017e03 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/submdspan_canonicalize_slices.cc
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc
index 077bafc2a9b..52d8c9e349e 100644
---
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc
+++
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices.cc
@@ -114,90 +114,194 @@ 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::submdspan_canonicalize_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::submdspan_canonicalize_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::submdspan_canonicalize_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::submdspan_canonicalize_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::submdspan_canonicalize_slices(exts, raw_ccc);
+ assert_same(ccc.stride, std::cw<IndexType{1}>);
+
+ auto raw_ccd = Triple{cf, cf, cs.value};
+ auto [ccd] = std::submdspan_canonicalize_slices(exts, raw_ccd);
+ assert_same(ccd.stride, std::cw<IndexType{1}>);
+
+ auto raw_cdd = Triple{cf, cf.value, cs.value};
+ auto [cdd] = std::submdspan_canonicalize_slices(exts, raw_cdd);
+ assert_same(cdd.stride, IndexType(1));
+
+ auto raw_dcd = Triple{cf.value, cf, cs.value};
+ auto [dcd] = std::submdspan_canonicalize_slices(exts, raw_dcd);
+ assert_same(dcd.stride, IndexType(1));
+
+ auto raw_ddd = Triple{cf.value, cf.value, cs.value};
+ auto [ddd] = std::submdspan_canonicalize_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::submdspan_canonicalize_slices(exts, raw_cdc);
+ assert_same(cdc.stride, cstride);
+
+ auto raw_dcc = Triple{cf.value, cf, cs};
+ auto [dcc] = std::submdspan_canonicalize_slices(exts, raw_dcc);
+ assert_same(dcc.stride, cstride);
+
+ auto raw_ddc = Triple{cf.value, cf.value, cs};
+ auto [ddc] = std::submdspan_canonicalize_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)
+template<typename Lower, typename Upper, typename Stride>
+struct StridedRange
{
- 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::submdspan_canonicalize_slices(exts, raw_ccc);
- assert_same(ccc.stride, std::cw<IndexType{1}>);
+ Lower lower;
+ Upper upper;
+ Stride stride;
+};
- auto raw_ccd = std::strided_slice{c0, c0, cs.value};
- auto [ccd] = std::submdspan_canonicalize_slices(exts, raw_ccd);
- assert_same(ccd.stride, std::cw<IndexType{1}>);
+constexpr bool
+test_triple_all()
+{
+ test_triple<std::range_slice>();
+ test_triple<std::tuple>();
+ test_triple<StridedRange>();
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::submdspan_canonicalize_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::submdspan_canonicalize_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::submdspan_canonicalize_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::submdspan_canonicalize_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 +310,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/submdspan_canonicalize_slices_neg.cc
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc
index 94bca183aa3..7dc51166a0c 100644
---
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_slices_neg.cc
+++
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_canonicalize_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/submdspan_extents.cc
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents.cc
index 6210161ffd8..51f51f51c88 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents.cc
@@ -104,27 +104,25 @@ 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 = submdspan_extents(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 = submdspan_extents(exts, s0, s1, s2);
VERIFY(sub_exts.rank() == 3);
VERIFY(sub_exts.extent(0) == 2);
diff --git
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents_neg.cc
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents_neg.cc
index cf27c0c7e4d..41dfe651559 100644
---
a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents_neg.cc
+++
b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_extents_neg.cc
@@ -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" }
--
2.52.0