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
> >
> >
>
>

Reply via email to