On Mon, Dec 8, 2025 at 9:21 PM Luc Grosheintz <[email protected]>
wrote:

> Implements submdspan for layout_left_padded as described in P3663.
>
>         PR libstdc++/110352
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/mdspan (layout_left_padded::submdspan_mapping):
>         New friend method.
>         * testsuite/23_containers/mdspan/layout_traits.h
>         (LayoutTraits::layout_same_padded): New template type alias.
>         *
> testsuite/23_containers/mdspan/submdspan/selections/left_padded_1.cc:
>         Instantiate tests for layout_left_padded.
>         *
> testsuite/23_containers/mdspan/submdspan/selections/left_padded_8.cc:
>         Ditto.
>         *
> testsuite/23_containers/mdspan/submdspan/selections/left_padded_dyn.cc:
>         Ditto.
>
I will see if I can merge this 3 files and still be without timeout, if so
I will push them merged.

>         * testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc:
>         Ditto.
>
> Signed-off-by: Luc Grosheintz <[email protected]>
> ---
>
LGTM.

>  libstdc++-v3/include/std/mdspan               |  56 +++++-
>  .../23_containers/mdspan/layout_traits.h      |   4 +
>  .../submdspan/selections/left_padded_1.cc     |   9 +
>  .../submdspan/selections/left_padded_8.cc     |   9 +
>  .../submdspan/selections/left_padded_dyn.cc   |   9 +
>  .../mdspan/submdspan/submdspan_mapping.cc     | 179 ++++++++++++++++--
>  6 files changed, 241 insertions(+), 25 deletions(-)
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_1.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_8.cc
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_dyn.cc
>
> diff --git a/libstdc++-v3/include/std/mdspan
> b/libstdc++-v3/include/std/mdspan
> index 16dda4c8468..520cf322d8c 100644
> --- a/libstdc++-v3/include/std/mdspan
> +++ b/libstdc++-v3/include/std/mdspan
> @@ -812,6 +812,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      template<typename _Mapping>
>        constexpr bool __is_right_padded_mapping = __padded_mapping_of<
>         layout_right_padded, _Mapping>;
> +
> +    template<typename _Mapping>
> +      constexpr bool __is_padded_mapping =
> __is_left_padded_mapping<_Mapping>
> +        || __is_right_padded_mapping<_Mapping>;
>  #endif
>
>      template<typename _PaddedMapping>
> @@ -1276,11 +1280,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>           }
>        }
>
> -    template<_LayoutSide _Side>
> +    template<_LayoutSide _Side, bool _Padded>
>        struct _SubMdspanMapping;
>
>      template<>
> -      struct _SubMdspanMapping<_LayoutSide::__left>
> +      struct _SubMdspanMapping<_LayoutSide::__left, false>
>        {
>         using _Layout = layout_left;
>         template<size_t _Pad> using _PaddedLayout =
> layout_left_padded<_Pad>;
> @@ -1304,7 +1308,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        };
>
>      template<>
> -      struct _SubMdspanMapping<_LayoutSide::__right>
> +      struct _SubMdspanMapping<_LayoutSide::__left, true>
> +      {
> +       using _Layout = layout_left;
> +       template<size_t _Pad> using _PaddedLayout =
> layout_left_padded<_Pad>;
> +
> +       template<typename _Mapping, size_t _Us>
> +         static consteval size_t
> +         _S_pad()
> +         {
> +           using _Extents = typename _Mapping::extents_type;
> +           constexpr auto __sta_exts
> +             = __mdspan::__static_extents<_Extents>(1, _Us);
> +           constexpr auto __sta_padstride
> +             = __mdspan::__get_static_stride<_Mapping>();
> +           if constexpr (__sta_padstride == dynamic_extent
> +                         || !__mdspan::__all_static(__sta_exts))
> +             return dynamic_extent;
> +           else
> +             return __sta_padstride * __mdspan::__fwd_prod(__sta_exts);
> +         }
> +
> +       template<size_t _Nm>
> +         static consteval bool
> +         _S_is_unpadded_submdspan(span<const _SliceKind, _Nm>
> __slice_kinds,
> +                                  size_t __sub_rank)
> +         {
> +           if (__sub_rank == 1)
> +             return __slice_kinds[0] == _SliceKind::__unit_strided_slice
> +               || __slice_kinds[0] == _SliceKind::__full;
> +           else
> +             return false;
> +         }
> +      };
> +
> +    template<>
> +      struct _SubMdspanMapping<_LayoutSide::__right, false>
>        {
>         using _Layout = layout_right;
>         template<size_t _Pad> using _PaddedLayout =
> layout_right_padded<_Pad>;
> @@ -1350,7 +1389,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
>         constexpr auto __side = __mdspan::__mapping_side<_Mapping>();
>         constexpr auto __rank = sizeof...(_Slices);
> -       using _Trait = _SubMdspanMapping<__side>;
> +       using _Trait = _SubMdspanMapping<__side,
> __is_padded_mapping<_Mapping>>;
>         using _SliceView = span<const _SliceKind, __rank>;
>
>         constexpr auto __slice_kinds =
> __mdspan::__make_slice_kind_array<_Slices...>();
> @@ -2558,6 +2597,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>           operator==(const mapping& __self, const _LeftpadMapping& __other)
>           noexcept
>           { return __self._M_storage._M_equal(__other); }
> +
> +      private:
> +#if __glibcxx_submdspan
> +       template<typename... _Slices>
> +         requires (extents_type::rank() == sizeof...(_Slices))
> +         friend constexpr auto
> +         submdspan_mapping(const mapping& __mapping, _Slices... __slices)
> +         { return __mdspan::__submdspan_mapping_impl(__mapping,
> __slices...); }
> +#endif // __glibcxx_submdspan
>        };
>
>    template<size_t _PaddingValue>
> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h
> b/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h
> index 619cab53b9e..f0aeac320de 100644
> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h
> @@ -87,6 +87,8 @@ template<>
>    {
>      using layout_same = std::layout_left;
>      using layout_other = std::layout_right;
> +    template<size_t PaddingValue>
> +      using layout_same_padded = std::layout_left_padded<PaddingValue>;
>
>      template<typename Extents>
>        using extents_type = Extents;
> @@ -126,6 +128,8 @@ template<>
>    struct LayoutTraits<PaddingSide::Right>
>    {
>      using layout_same = std::layout_right;
> +    template<size_t PaddingValue>
> +      using layout_same_padded = std::layout_right_padded<PaddingValue>;
>      using layout_other = std::layout_left;
>
>      template<typename IndexType, size_t... Extents>
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_1.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_1.cc
> new file mode 100644
> index 00000000000..b21de0cb59a
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_1.cc
> @@ -0,0 +1,9 @@
> +// { dg-do run { target c++26 } }
> +#include "testcases.h"
> +
> +int
> +main()
> +{
> +  test_all<std::layout_left_padded<1>>();
> +  return 0;
> +}
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_8.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_8.cc
> new file mode 100644
> index 00000000000..f2402d833f3
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_8.cc
> @@ -0,0 +1,9 @@
> +// { dg-do run { target c++26 } }
> +#include "testcases.h"
> +
> +int
> +main()
> +{
> +  test_all<std::layout_left_padded<8>>();
> +  return 0;
> +}
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_dyn.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_dyn.cc
> new file mode 100644
> index 00000000000..0f6e4e35550
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded_dyn.cc
> @@ -0,0 +1,9 @@
> +// { dg-do run { target c++26 } }
> +#include "testcases.h"
> +
> +int
> +main()
> +{
> +  test_all<std::layout_left_padded<dyn>>();
> +  return 0;
> +}
> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc
> index cf6167dc3b0..50836968a06 100644
> ---
> a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc
> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc
> @@ -6,6 +6,7 @@
>  #include <testsuite_hooks.h>
>
>  constexpr size_t dyn = std::dynamic_extent;
> +constexpr auto all = std::full_extent;
>
>  template<typename Mapping, typename... Slices>
>    constexpr auto
> @@ -18,10 +19,11 @@ template<typename Mapping, typename... Slices>
>
>  template<typename Layout>
>    constexpr bool
> -  test_layout_unpadded_return_types()
> +  test_layout_common_return_types()
>    {
>      constexpr auto padding_side =
> DeducePaddingSide::from_typename<Layout>();
>      using Traits = LayoutTraits<padding_side>;
> +    using layout_unpadded = typename Traits::layout_same;
>
>      {
>        auto m0 = typename Layout::mapping(std::extents());
> @@ -32,21 +34,13 @@ template<typename Layout>
>
>      auto exts = Traits::make_extents(std::dims<5, int>(3, 5, 7, 11, 13));
>      auto m = typename Layout::mapping(exts);
> -    auto all = std::full_extent;
>      auto s251 = std::strided_slice{2, 5, std::cw<1>};
>
>      {
>        auto slices = std::tuple{0, 0, 0, 0, 0};
>        auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
>        using layout_type = typename decltype(result.mapping)::layout_type;
> -      static_assert(std::same_as<layout_type, Layout>);
> -    }
> -
> -    {
> -      auto slices = std::tuple{all, all, all, s251, 0};
> -      auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
> -      using layout_type = typename decltype(result.mapping)::layout_type;
> -      static_assert(std::same_as<layout_type, Layout>);
> +      static_assert(std::same_as<layout_type, layout_unpadded>);
>      }
>
>      {
> @@ -98,6 +92,72 @@ template<typename Layout>
>      return true;
>    }
>
> +template<typename Layout>
> +  constexpr bool
> +  test_layout_unpadded_return_types()
> +  {
> +    constexpr auto padding_side =
> DeducePaddingSide::from_typename<Layout>();
> +    using Traits = LayoutTraits<padding_side>;
> +
> +    auto exts = Traits::make_extents(std::dims<5, int>(3, 5, 7, 11, 13));
> +    auto m = typename Layout::mapping(exts);
> +    auto s251 = std::strided_slice{2, 5, std::cw<1>};
> +
> +    {
> +      auto slices = std::tuple{all, all, all, s251, 0};
> +      auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
> +      using layout_type = typename decltype(result.mapping)::layout_type;
> +      static_assert(std::same_as<layout_type, Layout>);
> +    }
> +    return true;
> +  }
> +
> +template<typename Layout>
> +  constexpr bool
> +  test_layout_padded_return_types()
> +  {
> +    constexpr auto padding_side =
> DeducePaddingSide::from_typename<Layout>();
> +    using Traits = LayoutTraits<padding_side>;
> +
> +    auto exts = Traits::make_extents(std::dims<5, int>(3, 5, 7, 11, 13));
> +    auto m = typename Layout::mapping(exts);
> +    auto s251 = std::strided_slice{2, 5, std::cw<1>};
> +
> +    {
> +      auto slices = std::tuple{all, all, all, s251, 0};
> +      auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
> +      using layout_type = typename decltype(result.mapping)::layout_type;
> +      using layout_expected = typename Traits::layout_same_padded<dyn>;
> +      static_assert(std::same_as<layout_type, layout_expected>);
> +    }
> +
> +    {
> +      auto slices = std::tuple{all, 0, 0, 0, 0};
> +      auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
> +      using layout_type = typename decltype(result.mapping)::layout_type;
> +      using layout_expected = typename Traits::layout_same;
> +      static_assert(std::same_as<layout_type, layout_expected>);
> +    }
> +
> +    {
> +      auto s121 = std::strided_slice{1, 2, std::cw<1>};
> +      auto slices = std::tuple{s121, 0, 0, 0, 0};
> +      auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
> +      using layout_type = typename decltype(result.mapping)::layout_type;
> +      using layout_expected = typename Traits::layout_same;
> +      static_assert(std::same_as<layout_type, layout_expected>);
> +    }
> +
> +    {
> +      auto s121 = std::strided_slice{1, 2, std::cw<1>};
> +      auto slices = std::tuple{0, s121, 0, 0, 0};
> +      auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
> +      using layout_type = typename decltype(result.mapping)::layout_type;
> +      static_assert(std::same_as<layout_type, std::layout_stride>);
> +    }
> +    return true;
> +  }
> +
>  template<typename Layout>
>    constexpr bool
>    test_layout_unpadded_padding_value()
> @@ -105,7 +165,6 @@ template<typename Layout>
>      using Traits =
> LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
>      auto s0 = std::strided_slice{size_t(1), size_t(2),
> std::cw<size_t(1)>};
>      auto s3 = std::strided_slice{size_t(2), size_t(5),
> std::cw<size_t(1)>};
> -    auto all = std::full_extent;
>
>      auto check = [&](auto exts, size_t expected)
>      {
> @@ -123,6 +182,52 @@ template<typename Layout>
>      return true;
>    }
>
> +template<typename Layout>
> +constexpr size_t static_padding_value = 1;
> +
> +template<size_t PaddingValue>
> +constexpr size_t
> static_padding_value<std::layout_left_padded<PaddingValue>> = PaddingValue;
> +
> +template<size_t PaddingValue>
> +constexpr size_t
> static_padding_value<std::layout_right_padded<PaddingValue>> = PaddingValue;
> +
> +template<typename Layout>
> +  constexpr bool
> +  test_layout_padded_padding_value()
> +  {
> +    using Traits =
> LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
> +    auto s0 = std::strided_slice{size_t(1), size_t(2),
> std::cw<size_t(1)>};
> +    auto s3 = std::strided_slice{size_t(2), size_t(5),
> std::cw<size_t(1)>};
> +
> +    auto check = [&](auto exts, size_t expected)
> +    {
> +      auto m = typename Layout::mapping(Traits::make_extents(exts));
> +      auto slices = std::tuple{s0, size_t(0), all, s3, size_t(0)};
> +      auto result = call_submdspan_mapping(m, Traits::make_tuple(slices));
> +      auto padding_value = decltype(result.mapping)::padding_value;
> +      VERIFY(padding_value == expected);
> +    };
> +
> +    auto pad = [](int n, int m) -> size_t
> +    {
> +      constexpr auto padding_value = static_padding_value<Layout>;
> +      if constexpr (padding_value != dyn)
> +       {
> +         auto npad = ((n + padding_value - 1) / padding_value) *
> padding_value;
> +         return npad * m;
> +       }
> +      else
> +       return dyn;
> +    };
> +
> +    check(std::extents(std::cw<3>, std::cw<5>, std::cw<7>, 11, 13),
> pad(3, 5));
> +    check(std::extents(std::cw<3>, std::cw<5>, 7, 11, 13), pad(3, 5));
> +    check(std::extents(std::cw<3>, std::cw<6>, 7, 11, 13), pad(3, 6));
> +    check(std::extents(std::cw<3>, 5, 7, 11, 13), dyn);
> +    check(std::extents(3, 5, 7, 11, 13), dyn);
> +    return true;
> +  }
> +
>  constexpr bool
>  test_layout_stride_return_types()
>  {
> @@ -138,23 +243,55 @@ test_layout_stride_return_types()
>    return true;
>  }
>
> +template<typename Layout>
> +  constexpr bool
> +  test_return_types_all()
> +  {
> +    return true;
> +  }
> +
> +template<typename Layout>
> +  constexpr bool
> +  test_return_types_unpadded_all()
> +  {
> +    test_layout_common_return_types<Layout>();
> +    static_assert(test_layout_common_return_types<Layout>());
> +
> +    test_layout_unpadded_return_types<Layout>();
> +    static_assert(test_layout_unpadded_return_types<Layout>());
> +
> +    test_layout_unpadded_padding_value<Layout>();
> +    static_assert(test_layout_unpadded_padding_value<Layout>());
> +    return true;
> +  }
> +
> +template<typename Layout>
> +  constexpr bool
> +  test_return_types_padded_all()
> +  {
> +    test_layout_common_return_types<Layout>();
> +    static_assert(test_layout_common_return_types<Layout>());
> +
> +    test_layout_padded_return_types<Layout>();
> +    static_assert(test_layout_padded_return_types<Layout>());
> +
> +    test_layout_padded_padding_value<Layout>();
> +    static_assert(test_layout_padded_padding_value<Layout>());
> +    return true;
> +  }
> +
>  int
>  main()
>  {
> -  test_layout_unpadded_return_types<std::layout_left>();
> -  static_assert(test_layout_unpadded_return_types<std::layout_left>());
> +  test_return_types_unpadded_all<std::layout_left>();
> +  test_return_types_unpadded_all<std::layout_right>();
>
> -  test_layout_unpadded_return_types<std::layout_right>();
> -  static_assert(test_layout_unpadded_return_types<std::layout_right>());
> +  test_return_types_padded_all<std::layout_left_padded<1>>();
> +  test_return_types_padded_all<std::layout_left_padded<2>>();
> +  test_return_types_padded_all<std::layout_left_padded<dyn>>();
>
>    test_layout_stride_return_types();
>    static_assert(test_layout_stride_return_types());
> -
> -  test_layout_unpadded_padding_value<std::layout_left>();
> -  static_assert(test_layout_unpadded_padding_value<std::layout_left>());
> -
> -  test_layout_unpadded_padding_value<std::layout_right>();
> -  static_assert(test_layout_unpadded_padding_value<std::layout_right>());
>    return 0;
>  }
>
> --
> 2.52.0
>
>

Reply via email to