On Thu, Dec 4, 2025 at 10:28 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/submdspan.cc: > Restructed and new tests for layout_left_padded. > * testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc: > Ditto. > > Signed-off-by: Luc Grosheintz <[email protected]> > --- > Usual comments about static_assert, and split tests. And a small suggestion for expressing the condition. > libstdc++-v3/include/std/mdspan | 55 +++++- > .../23_containers/mdspan/layout_traits.h | 4 + > .../mdspan/submdspan/submdspan.cc | 3 + > .../mdspan/submdspan/submdspan_mapping.cc | 179 ++++++++++++++++-- > 4 files changed, 216 insertions(+), 25 deletions(-) > > diff --git a/libstdc++-v3/include/std/mdspan > b/libstdc++-v3/include/std/mdspan > index 8b6c24885ae..21dbe6def22 100644 > --- a/libstdc++-v3/include/std/mdspan > +++ b/libstdc++-v3/include/std/mdspan > @@ -795,40 +795,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > || (__static_quotient<_Extents, _IndexType>() != 0); > > template<typename _Layout, typename _Mapping> > concept __mapping_of = > is_same_v<typename _Layout::template mapping< > typename _Mapping::extents_type>, > _Mapping>; > > template<template<size_t> typename _Layout, typename _Mapping> > concept __padded_mapping_of = __mapping_of< > _Layout<_Mapping::padding_value>, _Mapping>; > > #ifdef __glibcxx_padded_layouts > template<typename _Mapping> > constexpr bool __is_left_padded_mapping = __padded_mapping_of< > layout_left_padded, _Mapping>; > > 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> > consteval size_t > __get_static_stride() > { return _PaddedMapping::_PaddedStorage::_S_static_stride; } > > template<typename _Mapping> > concept __standardized_mapping = __mapping_of<layout_left, _Mapping> > || __mapping_of<layout_right, > _Mapping> > || __mapping_of<layout_stride, > _Mapping> > #ifdef __glibcxx_padded_layouts > || > __is_left_padded_mapping<_Mapping> > || > __is_right_padded_mapping<_Mapping> > #endif > ; > > // A tag type to create internal ctors. > class __internal_ctor > { }; > @@ -1257,110 +1261,144 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > } > > template<_LayoutSide _Side, size_t _SubRank, size_t _Nm> > static consteval size_t > __padded_block_begin(span<const _SliceKind, _Nm> __slice_kinds) > { > if constexpr (_Side == _LayoutSide::__left) > return > __mdspan::__padded_block_begin_generic<_SubRank>(__slice_kinds); > else > { > std::array<_SliceKind, _Nm> __rev_slice_kinds; > for(size_t __i = 0; __i < _Nm; ++__i) > __rev_slice_kinds[__i] = __slice_kinds[_Nm - 1 - __i]; > > auto __u = __mdspan::__padded_block_begin_generic<_SubRank>( > std::span<const _SliceKind>(__rev_slice_kinds)); > return __u == dynamic_extent ? dynamic_extent : _Nm - 1 - __u; > } > } > > - 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>; > > 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>(0, _Us); > if constexpr (!__mdspan::__all_static(__sta_exts)) > return dynamic_extent; > else > return __mdspan::__fwd_prod(__sta_exts); > } > > template<size_t _SubRank, size_t _Nm> > static consteval bool > _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> > __slice_kinds) > { return __mdspan::__is_block<_SubRank>(__slice_kinds); } > }; > > 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 _SubRank, size_t _Nm> > + static consteval bool > + _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> > __slice_kinds) > + { > + if constexpr (_SubRank == 1) > I would preffer this being expressed as (which is equivalent), but would be easier to get: if constexpr (_SubRank > 1) return false; else return slice_kind_"check. > + 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>; > > template<typename _Mapping, size_t _Us> > static consteval size_t > _S_pad() > { > using _Extents = typename _Mapping::extents_type; > constexpr auto __rank = _Extents::rank(); > constexpr auto __sta_exts > = __mdspan::__static_extents<_Extents>(_Us + 1, __rank); > if constexpr (!__mdspan::__all_static(__sta_exts)) > return dynamic_extent; > else > return __fwd_prod(__sta_exts); > } > > template<size_t _SubRank, size_t _Nm> > static consteval bool > _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> > __slice_kinds) > { > auto __rev_slice_kinds = array<_SliceKind, _Nm>{}; > for(size_t __i = 0; __i < _Nm; ++__i) > __rev_slice_kinds[__i] = __slice_kinds[_Nm - 1 - __i]; > return __mdspan::__is_block<_SubRank>(span(__rev_slice_kinds)); > } > }; > > template<typename _Mapping> > constexpr auto > __submdspan_mapping_impl(const _Mapping& __mapping) > { return submdspan_mapping_result{__mapping, 0}; } > > template<typename _Mapping, typename... _Slices> > requires (sizeof...(_Slices) > 0) > constexpr auto > __submdspan_mapping_impl(const _Mapping& __mapping, _Slices... > __slices) > { > constexpr auto __side = __mdspan::__mapping_side<_Mapping>(); > - using _Trait = _SubMdspanMapping<__side>; > + using _Trait = _SubMdspanMapping<__side, > __is_padded_mapping<_Mapping>>; > > constexpr auto __slice_kinds = > __mdspan::__make_slice_kind_array<_Slices...>(); > auto __offset = __mdspan::__suboffset(__mapping, __slices...); > auto __sub_exts = __mdspan::__subextents(__mapping.extents(), > __slices...); > using _SubExts = decltype(__sub_exts); > constexpr auto __sub_rank = _SubExts::rank(); > if constexpr (__sub_rank == 0) > return submdspan_mapping_result{ > typename _Trait::_Layout::mapping(__sub_exts), __offset}; > else if constexpr ( > _Trait::template _S_is_unpadded_submdspan<__sub_rank>( > std::span<const _SliceKind, > __slice_kinds.size()>(__slice_kinds))) > return submdspan_mapping_result{ > typename _Trait::_Layout::mapping(__sub_exts), __offset}; > else if constexpr ( > constexpr auto __u = __padded_block_begin<__side, __sub_rank>( > span<const _SliceKind, __slice_kinds.size()>(__slice_kinds)); > __u != dynamic_extent) > { > constexpr auto __pad = _Trait::template _S_pad<_Mapping, > __u>(); > @@ -2536,40 +2574,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > constexpr index_type > stride(rank_type __r) const noexcept > { > __glibcxx_assert(__r < _S_rank); > if (__r == 0) > return 1; > else > return static_cast<index_type>( > static_cast<size_t>(_M_padstride()) * > static_cast<size_t>(__mdspan::__fwd_prod(extents(), 1, > __r))); > } > > template<typename _LeftpadMapping> > requires(__mdspan::__is_left_padded_mapping<_LeftpadMapping> > && _LeftpadMapping::extents_type::rank() == _S_rank) > friend constexpr bool > operator==(const mapping& __self, const _LeftpadMapping& __other) > noexcept > { return __self._M_storage._M_equal(__other); } > + > + private: > +#if __glibcxx_submdspan > + template<__mdspan::__acceptable_slice_type<index_type>... _Slices> > Again this will go away for static assert. > + 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> > template<typename _Extents> > class layout_right_padded<_PaddingValue>::mapping { > public: > static constexpr size_t padding_value = _PaddingValue; > using extents_type = _Extents; > using index_type = typename extents_type::index_type; > using size_type = typename extents_type::size_type; > using rank_type = typename extents_type::rank_type; > using layout_type = layout_right_padded<_PaddingValue>; > > private: > static constexpr size_t _S_rank = extents_type::rank(); > using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue, > _Extents, __mdspan::_RightPaddedLayoutTraits<_S_rank>>; > [[no_unique_address]] _PaddedStorage _M_storage; > > consteval friend size_t > 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 > @@ -70,79 +70,83 @@ struct DeducePaddingSide > constexpr static PaddingSide > from_typename() > { > if constexpr (std::same_as<Layout, std::layout_left>) > return PaddingSide::Left; > else if constexpr (is_left_padded<Layout>) > return PaddingSide::Left; > else > return PaddingSide::Right; > } > }; > > template<PaddingSide Side> > struct LayoutTraits; > > template<> > struct LayoutTraits<PaddingSide::Left> > { > 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; > > template<typename Extents> > constexpr static extents_type<Extents> > make_extents(const Extents& exts) > { return exts; } > > template<typename T, size_t N> > constexpr static std::array<T, N> > make_array(const std::array<T, N>& a) > { return a; } > > template<typename... Indices> > constexpr static auto > make_indices(Indices... indices) > { return std::array{indices...}; } > > template<typename... Ts> > constexpr static std::tuple<Ts...> > make_tuple(const std::tuple<Ts...>& tup) > { return tup; } > > template<typename Mapping> > constexpr static auto > padded_stride(const Mapping& m) > { return m.stride(1); } > > template<typename Extents> > constexpr static auto > padded_extent(const Extents& exts) > { return exts.extent(0); } > }; > > 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> > constexpr static auto > make_extents(const std::extents<IndexType, Extents...>& exts) > { > constexpr size_t rank = sizeof...(Extents); > auto impl = [&]<size_t... I>(std::index_sequence<I...>) > { > auto dyn_exts = make_array(dynamic_extents_array(exts)); > return std::extents<IndexType, Extents...[rank - 1 - > I]...>(dyn_exts); > }; > return impl(std::make_index_sequence<rank>()); > } > > template<typename Extents> > using extents_type = > decltype(make_extents(std::declval<Extents>())); > > template<typename T, size_t N> > constexpr static std::array<T, N> > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan.cc > index 645c4711294..927b5d06c6b 100644 > --- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan.cc > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan.cc > @@ -348,24 +348,27 @@ template<typename Layout> > }; > > run(std::extents(3, 5, 7)); > run(std::extents<int, 3, 5, 7>{}); > return true; > } > > template<typename Layout> > constexpr bool > test_all() > { > test_all_cheap<Layout>(); > test_all_expensive<Layout>(); > return true; > } > > int > main() > { > test_all<std::layout_left>(); > + test_all<std::layout_left_padded<1>>(); > + test_all<std::layout_left_padded<8>>(); > + test_all<std::layout_left_padded<dyn>>(); > To separate test files. > test_all<std::layout_right>(); > test_all<std::layout_stride>(); > 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 > @@ -1,69 +1,63 @@ > // { dg-do run { target c++26 } } > #include <mdspan> > > #include <iostream> // TODO remove > #include "../layout_traits.h" > #include <testsuite_hooks.h> > > constexpr size_t dyn = std::dynamic_extent; > +constexpr auto all = std::full_extent; > > template<typename Mapping, typename... Slices> > constexpr auto > call_submdspan_mapping(const Mapping& m, std::tuple<Slices...> slices) > { > auto impl = [&]<size_t... I>(std::index_sequence<I...>) > { return submdspan_mapping(m, get<I>(slices)...); }; > return impl(std::make_index_sequence<sizeof...(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()); > auto result = submdspan_mapping(m0); > using layout_type = typename decltype(result.mapping)::layout_type; > static_assert(std::same_as<layout_type, 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>); > } > > { > auto s0 = std::strided_slice{1, 1, std::cw<1>}; > auto slices = std::tuple{s0, 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(is_same_padded<padding_side, layout_type>); > } > > { > auto s0 = std::strided_slice{1, 2, std::cw<1>}; > auto slices = std::tuple{s0, 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(is_same_padded<padding_side, layout_type>); > } > > { > auto s0 = std::strided_slice{1, 2, std::cw<1>}; > @@ -81,80 +75,223 @@ template<typename Layout> > static_assert(std::same_as<layout_type, std::layout_stride>); > } > > { > auto slices = std::tuple{1, all, all, s251, 0}; > auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); > using layout_type = decltype(result.mapping)::layout_type; > static_assert(std::same_as<layout_type, std::layout_stride>); > } > > { > auto s3 = std::strided_slice{2, std::cw<7>, std::cw<2>}; > auto slices = std::tuple{all, all, all, s3, 0}; > auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); > using layout_type = 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_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() > { > 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) > { > 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); > }; > > check(std::extents(std::cw<3>, std::cw<5>, std::cw<7>, 11, 13), 3*5); > check(std::extents(std::cw<3>, std::cw<5>, 7, 11, 13), 3*5); > check(std::extents(std::cw<3>, 5, 7, 11, 13), dyn); > check(std::extents(3, 5, 7, 11, 13), dyn); > 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() > { > auto exts = std::extents(3, 5); > auto m = std::layout_stride::mapping(exts, std::array{2, 12}); > > using index_type = decltype(exts)::index_type; > auto s1 = std::strided_slice{index_type(2), index_type(2), > std::cw<index_type(2)>}; > auto result = submdspan_mapping(m, index_type(1), s1); > using layout_type = decltype(result.mapping)::layout_type; > static_assert(std::same_as<layout_type, std::layout_stride>); > 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 > >
