[v4,4/5] libstdc++: Implement submdspan_mapping for layout_left_padded. [PR110352]
Commit Message
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 <luc.grosheintz@gmail.com>
---
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(-)
Comments
On Thu, Dec 4, 2025 at 10:28 PM Luc Grosheintz <luc.grosheintz@gmail.com>
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 <luc.grosheintz@gmail.com>
> ---
>
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
>
>
@@ -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)
+ 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>
+ 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
@@ -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>
@@ -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>>();
test_all<std::layout_right>();
test_all<std::layout_stride>();
return 0;
}
@@ -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;
}