From 558ab7b6389e2dc8dcd5e9da2c982e79a3cdd42c Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Mon, 8 Dec 2025 21:23:44 +0100 Subject: [PATCH] libstdc++: Implement submdspan_mapping for layout_left_padded. [PR110352] MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Implements submdspan for layout_left_padded as described in P3663. PR libstdc++/110352 libstdc++-v3/ChangeLog: * include/std/mdspan (__mdspan::__is_padded_mapping): Define. (__mdspan::_SubMdspanMapping): Add _Padded template parameter. (__mdspan::_SubMdspanMapping<_LayoutSide::__left, true>): Define. (__mdspan::__submdspan_mapping_impl): Updated _Trait alias. (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.cc: Instantiate tests for layout_left_padded. * testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc: Ditto. Reviewed-by: Tomasz Kamiński Signed-off-by: Luc Grosheintz --- libstdc++-v3/include/std/mdspan | 56 +++++- .../23_containers/mdspan/layout_traits.h | 4 + .../submdspan/selections/left_padded.cc | 12 ++ .../mdspan/submdspan/submdspan_mapping.cc | 179 ++++++++++++++++-- 4 files changed, 226 insertions(+), 25 deletions(-) create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index 6386a26e392..12413a0662f 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -812,6 +812,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template constexpr bool __is_right_padded_mapping = __padded_mapping_of< layout_right_padded, _Mapping>; + + template + constexpr bool __is_padded_mapping = __is_left_padded_mapping<_Mapping> + || __is_right_padded_mapping<_Mapping>; #endif template @@ -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 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 using _PaddedLayout = layout_left_padded<_Pad>; + + template + 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 + static consteval bool + _S_is_unpadded_submdspan(span __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 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; 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 + 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 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 + using layout_same_padded = std::layout_left_padded; template using extents_type = Extents; @@ -126,6 +128,8 @@ template<> struct LayoutTraits { using layout_same = std::layout_right; + template + using layout_same_padded = std::layout_right_padded; using layout_other = std::layout_left; template diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc new file mode 100644 index 00000000000..711ce35b6e4 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc @@ -0,0 +1,12 @@ +// { dg-do run { target c++26 } } +// { dg-timeout-factor 2 } +#include "testcases.h" + +int +main() +{ + test_all>(); + test_all>(); + test_all>(); + 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 constexpr size_t dyn = std::dynamic_extent; +constexpr auto all = std::full_extent; template constexpr auto @@ -18,10 +19,11 @@ template template constexpr bool - test_layout_unpadded_return_types() + test_layout_common_return_types() { constexpr auto padding_side = DeducePaddingSide::from_typename(); using Traits = LayoutTraits; + using layout_unpadded = typename Traits::layout_same; { auto m0 = typename Layout::mapping(std::extents()); @@ -32,21 +34,13 @@ template 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); - } - - { - 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); + static_assert(std::same_as); } { @@ -98,6 +92,72 @@ template return true; } +template + constexpr bool + test_layout_unpadded_return_types() + { + constexpr auto padding_side = DeducePaddingSide::from_typename(); + using Traits = LayoutTraits; + + 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); + } + return true; + } + +template + constexpr bool + test_layout_padded_return_types() + { + constexpr auto padding_side = DeducePaddingSide::from_typename(); + using Traits = LayoutTraits; + + 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; + static_assert(std::same_as); + } + + { + 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); + } + + { + 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); + } + + { + 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); + } + return true; + } + template constexpr bool test_layout_unpadded_padding_value() @@ -105,7 +165,6 @@ template using Traits = LayoutTraits()>; auto s0 = std::strided_slice{size_t(1), size_t(2), std::cw}; auto s3 = std::strided_slice{size_t(2), size_t(5), std::cw}; - auto all = std::full_extent; auto check = [&](auto exts, size_t expected) { @@ -123,6 +182,52 @@ template return true; } +template +constexpr size_t static_padding_value = 1; + +template +constexpr size_t static_padding_value> = PaddingValue; + +template +constexpr size_t static_padding_value> = PaddingValue; + +template + constexpr bool + test_layout_padded_padding_value() + { + using Traits = LayoutTraits()>; + auto s0 = std::strided_slice{size_t(1), size_t(2), std::cw}; + auto s3 = std::strided_slice{size_t(2), size_t(5), std::cw}; + + 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; + 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 + constexpr bool + test_return_types_all() + { + return true; + } + +template + constexpr bool + test_return_types_unpadded_all() + { + test_layout_common_return_types(); + static_assert(test_layout_common_return_types()); + + test_layout_unpadded_return_types(); + static_assert(test_layout_unpadded_return_types()); + + test_layout_unpadded_padding_value(); + static_assert(test_layout_unpadded_padding_value()); + return true; + } + +template + constexpr bool + test_return_types_padded_all() + { + test_layout_common_return_types(); + static_assert(test_layout_common_return_types()); + + test_layout_padded_return_types(); + static_assert(test_layout_padded_return_types()); + + test_layout_padded_padding_value(); + static_assert(test_layout_padded_padding_value()); + return true; + } + int main() { - test_layout_unpadded_return_types(); - static_assert(test_layout_unpadded_return_types()); + test_return_types_unpadded_all(); + test_return_types_unpadded_all(); - test_layout_unpadded_return_types(); - static_assert(test_layout_unpadded_return_types()); + test_return_types_padded_all>(); + test_return_types_padded_all>(); + test_return_types_padded_all>(); test_layout_stride_return_types(); static_assert(test_layout_stride_return_types()); - - test_layout_unpadded_padding_value(); - static_assert(test_layout_unpadded_padding_value()); - - test_layout_unpadded_padding_value(); - static_assert(test_layout_unpadded_padding_value()); return 0; } -- 2.47.3