On Wed, Oct 8, 2025 at 10:53 AM Jonathan Wakely <[email protected]> wrote:
> On Mon, 29 Sep 2025 at 08:00 +0200, Luc Grosheintz wrote: > >This commit adds the right padded layout as described in N5014, with > >LWG4372 (dynamic padding value) and LWG4314 (move in operator()). > > > > PR libstdc++/110352 > > > >libstdc++-v3/ChangeLog: > > > > * include/std/mdspan (_RightPaddedIndices): Traits for right > > padded layouts. > > (layout_right::mapping::mapping) New overload for right padded > > layouts. > > (layout_right_padded): Add implementation. > > * src/c++23/std.cc.in (layout_right_padded): Add. > > * testsuite/23_containers/mdspan/layouts/ctors.cc: Update > > test for right padded layouts. > > * testsuite/23_containers/mdspan/layouts/empty.cc: Ditto. > > * testsuite/23_containers/mdspan/layouts/mapping.cc: Ditto. > > * testsuite/23_containers/mdspan/layouts/padded.cc: Ditto. > > * testsuite/23_containers/mdspan/layouts/padded_neg.cc: Ditto. > > * testsuite/23_containers/mdspan/layouts/padded_traits.h: Ditto. > > > >Signed-off-by: Luc Grosheintz <[email protected]> > >--- > I have missed without changes that apply to layout_left. I will apply them to both in the final commit that changes formatting. Willl push this only with class -> typename change. > > libstdc++-v3/include/std/mdspan | 248 ++++++++++++++++++ > > libstdc++-v3/src/c++23/std.cc.in | 5 +- > > .../23_containers/mdspan/layouts/ctors.cc | 1 + > > .../23_containers/mdspan/layouts/empty.cc | 1 + > > .../23_containers/mdspan/layouts/mapping.cc | 6 +- > > .../23_containers/mdspan/layouts/padded.cc | 4 + > > .../mdspan/layouts/padded_neg.cc | 28 ++ > > .../mdspan/layouts/padded_traits.h | 84 +++++- > > 8 files changed, 369 insertions(+), 8 deletions(-) > > > >diff --git a/libstdc++-v3/include/std/mdspan > b/libstdc++-v3/include/std/mdspan > >index 6bd75ffde0b..957da1e0e44 100644 > >--- a/libstdc++-v3/include/std/mdspan > >+++ b/libstdc++-v3/include/std/mdspan > >@@ -977,6 +977,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > : mapping(__other.extents(), __mdspan::__internal_ctor{}) > > { __glibcxx_assert(*this == __other); } > > > >+#if __glibcxx_padded_layouts > >+ template<class _RightPaddedMapping> > > s/class/typename/ > > and now that I notice it, that's present in the left padded layout > too: > > template<class _LeftpadMapping> > I have applied this change here. > > > >+ requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping> > >+ && is_constructible_v<extents_type, > >+ typename > _RightPaddedMapping::extents_type> > >+ constexpr > >+ explicit(!is_convertible_v<typename > _RightPaddedMapping::extents_type, > >+ extents_type>) > >+ mapping(const _RightPaddedMapping& __other) noexcept > >+ : mapping(__other.extents(), __mdspan::__internal_ctor{}) > >+ { > >+ constexpr size_t __rank = extents_type::rank(); > >+ constexpr size_t __ostride_sta = __mdspan::__get_static_stride< > >+ _RightPaddedMapping>(); > > I would usually break the line before the '=' and keep the function > call together, like so: > > constexpr size_t __ostride_sta > = __mdspan::__get_static_stride<_RightPaddedMapping>(); > > >+ > >+ if constexpr (__rank > 1) > >+ { > >+ if constexpr (extents_type::static_extent(__rank - 1) != > dynamic_extent > >+ && __ostride_sta != dynamic_extent) > >+ static_assert(extents_type::static_extent(__rank - 1) > >+ == __ostride_sta); > >+ else > >+ __glibcxx_assert(__other.stride(__rank - 2) > >+ == __other.extents().extent(__rank - 1)); > >+ } > >+ } > >+#endif > >+ > > constexpr mapping& > > operator=(const mapping&) noexcept = default; > > > >@@ -1370,6 +1398,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > return __res; > > } > > > >+ template<typename _Extents, typename _Stride, typename... _Indices> > >+ constexpr typename _Extents::index_type > >+ __linear_index_rightpad(const _Extents& __exts, _Stride __stride, > >+ _Indices... __indices) > >+ { > >+ // i[n-1] + stride*(i[n-2] + extents.extent(n-2])*...) > >+ using _IndexType = typename _Extents::index_type; > >+ _IndexType __res = 0; > >+ if constexpr (sizeof...(__indices) > 0) > >+ { > >+ _IndexType __mult = 1; > >+ array<_IndexType, sizeof...(__indices)> > __ind_arr{__indices...}; > >+ > >+ auto __update_rest = [&, __pos = __exts.rank()-1](_IndexType) > mutable > >+ { > >+ --__pos; > >+ __res += __ind_arr[__pos] * __mult; > >+ __mult *= __exts.extent(__pos); > >+ }; > >+ > >+ auto __update = [&](_IndexType, auto... __rest) > >+ { > >+ __res += __ind_arr[__exts.rank() - 1]; > >+ __mult = __stride.extent(0); > >+ (__update_rest(__rest), ...); > >+ }; > >+ __update(__indices...); > >+ } > >+ return __res; > >+ } > >+ > > template<size_t _Rank> > > struct _LeftPaddedLayoutTraits > > { > >@@ -1396,6 +1455,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > } > > }; > > > >+ template<size_t _Rank> > >+ struct _RightPaddedLayoutTraits > >+ { > >+ using _LayoutSame = layout_right; > >+ using _LayoutOther = layout_left; > >+ > >+ constexpr static size_t _S_ext_idx = _Rank - 1; > >+ constexpr static size_t _S_stride_idx = _Rank - 2; > >+ constexpr static size_t _S_unpad_begin = 0; > >+ constexpr static size_t _S_unpad_end = _Rank - 1; > >+ > >+ template<typename _IndexType, size_t _StaticStride, > size_t..._Extents> > >+ constexpr static auto _S_make_padded_extent( > > The _S_make_padded_extent function name should start a new line (same > observation for the left padded layout too). > > >+ extents<_IndexType, _StaticStride> __stride, > >+ const extents<_IndexType, _Extents...>& __exts) > >+ { > >+ auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, > _Is...>) > >+ { > >+ return extents<_IndexType, (_Extents...[_Is])..., > _StaticStride>{ > >+ __exts.extent(_Is)..., __stride.extent(0)}; > >+ }; > >+ return __impl(make_index_sequence<sizeof...(_Extents) - 1>()); > >+ } > >+ }; > >+ > > template<size_t _PaddingValue, typename _Extents, typename > _LayoutTraits> > > class _PaddedStorage > > { > >@@ -1822,6 +1906,170 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > noexcept > > { return __self._M_storage._M_equal(__other); } > > }; > >+ > >+ 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 > >+ __mdspan::__get_static_stride<mapping>(); > >+ > >+ constexpr index_type > >+ _M_extent(size_t __r) const noexcept > >+ { return _M_storage._M_extents.extent(__r); } > >+ > >+ constexpr index_type > >+ _M_padstride() const noexcept > >+ { return _M_storage._M_stride.extent(0); } > >+ > >+ public: > >+ constexpr > >+ mapping() noexcept > >+ { } > >+ > >+ constexpr > >+ mapping(const mapping&) noexcept = default; > >+ > >+ constexpr > >+ mapping(const extents_type& __exts) > >+ : _M_storage(__exts) > >+ { } > >+ > >+ template<__mdspan::__valid_index_type<index_type> _OIndexType> > >+ constexpr mapping(const extents_type& __exts, _OIndexType __pad) > > 'mapping' on a new line (and in the left padded layout too). > > >+ : _M_storage(__exts, > >+ __mdspan::__index_type_cast<index_type>(std::move(__pad))) > >+ { } > >+ > >+ template<typename _OExtents> > >+ requires is_constructible_v<extents_type, _OExtents> > >+ constexpr explicit(!is_convertible_v<_OExtents, extents_type>) > >+ mapping(const layout_right::mapping<_OExtents>& __other) > >+ : _M_storage(__other) > >+ { } > >+ > >+ template<typename _OExtents> > >+ requires is_constructible_v<_OExtents, extents_type> > >+ constexpr explicit(_OExtents::rank() > 0) > >+ mapping(const typename layout_stride::mapping<_OExtents>& > __other) > >+ : _M_storage(__other) > >+ { __glibcxx_assert(*this == __other); } > >+ > >+ template<typename _RightPaddedMapping> > >+ requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping> > >+ && is_constructible_v<extents_type, > >+ typename > _RightPaddedMapping::extents_type> > >+ constexpr explicit(_S_rank > 1 && (padding_value != > dynamic_extent > >+ || _RightPaddedMapping::padding_value == dynamic_extent)) > >+ mapping(const _RightPaddedMapping& __other) > >+ : _M_storage(layout_right{}, __other) > >+ { } > >+ > >+ template<typename _LeftPaddedMapping> > >+ requires (__mdspan::__is_left_padded_mapping<_LeftPaddedMapping> > >+ || __mdspan::__mapping_of<layout_left, _LeftPaddedMapping>) > >+ && (_S_rank <= 1) > >+ && is_constructible_v<extents_type, > >+ typename > _LeftPaddedMapping::extents_type> > >+ constexpr explicit(!is_convertible_v< > >+ typename _LeftPaddedMapping::extents_type, extents_type>) > >+ mapping(const _LeftPaddedMapping& __other) noexcept > >+ : _M_storage(layout_left{}, __other) > >+ { } > >+ > >+ constexpr mapping& operator=(const mapping&) noexcept = default; > >+ > >+ constexpr const extents_type& > >+ extents() const noexcept { return _M_storage._M_extents; } > >+ > >+ constexpr array<index_type, _S_rank> > >+ strides() const noexcept > >+ { > >+ array<index_type, _S_rank> __ret; > >+ if constexpr (_S_rank > 0) > >+ __ret[_S_rank - 1] = 1; > >+ if constexpr (_S_rank > 1) > >+ __ret[_S_rank - 2] = _M_padstride(); > >+ if constexpr (_S_rank > 2) > >+ for(size_t __i = _S_rank - 2; __i > 0; --__i) > >+ __ret[__i - 1] = __ret[__i] * _M_extent(__i); > >+ return __ret; > >+ } > >+ > >+ constexpr index_type > >+ required_span_size() const noexcept > >+ { return _M_storage._M_required_span_size(); } > >+ > >+ // _GLIBCXX_RESOLVE_LIB_DEFECTS > >+ // 4314. Missing move in mdspan layout mapping::operator() > >+ template<__mdspan::__valid_index_type<index_type>... _Indices> > >+ requires (sizeof...(_Indices) == _S_rank) > >+ constexpr index_type > >+ operator()(_Indices... __indices) const noexcept > >+ { > >+ return __mdspan::__linear_index_rightpad( > >+ extents(), _M_storage._M_stride, > >+ static_cast<index_type>(std::move(__indices))...); > >+ } > >+ > >+ static constexpr bool > >+ is_always_exhaustive() noexcept > >+ { return _PaddedStorage::_M_is_always_exhaustive(); } > >+ > >+ constexpr bool > >+ is_exhaustive() noexcept > >+ { return _M_storage._M_is_exhaustive(); } > >+ > >+ static constexpr bool > >+ is_always_unique() noexcept { return true; } > >+ > >+ static constexpr bool > >+ is_always_strided() noexcept { return true; } > >+ > >+ static constexpr bool > >+ is_unique() noexcept { return true; } > >+ > >+ static constexpr bool > >+ is_strided() noexcept { return true; } > > For the six functions above, could we either group all the static > is_always_foo functions together (as in the standard), or group each > static is_always_foo with the non-static is_foo. > I will group is_always_foo with is_foo. > > Currently we have: > static non-static static static non-static non-static. > > (same comment for lefty). > > > >+ > >+ constexpr index_type > >+ stride(rank_type __r) const noexcept > >+ { > >+ __glibcxx_assert(__r < _S_rank); > >+ if constexpr (_S_rank <= 1) > >+ return 1; > >+ else if (__r == _S_rank - 1) > >+ return 1; > >+ else if (__r == _S_rank - 2) > >+ return _M_padstride(); > >+ else > >+ return static_cast<index_type>( > >+ static_cast<size_t>(_M_padstride()) * > >+ static_cast<size_t>(__mdspan::__fwd_prod( > >+ extents(), __r + 1, _S_rank - 1))); > >+ } > >+ > >+ template<typename _RightPaddedMapping> > >+ requires(__mdspan::__is_right_padded_mapping<_RightPaddedMapping> > >+ && _RightPaddedMapping::extents_type::rank() == _S_rank) > >+ friend constexpr bool > >+ operator==(const mapping& __self, const _RightPaddedMapping& > __other) > >+ noexcept > >+ { return __self._M_storage._M_equal(__other); } > >+ }; > > #endif > > Comment on the #endif please. > > Those are all minor tweaks, so this is OK for trunk, thanks! > > > > > > template<typename _ElementType> > >diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/ > std.cc.in > >index f10bab59e2c..c1b4e4c88b7 100644 > >--- a/libstdc++-v3/src/c++23/std.cc.in > >+++ b/libstdc++-v3/src/c++23/std.cc.in > >@@ -1871,9 +1871,10 @@ export namespace std > > using std::mdspan; > > #if __glibcxx_padded_layouts > > using std::layout_left_padded; > >+ using std::layout_right_padded; > > #endif > >- // FIXME layout_right_padded, strided_slice, submdspan_mapping_result, > >- // full_extent_t, full_extent, submdspan_extents, mdsubspan > >+ // FIXME strided_slice, submdspan_mapping_result, full_extent_t, > full_extent, > >+ // submdspan_extents, mdsubspan > > } > > #endif > > > >diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc > >index 8cba8094abc..27065a0dfc6 100644 > >--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc > >+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc > >@@ -469,6 +469,7 @@ main() > > test_all<std::layout_right>(); > > #if __cplusplus > 202302L > > test_padded_all<std::layout_left_padded>(); > >+ test_padded_all<std::layout_right_padded>(); > > #endif > > > > from_left_or_right::test_all<std::layout_left, std::layout_right>(); > >diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc > >index 05188432f14..8840d07879c 100644 > >--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc > >+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc > >@@ -142,6 +142,7 @@ main() > > static_assert(test_all<std::layout_stride>()); > > #if __cplusplus > 202302L > > static_assert(test_padded_all<std::layout_left_padded>()); > >+ static_assert(test_padded_all<std::layout_right_padded>()); > > #endif > > return 0; > > } > >diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc > >index 10ce622523d..d1486e4e11c 100644 > >--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc > >+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc > >@@ -373,7 +373,7 @@ template<> > > > > #if __cplusplus > 202302L > > template<typename Layout> > >- requires is_left_padded<Layout> > >+ requires is_left_padded<Layout> || is_right_padded<Layout> > > struct TestStride2D<Layout> > > { > > static constexpr void > >@@ -457,7 +457,7 @@ template<> > > > > #if __cplusplus > 202302L > > template<typename Layout> > >- requires is_left_padded<Layout> > >+ requires is_left_padded<Layout> || is_right_padded<Layout> > > struct TestStride3D<Layout> > > { > > static constexpr void > >@@ -701,6 +701,7 @@ main() > > test_all<std::layout_stride>(); > > #if __cplusplus > 202302L > > test_padded_all<std::layout_left_padded>(); > >+ test_padded_all<std::layout_right_padded>(); > > #endif > > > > test_has_op_eq<std::layout_right, std::layout_left, false>(); > >@@ -708,6 +709,7 @@ main() > > test_has_op_eq<std::layout_left, std::layout_stride, true>(); > > #if __cplusplus > 202302L > > test_padded_has_op_eq<std::layout_left_padded>(); > >+ test_padded_has_op_eq<std::layout_right_padded>(); > > #endif > > > > test_has_op_eq_peculiar(); > >diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc > >index d43b84ef875..cf4821a3c74 100644 > >--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc > >+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc > >@@ -668,6 +668,10 @@ main() > > test_all<std::layout_left_padded>(); > > static_assert(test_all<std::layout_left_padded>()); > > > >+ test_all<std::layout_right_padded>(); > >+ static_assert(test_all<std::layout_right_padded>()); > >+ > > test_from_pad_all<std::layout_left_padded>(); > >+ test_from_pad_all<std::layout_right_padded>(); > > return 0; > > } > >diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc > >index f0dbfe9d9c6..a758f74287f 100644 > >--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc > >+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc > >@@ -15,6 +15,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > > static_assert(test_from_extens_representable_sta<std::layout_left_padded>()); > // { dg-error "from here" } > >+static_assert(test_from_extens_representable_sta<std::layout_right_padded>()); > // { dg-error "from here" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -28,6 +29,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > > static_assert(test_from_extents_representable_padded_size<std::layout_left_padded>()); > // { dg-error "expansion of" } > >+static_assert(test_from_extents_representable_padded_size<std::layout_right_padded>()); > // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -40,6 +42,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > > static_assert(test_from_extents_representable_stride<std::layout_left_padded>()); > // { dg-error "expansion of" } > >+static_assert(test_from_extents_representable_stride<std::layout_right_padded>()); > // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -51,6 +54,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > > static_assert(test_from_pad_representable_stride<std::layout_left_padded>()); > // { dg-error "expansion of" } > >+static_assert(test_from_pad_representable_stride<std::layout_right_padded>()); > // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -62,6 +66,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > > static_assert(test_from_pad_representable_padded_size<std::layout_left_padded>()); > // { dg-error "expansion of" } > >+static_assert(test_from_pad_representable_padded_size<std::layout_right_padded>()); > // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -76,6 +81,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > static_assert(test_from_left<std::layout_left_padded>()); // { dg-error > "required from here" } > >+static_assert(test_from_left<std::layout_right_padded>()); // { dg-error > "required from here" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -90,6 +96,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > > static_assert(test_from_left_bad_runtime_stride<std::layout_left_padded>()); > // { dg-error "expansion of" } > >+static_assert(test_from_left_bad_runtime_stride<std::layout_right_padded>()); > // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -103,6 +110,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > > static_assert(test_from_left_representable_extents<std::layout_left_padded>()); > // { dg-error "expansion of" } > >+static_assert(test_from_left_representable_extents<std::layout_right_padded>()); > // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout, size_t PaddingValue> > > constexpr bool > >@@ -116,6 +124,8 @@ template<template<size_t> typename Layout, size_t > PaddingValue> > > } > > static_assert(test_pad_overflow<std::layout_left_padded, 1>()); // { > dg-error "expansion of" } > > static_assert(test_pad_overflow<std::layout_left_padded, dyn>()); // { > dg-error "expansion of" } > >+static_assert(test_pad_overflow<std::layout_right_padded, 1>()); // { > dg-error "expansion of" } > >+static_assert(test_pad_overflow<std::layout_right_padded, dyn>()); // { > dg-error "expansion of" } > > > > template<template<size_t> typename Layout, size_t PaddingValue> > > constexpr bool > >@@ -128,6 +138,8 @@ template<template<size_t> typename Layout, size_t > PaddingValue> > > } > > static_assert(test_from_pad_negative<std::layout_left_padded, 1>()); > // { dg-error "expansion of" } > > static_assert(test_from_pad_negative<std::layout_left_padded, dyn>()); > // { dg-error "expansion of" } > >+static_assert(test_from_pad_negative<std::layout_right_padded, 1>()); > // { dg-error "expansion of" } > >+static_assert(test_from_pad_negative<std::layout_right_padded, dyn>()); > // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout, size_t Pad> > > constexpr bool > >@@ -142,6 +154,8 @@ template<template<size_t> typename Layout, size_t Pad> > > } > > static_assert(test_static_pad_same<std::layout_left_padded, 1>()); // { > dg-error "expansion of" } > > static_assert(test_static_pad_same<std::layout_left_padded, 3>()); // { > dg-error "expansion of" } > >+static_assert(test_static_pad_same<std::layout_right_padded, 1>()); // { > dg-error "expansion of" } > >+static_assert(test_static_pad_same<std::layout_right_padded, 3>()); // { > dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -156,6 +170,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > > static_assert(test_from_stride_wrong_stride0<std::layout_left_padded>()); > // { dg-error "expansion of" } > >+static_assert(test_from_stride_wrong_stride0<std::layout_right_padded>()); > // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -170,6 +185,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > > static_assert(test_from_stride_wrong_stride1<std::layout_left_padded>()); > // { dg-error "expansion of" } > >+static_assert(test_from_stride_wrong_stride1<std::layout_right_padded>()); > // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -184,6 +200,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > static_assert(test_from_stride_wrong_stride2<std::layout_left_padded>()); > > >+static_assert(test_from_stride_wrong_stride2<std::layout_right_padded>()); > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -200,6 +217,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > static_assert(test_from_stride_oversized<std::layout_left_padded>()); // > { dg-error "expansion of" } > >+static_assert(test_from_stride_oversized<std::layout_right_padded>()); > // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -213,6 +231,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > static_assert(test_from_samepad_dyn<std::layout_left_padded>()); // { > dg-error "expansion of" } > >+static_assert(test_from_samepad_dyn<std::layout_right_padded>()); // { > dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -226,6 +245,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > static_assert(test_from_samepad_sta<std::layout_left_padded>()); // { > dg-error "expansion of" } > >+static_assert(test_from_samepad_sta<std::layout_right_padded>()); // { > dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -240,6 +260,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > static_assert(test_from_samepad_oversized<std::layout_left_padded>()); > // { dg-error "expansion of" } > >+static_assert(test_from_samepad_oversized<std::layout_right_padded>()); > // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout, size_t RunId> > > constexpr bool > >@@ -278,6 +299,10 @@ > static_assert(test_to_same_not_exhaustive<std::layout_left_padded, 0>()); > // { d > > static_assert(test_to_same_not_exhaustive<std::layout_left_padded, > 1>()); // { dg-error "expansion of" } > > static_assert(test_to_same_not_exhaustive<std::layout_left_padded, > 2>()); // { dg-error "expansion of" } > > static_assert(test_to_same_not_exhaustive<std::layout_left_padded, > 3>()); // { dg-error "expansion of" } > >+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, > 0>()); // { dg-error "expansion of" } > >+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, > 1>()); // { dg-error "expansion of" } > >+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, > 2>()); // { dg-error "expansion of" } > >+static_assert(test_to_same_not_exhaustive<std::layout_right_padded, > 3>()); // { dg-error "expansion of" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -290,6 +315,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > > static_assert(test_statically_bad_padding_value1<std::layout_left_padded>()); > // { dg-error "required from" } > >+static_assert(test_statically_bad_padding_value1<std::layout_right_padded>()); > // { dg-error "required from" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -301,6 +327,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > > static_assert(test_statically_bad_padding_value2<std::layout_left_padded>()); > // { dg-error "required from" } > >+static_assert(test_statically_bad_padding_value2<std::layout_right_padded>()); > // { dg-error "required from" } > > > > template<template<size_t> typename Layout> > > constexpr bool > >@@ -312,6 +339,7 @@ template<template<size_t> typename Layout> > > return true; > > } > > static_assert(test_statically_oversized<std::layout_left_padded>()); // > { dg-error "from here" } > >+static_assert(test_statically_oversized<std::layout_right_padded>()); // > { dg-error "from here" } > > > > // { dg-prune-output "padding_value must be representable as index_type" > } > > // { dg-prune-output "non-constant condition for static assertion" } > >diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h > b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h > >index 9171d8c1ce1..788ae82fcc4 100644 > >--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h > >+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h > >@@ -12,15 +12,34 @@ template<size_t PaddingValue> > > = true; > > #endif > > > >+template<typename Layout> > >+ constexpr static bool is_right_padded = false; > >+ > >+#if __cplusplus > 202302L > >+template<size_t PaddingValue> > >+ constexpr static bool > is_right_padded<std::layout_right_padded<PaddingValue>> > >+ = true; > >+#endif > >+ > > template<typename Layout> > > constexpr bool > >- is_padded_layout = is_left_padded<Layout>; > >+ is_padded_layout = is_left_padded<Layout> || is_right_padded<Layout>; > > > > #if __cplusplus > 202302L > >+template<typename Extents> > >+ constexpr auto > >+ dynamic_extents_array(const Extents& exts) > >+ { > >+ std::array<typename Extents::index_type, Extents::rank()> ret; > >+ for(size_t i = 0; i < Extents::rank(); ++i) > >+ ret[i] = exts.extent(i); > >+ return ret; > >+ } > > > > enum class PaddingSide > > { > >- Left > >+ Left, > >+ Right > > }; > > > > struct DeducePaddingSide > >@@ -28,12 +47,22 @@ struct DeducePaddingSide > > template<template<size_t> typename Layout> > > constexpr static PaddingSide > > from_template() > >- { return PaddingSide::Left; } > >+ { > >+ if constexpr (std::same_as<Layout<0>, std::layout_left_padded<0>>) > >+ return PaddingSide::Left; > >+ else > >+ return PaddingSide::Right; > >+ } > > > > template<typename Layout> > > constexpr static PaddingSide > > from_typename() > >- { return PaddingSide::Left; } > >+ { > >+ if constexpr (is_left_padded<Layout>) > >+ return PaddingSide::Left; > >+ else > >+ return PaddingSide::Right; > >+ } > > }; > > > > template<PaddingSide Side> > >@@ -69,5 +98,52 @@ template<> > > { return exts.extent(0); } > > }; > > > >+template<> > >+ struct LayoutTraits<PaddingSide::Right> > >+ { > >+ using layout_same = std::layout_right; > >+ 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> > >+ make_array(std::array<T, N> a) > >+ { > >+ std::ranges::reverse(a); > >+ return a; > >+ } > >+ > >+ template<typename Mapping> > >+ constexpr static auto > >+ padded_stride(const Mapping& m) > >+ { > >+ auto rank = Mapping::extents_type::rank(); > >+ return m.stride(rank - 2); > >+ } > >+ > >+ template<typename Extents> > >+ constexpr static auto > >+ padded_extent(const Extents& exts) > >+ { > >+ auto rank = Extents::rank(); > >+ return exts.extent(rank - 1); > >+ } > >+ }; > >+ > > #endif > > #endif > >-- > >2.50.1 > > > > > >
