This commit adds the right padded layout as described in N5014, with
LWG4372 (dynamic padding value) and LWG4314 (move in operator()).

libstdc++-v3/ChangeLog:

        * include/std/mdspan (_RightPaddedIndices): New class.
        (layout_right_padded): New class.
        * src/c++23/std.cc.in (layout_right_padded): Add.
        * testsuite/23_containers/mdspan/layouts/ctors.cc: Update
        test for right padded layout.
        * 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]>
---
 libstdc++-v3/include/std/mdspan               | 263 ++++++++++++++++++
 libstdc++-v3/src/c++23/std.cc.in              |   5 +-
 .../23_containers/mdspan/layouts/ctors.cc     |   3 +-
 .../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            | 135 ++++++++-
 8 files changed, 437 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index 18782bf0a06..f61931ab8e6 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -954,6 +954,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        : mapping(__other.extents(), __mdspan::__internal_ctor{})
        { __glibcxx_assert(*this == __other); }
 
+#if __glibcxx_padded_layouts
+      template<class _RightPaddedMapping>
+       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>();
+
+         if constexpr (__rank > 1
+             && extents_type::static_extent(__rank - 1) != dynamic_extent
+             && __ostride_sta != dynamic_extent)
+           static_assert(extents_type::static_extent(__rank - 1) == 
__ostride_sta);
+
+         if constexpr (__rank > 1)
+           __glibcxx_assert(__other.stride(__rank - 2)
+               == __other.extents().extent(__rank - 1));
+       }
+#endif
+
       constexpr mapping&
       operator=(const mapping&) noexcept = default;
 
@@ -1350,6 +1376,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
       {
@@ -1384,6 +1441,39 @@ _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 _Mapping>
+         constexpr static bool _S_is_same_padded_mapping =
+         __is_right_padded_mapping<_Mapping>;
+
+       template<typename _Mapping>
+         constexpr static bool _S_is_other_padded_mapping =
+         __is_left_padded_mapping<_Mapping>;
+
+       template<typename _IndexType, size_t _StaticStride, size_t..._Extents>
+         constexpr static auto _S_make_padded_extent(
+           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
       {
@@ -1834,6 +1924,179 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                           __other.stride(1)));
          }
       };
+
+  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 _RightPaddedStorage = __mdspan::_PaddedStorage<_PaddingValue,
+             _Extents, __mdspan::_RightPaddedLayoutTraits<_S_rank>>;
+       [[no_unique_address]] _RightPaddedStorage _M_storage;
+
+       static constexpr size_t _S_static_stride =
+         _RightPaddedStorage::_S_static_stride;
+
+       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_dynamic_padded_stride() 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 __opad)
+         : _M_storage(__exts, std::move(__opad))
+         { }
+
+       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(__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(__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_dynamic_padded_stride();
+         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 _RightPaddedStorage::_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; }
+
+       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_dynamic_padded_stride();
+             else
+               return static_cast<index_type>(
+                 static_cast<size_t>(_M_dynamic_padded_stride()) *
+                 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.extents() == __other.extents()
+             && (_S_rank < 2 || cmp_equal(__self.stride(_S_rank - 2),
+                                          __other.stride(_S_rank - 2)));
+         }
+      };
 #endif
 
   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 891471467e1..73b161f5979 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
@@ -10,7 +10,7 @@ constexpr size_t dyn = std::dynamic_extent;
 #if __glibcxx_padded_layouts
 template<typename Layout>
   constexpr bool
-  is_padded_layout = is_left_padded<Layout>;
+  is_padded_layout = is_left_padded<Layout> || is_right_padded<Layout>;
 #else
 template<typename>
   constexpr bool
@@ -479,6 +479,7 @@ main()
   test_all<std::layout_right>();
 #ifdef __glibcxx_padded_layouts
   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 236aca8bc2b..c5519afe34f 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>());
 #ifdef __glibcxx_padded_layouts
   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 5bf6bf65d3a..57560a6aae7 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
@@ -374,7 +374,7 @@ template<>
 
 #if __glibcxx_padded_layouts
 template<typename Layout>
-  requires is_left_padded<Layout>
+  requires is_left_padded<Layout> || is_right_padded<Layout>
   struct TestStride2D<Layout>
   {
     static constexpr void
@@ -458,7 +458,7 @@ template<>
 
 #if __glibcxx_padded_layouts
 template<typename Layout>
-  requires is_left_padded<Layout>
+  requires is_left_padded<Layout> || is_right_padded<Layout>
   struct TestStride3D<Layout>
   {
     static constexpr void
@@ -702,6 +702,7 @@ main()
   test_all<std::layout_stride>();
 #ifdef __glibcxx_padded_layouts
   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>();
@@ -709,6 +710,7 @@ main()
   test_has_op_eq<std::layout_left, std::layout_stride, true>();
 #ifdef __glibcxx_padded_layouts
   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 ea9a8ef3f4b..a607d1ddd02 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
@@ -670,6 +670,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 29f12aa4de2..d0ac31c2810 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 1f0169d7c02..c267454f467 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h
@@ -2,9 +2,86 @@
 #define TEST_MDSPAN_PADDED_TRAITS_H
 
 #if __glibcxx_padded_layouts
+template<typename Rev, typename Fwd>
+  struct reverse_impl;
+
+template<size_t... Ir, size_t I0, size_t... I>
+  struct reverse_impl<std::integer_sequence<size_t, Ir...>,
+                     std::integer_sequence<size_t, I0, I...>>
+  {
+    using type = typename reverse_impl<std::index_sequence<I0, Ir...>,
+                                      std::index_sequence<I...>>::type;
+  };
+
+template<size_t... Ir>
+  struct reverse_impl<std::integer_sequence<size_t, Ir...>,
+                     std::integer_sequence<size_t>>
+  {
+    using type = std::index_sequence<Ir...>;
+  };
+
+template<typename I>
+  struct reverse;
+
+template<size_t... Ir>
+  struct reverse<std::index_sequence<Ir...>>
+  {
+    using type = typename reverse_impl<std::integer_sequence<size_t>,
+                                      std::integer_sequence<size_t, 
Ir...>>::type;
+  };
+
+template<typename, typename>
+ struct sequence_to_extents;
+
+template<typename IndexType,  size_t... I>
+  struct sequence_to_extents<IndexType, std::index_sequence<I...>>
+  {
+    using type = std::extents<IndexType, I...>;
+  };
+
+template<typename IndexType, size_t... I>
+  struct reverse<std::extents<IndexType, I...>>
+  {
+    using type = typename sequence_to_extents<
+       IndexType,
+       typename reverse<std::index_sequence<I...>>::type
+      >::type;
+  };
+
+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;
+  }
+
+template<typename T, size_t N>
+  constexpr std::array<T, N>
+  reversed(const std::array<T, N>& fwd)
+  {
+    std::array<T, N> rev;
+    for(size_t i = 0; i < N; ++i)
+      rev[(N-1) - i] = fwd[i];
+    return rev;
+  }
+
+template<typename IndexType, size_t... I>
+  constexpr auto
+  reversed(const std::extents<IndexType, I...>& exts)
+  {
+    using rev_type = typename reverse<std::extents<IndexType, I...>>::type;
+    return rev_type(reversed(dynamic_extents_array(exts)));
+  }
+
+static_assert(std::array{3, 2, 1} == reversed(std::array{1, 2, 3}));
+
 enum class PaddingSide
 {
-  Left
+  Left,
+  Right
 };
 
 template<typename Layout>
@@ -13,17 +90,33 @@ template<typename Layout>
 template<size_t PaddingValue>
   constexpr static bool is_left_padded<std::layout_left_padded<PaddingValue>> 
= true;
 
+template<typename Layout>
+  constexpr static bool is_right_padded = false;
+
+template<size_t PaddingValue>
+  constexpr static bool 
is_right_padded<std::layout_right_padded<PaddingValue>> = true;
+
 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>
@@ -59,5 +152,41 @@ template<>
       { return exts.extent(0); }
   };
 
+template<>
+  struct LayoutTraits<PaddingSide::Right>
+  {
+    using layout_same = std::layout_right;
+    using layout_other = std::layout_left;
+
+    template<typename Extents>
+      using extents_type = typename reverse<Extents>::type;
+
+    template<typename Extents>
+      constexpr static extents_type<Extents>
+      make_extents(const Extents& exts)
+      { return reversed(exts); }
+
+    template<typename T, size_t N>
+      constexpr static std::array<T, N>
+      make_expected(const std::array<T, N>& expected)
+      { return reversed(expected); }
+
+    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

Reply via email to