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;
 }

Reply via email to