https://gcc.gnu.org/g:3edcf6a22576d076df6d86f0bfe4a453c057eea7
commit r16-8411-g3edcf6a22576d076df6d86f0bfe4a453c057eea7 Author: Tomasz Kamiński <[email protected]> Date: Tue Dec 16 18:03:23 2025 +0100 libstdc++: Implement range_slice from P3982R2. This patch add a range_slice a class, and maps it to strided_slice with the original meanning. This is usefull for benchmark, as effects of strided_slice remain stable before and after the change. libstdc++-v3/ChangeLog: * src/c++23/std.cc.in (range_slice): Export. * include/std/mdspan (range_slice, __mdspan::__is_range_slice): Define. (__mdspan::__slice_cast): Handle strided_slice. * testsuite/23_containers/mdspan/submdspan/subextents.cc: Sanity tests for range_slice. Reviewed-by: Jonathan Wakely <[email protected]> Signed-off-by: Tomasz Kamiński <[email protected]> Diff: --- libstdc++-v3/include/std/mdspan | 33 +++++++++ libstdc++-v3/src/c++23/std.cc.in | 1 + .../23_containers/mdspan/submdspan/subextents.cc | 82 ++++++++++++++++++++++ 3 files changed, 116 insertions(+) diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index 2d3e82a9980d..7f02b3460546 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -374,6 +374,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION [[no_unique_address]] stride_type stride{}; }; + template<typename _FirstType, typename _LastType, typename _StrideType = constant_wrapper<1zu>> + struct range_slice + { + static_assert(__is_signed_or_unsigned_integer<_FirstType>::value + || __detail::__integral_constant_like<_FirstType>); + static_assert(__is_signed_or_unsigned_integer<_LastType>::value + || __detail::__integral_constant_like<_LastType>); + static_assert(__is_signed_or_unsigned_integer<_StrideType>::value + || __detail::__integral_constant_like<_StrideType>); + + [[no_unique_address]] _FirstType first{}; + [[no_unique_address]] _LastType last{}; + [[no_unique_address]] _StrideType stride{}; + }; + template<typename _Mapping> struct submdspan_mapping_result { @@ -870,6 +885,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr bool __is_strided_slice<strided_slice<_OffsetType, _ExtentType, _StrideType>> = true; + template<typename _Tp> + constexpr bool __is_range_slice = false; + + template<typename _FirstType, typename _LastType, typename _StrideType> + constexpr bool __is_range_slice<range_slice<_FirstType, + _LastType, _StrideType>> = true; + template<typename _IndexType, typename _OIndexType> consteval bool __is_representable_integer(_OIndexType __value) @@ -3301,6 +3323,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION = __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}); + } else { auto [__sbegin, __send] = std::move(__slice); diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in index e857463812be..32e167be0c1c 100644 --- a/libstdc++-v3/src/c++23/std.cc.in +++ b/libstdc++-v3/src/c++23/std.cc.in @@ -1915,6 +1915,7 @@ export namespace std #endif #if __glibcxx_submdspan using std::strided_slice; + using std::range_slice; using std::full_extent_t; using std::full_extent; using std::submdspan_mapping_result; diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc index ae77d3d96a89..464b253ff4d8 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/subextents.cc @@ -134,6 +134,86 @@ template<template<int> typename Cw> return true; } +template<template<int> typename Cw> + constexpr bool + test_from_range_slice() + { + 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 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) == 0); + VERIFY(sub_exts.static_extent(1) == 0); + } + + { + auto s0 = 1; + auto s1 = std::range_slice{0, 2, Cw<1>{}}; + auto s2 = std::range_slice{1, 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(1) == dyn); + VERIFY(sub_exts.extent(1) == 2); + } + + { + auto s0 = 1; + auto s1 = std::range_slice{0, 2, Cw<1>{}}; + auto s2 = std::range_slice{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); + VERIFY(sub_exts.extent(0) == 2); + VERIFY(sub_exts.static_extent(1) == dyn); + VERIFY(sub_exts.extent(1) == 2); + } + + { + // 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 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(1) == dyn); + VERIFY(sub_exts.extent(1) == 4); + } + + { + // 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 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(1) == 4); + } + + { + // 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 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<int Value> using CW = std::constant_wrapper<Value, int>; @@ -150,6 +230,8 @@ test_all() 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_int_like_in_tuple<StructuralInt>(); return true; }
