[gcc r16-8411] libstdc++: Implement range_slice from P3982R2.
Tomasz Kaminski
tkaminsk@gcc.gnu.org
Thu Apr 2 07:43:43 GMT 2026
https://gcc.gnu.org/g:3edcf6a22576d076df6d86f0bfe4a453c057eea7
commit r16-8411-g3edcf6a22576d076df6d86f0bfe4a453c057eea7
Author: Tomasz Kamiński <tkaminsk@redhat.com>
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 <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
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;
}
More information about the Libstdc++-cvs
mailing list