https://gcc.gnu.org/g:558ab7b6389e2dc8dcd5e9da2c982e79a3cdd42c
commit r16-5997-g558ab7b6389e2dc8dcd5e9da2c982e79a3cdd42c Author: Luc Grosheintz <[email protected]> Date: Mon Dec 8 21:23:44 2025 +0100 libstdc++: Implement submdspan_mapping for layout_left_padded. [PR110352] 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 <[email protected]> Signed-off-by: Luc Grosheintz <[email protected]> Diff: --- libstdc++-v3/include/std/mdspan | 56 ++++++- .../testsuite/23_containers/mdspan/layout_traits.h | 4 + .../mdspan/submdspan/selections/left_padded.cc | 12 ++ .../mdspan/submdspan/submdspan_mapping.cc | 179 ++++++++++++++++++--- 4 files changed, 226 insertions(+), 25 deletions(-) diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index 6386a26e392d..12413a0662fb 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 619cab53b9e7..f0aeac320de0 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.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc new file mode 100644 index 000000000000..711ce35b6e45 --- /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<std::layout_left_padded<1>>(); + test_all<std::layout_left_padded<8>>(); + 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 cf6167dc3b0f..50836968a06b 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; }
