https://gcc.gnu.org/g:e920613db52adece7e3de5f2a2812247c72782f6
commit r16-8412-ge920613db52adece7e3de5f2a2812247c72782f6 Author: Tomasz Kamiński <[email protected]> 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 <[email protected]> Signed-off-by: Tomasz Kamiński <[email protected]> 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" }
