[PATCH v3 3/4] libstdc++: Implement std::layout_left_padded.
Tomasz Kaminski
tkaminsk@redhat.com
Fri Sep 26 12:49:25 GMT 2025
On Fri, Sep 26, 2025 at 2:36 PM Luc Grosheintz <luc.grosheintz@gmail.com>
wrote:
>
>
> On 9/26/25 2:22 PM, Tomasz Kaminski wrote:
> > On Tue, Sep 23, 2025 at 3:23 PM Luc Grosheintz <luc.grosheintz@gmail.com
> >
> > wrote:
> >
> >> This commit adds a new layout layout_left_padded as standardized in
> >> N5014 but with one deviation.It adds a purely internal feature testing
> >> macro padded_layouts and registers layout_left_padded in the std module.
> >>
> >> This commit implements LWG4372, because without it's not possible
> >> to properly test padded layouts with a dynamic padding value. It also
> >> implements LWG4314, for consistency with prior layouts.
> >>
> >> The implementation uses a _PaddedStorage to deduplicate most of the code
> >> shared between left- and right-padded layouts. It's implemented through
> >> aggregation rather than inheritence, because of a bug related to
> >> inheriting conditionally explicit ctors.
> >>
> >> The tests are written such that the canonical version is works for
> >> layout_left_padded. A version for layout_right_padded is derived
> >> essentially by reversing the order of the extents.
> >>
> >> libstdc++-v3/ChangeLog:
> >>
> >> * include/bits/version.def (padded_layouts): Add as internal
> >> only.
> >> * include/bits/version.h: Regenerate.
> >> * include/std/mdspan (__fwd_prod): New overload.
> >> (layout_left_padded): Add declaration and implementation.
> >> (layout_right_padded): Add declaration only.
> >> (layout_left::mapping::mapping): New overload for left
> >> padded mappings.
> >> (__is_left_padded_mapping): New concept.
> >> (__is_right_padded_mapping): Ditto.
> >> (__standardized_mapping): Recognize left and right padded
> >> mappings.
> >> (__valid_static_stride): Prepare for right padded layouts.
> >> (__valid_padded_size): Ditto.
> >> (_LeftPaddedIndices): Traits for left padded details.
> >> (_PaddedStorage): New class.
> >> * src/c++23/std.cc.in (layout_left_padded): Add.
> >> * testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc:
> >> Refactor and add tests for layout_left_padded.
> >> * testsuite/23_containers/mdspan/layouts/ctors.cc: Ditto.
> >> * 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: New
> >> traits.
> >>
> >> Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>
> >> ---
> >> libstdc++-v3/include/bits/version.def | 10 +
> >> libstdc++-v3/include/bits/version.h | 9 +
> >> libstdc++-v3/include/std/mdspan | 665 ++++++++++++++++-
> >> libstdc++-v3/src/c++23/std.cc.in | 8 +-
> >> .../mdspan/layouts/class_mandate_neg.cc | 1 +
> >> .../23_containers/mdspan/layouts/ctors.cc | 69 +-
> >> .../23_containers/mdspan/layouts/empty.cc | 20 +-
> >> .../23_containers/mdspan/layouts/mapping.cc | 108 ++-
> >> .../23_containers/mdspan/layouts/padded.cc | 675 ++++++++++++++++++
> >> .../mdspan/layouts/padded_neg.cc | 324 +++++++++
> >> .../mdspan/layouts/padded_traits.h | 63 ++
> >> 11 files changed, 1936 insertions(+), 16 deletions(-)
> >> create mode 100644
> >> libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
> >> create mode 100644
> >> libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc
> >> create mode 100644
> >> libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h
> >>
> >> diff --git a/libstdc++-v3/include/bits/version.def
> >> b/libstdc++-v3/include/bits/version.def
> >> index 721125df280..b92b71fc624 100644
> >> --- a/libstdc++-v3/include/bits/version.def
> >> +++ b/libstdc++-v3/include/bits/version.def
> >> @@ -1062,6 +1062,16 @@ ftms = {
> >> cxxmin = 26;
> >> extra_cond = "__glibcxx_assume_aligned "
> >> "&& __glibcxx_is_sufficiently_aligned";
> >> + };
> >> +};
> >> +
> >> +// Unofficial macro signaling presence of the two padded layouts.
> >> +ftms = {
> >> + name = padded_layouts;
> >> + no_stdname = true; // Don't change: it's not a standardized FTM.
> >> + values = {
> >> + v = 1;
> >> + cxxmin = 26;
> >> };
> >> };
> >>
> >> diff --git a/libstdc++-v3/include/bits/version.h
> >> b/libstdc++-v3/include/bits/version.h
> >> index 7e8ad1007ef..5e10a893426 100644
> >> --- a/libstdc++-v3/include/bits/version.h
> >> +++ b/libstdc++-v3/include/bits/version.h
> >> @@ -1193,6 +1193,15 @@
> >> #endif /* !defined(__cpp_lib_aligned_accessor) &&
> >> defined(__glibcxx_want_aligned_accessor) */
> >> #undef __glibcxx_want_aligned_accessor
> >>
> >> +#if !defined(__cpp_lib_padded_layouts)
> >> +# if (__cplusplus > 202302L)
> >> +# define __glibcxx_padded_layouts 1L
> >> +# if defined(__glibcxx_want_all) ||
> >> defined(__glibcxx_want_padded_layouts)
> >> +# endif
> >> +# endif
> >> +#endif /* !defined(__cpp_lib_padded_layouts) &&
> >> defined(__glibcxx_want_padded_layouts) */
> >> +#undef __glibcxx_want_padded_layouts
> >> +
> >> #if !defined(__cpp_lib_ssize)
> >> # if (__cplusplus >= 202002L)
> >> # define __glibcxx_ssize 201902L
> >> diff --git a/libstdc++-v3/include/std/mdspan
> >> b/libstdc++-v3/include/std/mdspan
> >> index 9dd0c85f5b0..18782bf0a06 100644
> >> --- a/libstdc++-v3/include/std/mdspan
> >> +++ b/libstdc++-v3/include/std/mdspan
> >> @@ -261,6 +261,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >> __static_extents() noexcept
> >> { return _Extents::_Storage::_S_static_extents(); }
> >>
> >> + template<typename _Extents>
> >> + constexpr span<const size_t>
> >> + __static_extents(size_t __begin, size_t __end) noexcept
> >> + {
> >> + const auto& __sta_exts = __static_extents<_Extents>();
> >> + return span<const size_t>(__sta_exts.data() + __begin, __end -
> >> __begin);
> >> + }
> >> +
> >> // Pre-compute: \prod_{i = 0}^r _Extents[i], for r = 0,..., n
> >> (exclusive)
> >> template<array _Extents>
> >> constexpr auto __fwd_partial_prods = [] consteval
> >> @@ -476,6 +484,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >> }
> >>
> >> // Preconditions: _r < _Extents::rank()
> >> + template<typename _Extents>
> >> + constexpr typename _Extents::index_type
> >> + __fwd_prod(const _Extents& __exts, size_t __begin, size_t __end)
> >> noexcept
> >> + {
> >> + size_t __sta_prod = [__begin, __end] {
> >> + span<const size_t> __sta_exts =
> >> __static_extents<_Extents>(__begin, __end);
> >> + size_t __ret = 1;
> >> + for(auto __ext : __sta_exts)
> >> + if (__ext != dynamic_extent)
> >> + __ret *= __ext;
> >> + return __ret;
> >> + }();
> >> + return __extents_prod(__exts, __sta_prod, __begin, __end);
> >> + }
> >> +
> >> template<typename _Extents>
> >> constexpr typename _Extents::index_type
> >> __fwd_prod(const _Extents& __exts, size_t __r) noexcept
> >> @@ -567,6 +590,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >> class mapping;
> >> };
> >>
> >> +#ifdef __glibcxx_padded_layouts
> >> + template<size_t _PaddingValue>
> >> + struct layout_left_padded
> >> + {
> >> + template<typename _Extents>
> >> + class mapping;
> >> + };
> >> +
> >> + template<size_t _PaddingValue>
> >> + struct layout_right_padded
> >> + {
> >> + template<typename _Extents>
> >> + class mapping;
> >> + };
> >> +#endif
> >> +
> >> namespace __mdspan
> >> {
> >> template<typename _Tp>
> >> @@ -669,10 +708,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >> is_same_v<typename _Layout::template mapping<typename
> >> _Mapping::extents_type>,
> >> _Mapping>;
> >>
> >> + template<template<size_t> typename _Layout, typename _Mapping>
> >> + concept __padded_mapping_of = __mapping_of<
> >> + _Layout<_Mapping::padding_value>, _Mapping>;
> >> +
> >> +#ifdef __glibcxx_padded_layouts
> >> + template<typename _Mapping>
> >> + constexpr bool __is_left_padded_mapping = __padded_mapping_of<
> >> + layout_left_padded, _Mapping>;
> >> +
> >> + template<typename _Mapping>
> >> + constexpr bool __is_right_padded_mapping = __padded_mapping_of<
> >> + layout_right_padded, _Mapping>;
> >> +#endif
> >> +
> >> + template<typename _PaddedMapping>
> >> + consteval size_t
> >> + __get_static_stride()
> >> + { return _PaddedMapping::_S_static_stride; }
> >> +
> >> template<typename _Mapping>
> >> concept __standardized_mapping = __mapping_of<layout_left,
> _Mapping>
> >> || __mapping_of<layout_right,
> >> _Mapping>
> >> - || __mapping_of<layout_stride,
> >> _Mapping>;
> >> + || __mapping_of<layout_stride,
> >> _Mapping>
> >> +#ifdef __glibcxx_padded_layouts
> >> + ||
> >> __is_left_padded_mapping<_Mapping>
> >> + ||
> >> __is_right_padded_mapping<_Mapping>
> >> +#endif
> >> + ;
> >>
> >> // A tag type to create internal ctors.
> >> class __internal_ctor
> >> @@ -726,6 +789,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >> : mapping(__other.extents(), __mdspan::__internal_ctor{})
> >> { __glibcxx_assert(*this == __other); }
> >>
> >> +#if __glibcxx_padded_layouts
> >> + template<class _LeftpadMapping>
> >> + requires __mdspan::__is_left_padded_mapping<_LeftpadMapping>
> >> + && is_constructible_v<extents_type,
> >> + typename
> >> _LeftpadMapping::extents_type>
> >> + constexpr
> >> + explicit(!is_convertible_v<typename
> _LeftpadMapping::extents_type,
> >> + extents_type>)
> >> + mapping(const _LeftpadMapping& __other) noexcept
> >> + : mapping(__other.extents(), __mdspan::__internal_ctor{})
> >> + {
> >> + constexpr size_t __ostride_sta =
> __mdspan::__get_static_stride<
> >> + _LeftpadMapping>();
> >> +
> >> + if constexpr (extents_type::rank() > 1
> >> + && extents_type::static_extent(0) != dynamic_extent
> >> + && __ostride_sta != dynamic_extent)
> >> + static_assert(extents_type::static_extent(0) ==
> __ostride_sta);
> >> +
> >> + if constexpr (extents_type::rank() > 1)
> >> + __glibcxx_assert(__other.stride(1) ==
> >> __other.extents().extent(0));
> >> + }
> >> +#endif
> >> +
> >> constexpr mapping&
> >> operator=(const mapping&) noexcept = default;
> >>
> >> @@ -1173,6 +1260,582 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >> [[no_unique_address]] _Strides _M_strides;
> >> };
> >>
> >> +#ifdef __glibcxx_padded_layouts
> >> + namespace __mdspan
> >> + {
> >> + constexpr size_t
> >> + __least_multiple(size_t __x, size_t __y)
> >> + {
> >> + if (__x <= 1)
> >> + return __y;
> >> + return (__y / __x + (__y % __x != 0)) * __x ;
> >> + }
> >> +
> >> + template<typename _IndexType>
> >> + constexpr bool
> >> + __is_representable_least_multiple(size_t __x, size_t __y)
> >> + {
> >> + constexpr auto __y_max =
> __gnu_cxx::__int_traits<_IndexType>::__max;
> >> + if(std::cmp_greater(__y, __y_max))
> >> + return false;
> >> +
> >> + if(__x <= 1)
> >> + return true;
> >> +
> >> + auto __max_delta = __y_max - static_cast<_IndexType>(__y);
> >> + auto __y_mod_x = __y % __x;
> >> + auto __delta = (__y_mod_x == 0) ? size_t(0) : (__x - __y_mod_x);
> >> + return std::cmp_less_equal(__delta, __max_delta);
> >> + }
> >> +
> >> + template<typename _Extents, size_t _PaddingValue, typename
> >> _LayoutTraits,
> >> + size_t _Rank = _Extents::rank()>
> >> + concept __valid_static_stride = (_Extents::rank() <= 1)
> >> + || (_PaddingValue == dynamic_extent)
> >> + || (_Extents::static_extent(_LayoutTraits::_S_ext_idx) ==
> >> dynamic_extent)
> >> + || (__is_representable_least_multiple<size_t>(
> >> + _PaddingValue,
> >> _Extents::static_extent(_LayoutTraits::_S_ext_idx)));
> >> +
> >> + template<typename _TargetInt, size_t _PaddingValue, typename
> _Extents,
> >> + typename _LayoutTraits>
> >> + consteval bool
> >> + __is_representable_padded_size()
> >> + {
> >> + size_t __ext_idx = _LayoutTraits::_S_ext_idx;
> >> + auto __sta_exts = __static_extents<_Extents>(
> >> + _LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end);
> >> + auto __pad_ext = _Extents::static_extent(__ext_idx);
> >> + size_t __padded_stride = __least_multiple(_PaddingValue,
> >> __pad_ext);
> >> + auto __max = __gnu_cxx::__int_traits<_TargetInt>::__max;
> >> + return __static_quotient(__sta_exts, __max / __padded_stride)
> != 0;
> >> + }
> >> +
> >> + template<typename _TargetInt, typename _Extents, size_t
> _PaddingValue,
> >> + typename _LayoutTraits,
> >> + size_t _Rank = _Extents::rank()>
> >> + concept __valid_padded_size = (_Rank <= 1)
> >> + || (_PaddingValue == dynamic_extent)
> >> + || (!__all_static(__static_extents<_Extents>()))
> >> + || (__contains_zero(__static_extents<_Extents>()))
> >> + || (__is_representable_padded_size<_TargetInt, _PaddingValue,
> >> _Extents,
> >> + _LayoutTraits>());
> >> +
> >> + template<typename _Extents, typename _Stride, typename... _Indices>
> >> + constexpr typename _Extents::index_type
> >> + __linear_index_leftpad(const _Extents& __exts, _Stride __stride,
> >> + _Indices... __indices)
> >> + {
> >> + // i0 + stride*(i1 + extents.extent(1)*...)
> >> + using _IndexType = typename _Extents::index_type;
> >> + _IndexType __res = 0;
> >> + if constexpr (sizeof...(__indices) > 0)
> >> + {
> >> + _IndexType __mult = 1;
> >> +
> >> + auto __update_rest = [&, __pos = 1u](_IndexType __idx)
> mutable
> >> + {
> >> + __res += __idx * __mult;
> >> + __mult *= __exts.extent(__pos);
> >> + ++__pos;
> >> + };
> >> +
> >> + auto __update = [&](_IndexType __idx, auto... __rest)
> >> + {
> >> + __res += __idx;
> >> + __mult = __stride.extent(0);
> >> + (__update_rest(__rest), ...);
> >> + };
> >> + __update(__indices...);
> >> + }
> >> + return __res;
> >> + }
> >> +
> >> + template<size_t _Rank>
> >> + struct _LeftPaddedLayoutTraits
> >> + {
> >> + using _LayoutSame = layout_left;
> >> + using _LayoutOther = layout_right;
> >> +
> >> + constexpr static size_t _S_ext_idx = 0;
> >> + constexpr static size_t _S_stride_idx = 1;
> >> + constexpr static size_t _S_unpad_begin = 1;
> >> + constexpr static size_t _S_unpad_end = _Rank;
> >> +
> >> + template<typename _Mapping>
> >> + constexpr static bool _S_is_same_padded_mapping =
> >> + __is_left_padded_mapping<_Mapping>;
> >> +
> >> + template<typename _Mapping>
> >> + constexpr static bool _S_is_other_padded_mapping =
> >> + __is_right_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, _StaticStride,
> >> + (_Extents...[_Is + 1])...>{
> >> + __stride.extent(0), __exts.extent(_Is + 1)...};
> >> + };
> >> + return __impl(make_index_sequence<sizeof...(_Extents) -
> 1>());
> >> + }
> >> + };
> >> +
> >> + template<size_t _PaddingValue, typename _Extents, typename
> >> _LayoutTraits>
> >> + class _PaddedStorage
> >> + {
> >> + using _LayoutSame = typename _LayoutTraits::_LayoutSame;
> >> +
> >> + public:
> >> + using _IndexType = typename _Extents::index_type;
> >> + constexpr static size_t _S_rank = _Extents::rank();
> >> +
> >> + static_assert(__representable_size<_Extents, _IndexType>,
> >> + "The size of extents_type must be representable as
> index_type");
> >> +
> >> + static_assert(__valid_static_stride<_Extents, _PaddingValue,
> >> + _LayoutTraits>,
> >> + "The padded stride must be representable as size_t");
> >> +
> >> + static_assert(__valid_padded_size<size_t, _Extents,
> _PaddingValue,
> >> + _LayoutTraits>);
> >> +
> >> + static constexpr size_t _S_static_stride = [] consteval
> >> + {
> >> + constexpr size_t __rank = _Extents::rank();
> >> + if constexpr (__rank <= 1)
> >> + return 0;
> >> + else
> >> + {
> >> + constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
> >> + constexpr size_t __sta_ext =
> >> _Extents::static_extent(__ext_idx);
> >> + if constexpr (__sta_ext == 0)
> >> + return size_t(0);
> >> + else if constexpr (_PaddingValue == dynamic_extent
> >> + || __sta_ext == dynamic_extent)
> >> + return dynamic_extent;
> >> + else
> >> + return __least_multiple(_PaddingValue, __sta_ext);
> >> + }
> >> + }();
> >> +
> >> + static_assert(_S_static_stride == dynamic_extent
> >> + || cmp_less_equal(_S_static_stride,
> >> +
> __gnu_cxx::__int_traits<_IndexType>::__max));
> >> +
> >> + static_assert(__valid_padded_size<_IndexType, _Extents,
> >> _PaddingValue,
> >> + _LayoutTraits>);
> >> +
> >> + // _GLIBCXX_RESOLVE_LIB_DEFECTS
> >> + // 4372. Weaken Mandates: for dynamic padding values in padded
> >> layouts
> >> + static_assert((_PaddingValue == dynamic_extent)
> >> + || (cmp_less_equal(_PaddingValue,
> >> +
> >> __gnu_cxx::__int_traits<_IndexType>::__max)),
> >> + "padding_value must be representable as index_type");
> >> +
> >> + constexpr
> >> + _PaddedStorage() noexcept
> >> + {
> >> + if constexpr (_S_rank > 0)
> >> + {
> >> + constexpr size_t __sta_ext = _S_static_padded_extent();
> >> + if constexpr (_S_static_stride == dynamic_extent
> >> + && __sta_ext != dynamic_extent)
> >> + _M_stride = _Stride{__sta_ext};
> >> + }
> >> + }
> >> +
> >> + constexpr explicit
> >> + _PaddedStorage(const _Extents& __exts)
> >> + : _M_extents(__exts)
> >> + {
> >> + if constexpr (!__all_static(__static_extents<_Extents>()))
> >> + __glibcxx_assert(__is_representable_extents(_M_extents));
> >> +
> >> + if constexpr (_S_rank > 1)
> >> + {
> >> + constexpr size_t __sta_pad_ext =
> _S_static_padded_extent();
> >> + _IndexType __dyn_pad_ext = _M_dynamic_padded_extent();
> >> +
> >> + if constexpr (_PaddingValue != dynamic_extent)
> >> + __glibcxx_assert(
> >> + __is_representable_least_multiple<_IndexType>(
> >> + _PaddingValue, __dyn_pad_ext));
> >> +
> >> + _IndexType __stride;
> >> + if constexpr (_PaddingValue == dynamic_extent)
> >> + __stride = __dyn_pad_ext;
> >> + else if constexpr (__sta_pad_ext != dynamic_extent)
> >> + return;
> >> + else
> >> + {
> >> + __stride = static_cast<_IndexType>(
> >> + __least_multiple(_PaddingValue, __dyn_pad_ext));
> >> + __glibcxx_assert(__is_representable_extents(
> >> + _LayoutTraits::_S_make_padded_extent(
> >> + std::dextents<_IndexType, 1>{__stride},
> >> + _M_extents)));
> >> + }
> >> + _M_stride = _Stride{__stride};
> >> + }
> >> + }
> >> +
> >> + template<__valid_index_type<_IndexType> _OIndexType>
> >> + constexpr
> >> + _PaddedStorage(const _Extents& __exts, _OIndexType&& __opad)
> >> + : _M_extents(__exts)
> >> + {
> >> + if constexpr (std::is_integral_v<_OIndexType>)
> >> + {
> >> + __glibcxx_assert(cmp_less_equal(__opad,
> >> + __gnu_cxx::__int_traits<_IndexType>::__max));
> >> + if constexpr (std::is_signed_v<_OIndexType>)
> >> + __glibcxx_assert(__opad >= 0);
> >> + }
> >> + auto __pad = static_cast<_IndexType>(std::move(__opad));
> >> + if constexpr (std::is_signed_v<_IndexType>)
> >> + __glibcxx_assert(__pad >= 0);
> >> + if constexpr (_PaddingValue != dynamic_extent)
> >> + __glibcxx_assert(cmp_equal(_PaddingValue, __pad));
> >> + if constexpr (_S_rank > 1 && _S_static_stride ==
> >> dynamic_extent)
> >> + {
> >> + __glibcxx_assert(
> >> + __is_representable_least_multiple<_IndexType>(
> >> + __pad, _M_dynamic_padded_extent()));
> >> +
> >> + _M_stride = _Stride{static_cast<_IndexType>(
> >> + __least_multiple(__pad, _M_dynamic_padded_extent()))};
> >> +
> >> + __glibcxx_assert(__is_representable_extents(
> >> + _LayoutTraits::_S_make_padded_extent(
> >> + _M_stride, _M_extents)));
> >> + }
> >> + }
> >> +
> >> + template<typename _OExtents>
> >> + requires is_constructible_v<_Extents, _OExtents>
> >> + constexpr explicit
> >> + _PaddedStorage(const typename _LayoutSame::mapping<_OExtents>&
> >> + __other)
> >> + : _PaddedStorage(_Extents(__other.extents()))
> >> + {
> >> + constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
> >> + static_assert(_S_rank <= 1
> >> + || _S_static_stride == dynamic_extent
> >> + || _OExtents::static_extent(__ext_idx) == dynamic_extent
> >> + || _S_static_stride ==
> _OExtents::static_extent(__ext_idx),
> >> + "The padded stride must be compatible with other");
> >> +
> >> + if constexpr (_S_rank > 1 && _PaddingValue !=
> dynamic_extent)
> >> +
> __glibcxx_assert(std::cmp_equal(_M_dynamic_padded_stride(),
> >> +
> _M_dynamic_padded_extent()));
> >> + }
> >> +
> >> + template<typename _OExtents>
> >> + requires is_constructible_v<_OExtents, _Extents>
> >> + constexpr explicit
> >> + _PaddedStorage(const typename
> layout_stride::mapping<_OExtents>&
> >> + __other)
> >> + : _M_extents(__other.extents())
> >> + {
> >> + constexpr size_t __stride_idx =
> _LayoutTraits::_S_stride_idx;
> >> + if constexpr (_S_rank > 1 && _S_static_stride !=
> >> dynamic_extent)
> >> + __glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
> >> + _S_static_stride));
> >> + else if constexpr (_S_rank > 1 && _PaddingValue !=
> >> dynamic_extent)
> >> + __glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
> >> + __least_multiple(_PaddingValue,
> >> _M_dynamic_padded_extent())));
> >> +
> >> +
> __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
> >> +
> >> __gnu_cxx::__int_traits<_IndexType>
> >> + ::__max));
> >> +
> >> + if constexpr (_S_rank > 1 && _S_static_stride ==
> >> dynamic_extent)
> >> + _M_stride = _Stride{__other.stride(__stride_idx)};
> >> + }
> >> +
> >> + template<typename _SamePaddedMapping>
> >> + requires _LayoutTraits::template _S_is_same_padded_mapping<
> >> + _SamePaddedMapping>
> >> + && is_constructible_v<_Extents,
> >> + typename
> >> _SamePaddedMapping::extents_type>
> >> + constexpr explicit
> >> + _PaddedStorage(const _SamePaddedMapping& __other)
> >> + : _M_extents(__other.extents())
> >> + {
> >> + if constexpr (_S_rank > 1)
> >> + {
> >> + static_assert(_PaddingValue == dynamic_extent
> >> + || _SamePaddedMapping::padding_value ==
> dynamic_extent
> >> + || _PaddingValue == _SamePaddedMapping::padding_value,
> >> + "If neither PaddingValue is dynamic_extent, then they
> must
> >> "
> >> + "be equal");
> >> +
> >> + constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
> >> + constexpr size_t __stride_idx =
> _LayoutTraits::_S_stride_idx;
> >> + if constexpr (_S_static_stride != dynamic_extent)
> >> + __glibcxx_assert(cmp_equal(_S_static_stride,
> >> +
> __other.stride(__stride_idx)));
> >> + else if constexpr (_PaddingValue != dynamic_extent)
> >> + __glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
> >> + __least_multiple(
> >> + _PaddingValue,
> >> __other.extents().extent(__ext_idx)))
> >> + && "The padded stride must be compatible with other");
> >> +
> >> + if constexpr (_S_static_stride == dynamic_extent)
> >> + _M_stride = _Stride{__other.stride(__stride_idx)};
> >> + }
> >> +
> __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
> >> + __gnu_cxx::__int_traits<_IndexType>::__max));
> >> + }
> >> +
> >> + template<typename _OtherPaddedMapping>
> >> + requires (_LayoutTraits::template _S_is_other_padded_mapping<
> >> + _OtherPaddedMapping>
> >> + || __mapping_of<typename _LayoutTraits::_LayoutOther,
> >> + _OtherPaddedMapping>)
> >> + && (_S_rank <= 1)
> >> + && is_constructible_v<_Extents,
> >> + typename
> >> _OtherPaddedMapping::extents_type>
> >> + constexpr explicit
> >> + _PaddedStorage(const _OtherPaddedMapping& __other) noexcept
> >> + : _M_extents(__other.extents())
> >> + {
> >> +
> __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
> >> + __gnu_cxx::__int_traits<_IndexType>::__max));
> >> + }
> >> +
> >> + static constexpr bool
> >> + _M_is_always_exhaustive() noexcept
> >> + {
> >> + if constexpr (_S_rank <= 1)
> >> + return true;
> >> + else
> >> + {
> >> + constexpr size_t __sta_pad_ext =
> _S_static_padded_extent();
> >> + return __sta_pad_ext != dynamic_extent
> >> + && _S_static_stride != dynamic_extent
> >> + && __sta_pad_ext == _S_static_stride;
> >> + }
> >> + }
> >> +
> >> + constexpr bool
> >> + _M_is_exhaustive() const noexcept
> >> + {
> >> + if constexpr (_M_is_always_exhaustive())
> >> + return true;
> >> + else
> >> + return cmp_equal(_M_dynamic_padded_extent(),
> >> + _M_dynamic_padded_stride());
> >> + }
> >> +
> >> + constexpr static size_t
> >> + _S_static_padded_extent() noexcept
> >> + { return _Extents::static_extent(_LayoutTraits::_S_ext_idx); }
> >> +
> >> + constexpr _IndexType
> >> + _M_dynamic_padded_extent() const noexcept
> >> + { return _M_extents.extent(_LayoutTraits::_S_ext_idx); }
> >> +
> >> + constexpr size_t
> >> + _M_dynamic_padded_stride() const noexcept
> >> + { return _M_stride.extent(0); }
> >> +
> >> + constexpr _IndexType
> >> + _M_required_span_size() const noexcept
> >> + {
> >> + if constexpr (_S_rank == 0)
> >> + return 1;
> >> + else if (__mdspan::__empty(_M_extents))
> >> + return 0;
> >> + else
> >> + return static_cast<_IndexType>(
> >> + static_cast<size_t>(_M_dynamic_padded_stride())
> >> + * __mdspan::__fwd_prod(_M_extents,
> >> + _LayoutTraits::_S_unpad_begin,
> >> + _LayoutTraits::_S_unpad_end)
> >> + - static_cast<size_t>(_M_dynamic_padded_stride()
> >> + - _M_dynamic_padded_extent()));
> >> + }
> >> +
> >> + using _Stride = std::extents<_IndexType, _S_static_stride>;
> >> + [[no_unique_address]] _Stride _M_stride;
> >> + [[no_unique_address]] _Extents _M_extents{};
> >>
> > We do not need braces here, otherwise we would need them on _M_stride.
> >
>
> The argument being, that because the default ctor is implemented
> by calling mapping(extents_type{}) we can be sure they'll always
> get intialized?
>
The default constructor of extent will zero all dynamic extents. The {}
in member is only needed for classes which constructors do not initializer
members, For example:
struct S1 { int x; int y; };
S1 s1a; // s.x, s.y are intermediate
S1 s1b{}; // s.x, s.y are zero
struct S2 { int x = 1; int y; };
S2 s2a; // s.x is 1, s.y is intermediate
S2 s2b{}; // s.x is 1, s.y are zero
struct S3 { int x; int y; S3() { /* forgot to set x, y */ } };
S3 s3a; // s.x, s.y are intermediate
S3 s3b{}; // s.x, s.y are intermediate, because we call constructor that do
not set them
struct S4 { int x = 1; int y = 2; S() { } };
S3 s4a; // s.x is 1, s.y is 2
S3 s4a{}; // s.x is 1, s.y is 2
And we have this in _ExtentsStorage:
[[no_unique_address]] _Storage _M_dyn_exts{};
> The standard has it with:
> https://eel.is/c++draft/mdspan.layout.leftpad.overview#1
>
> >> + };
> >> + }
> >> +
> >> + template<size_t _PaddingValue>
> >> + template<typename _Extents>
> >> + class layout_left_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_left_padded<padding_value>;
> >> +
> >> + private:
> >> + static constexpr size_t _S_rank = extents_type::rank();
> >> + using _LeftPaddedStorage =
> __mdspan::_PaddedStorage<_PaddingValue,
> >> + _Extents, __mdspan::_LeftPaddedLayoutTraits<_S_rank>>;
> >> + [[no_unique_address]] _LeftPaddedStorage _M_storage;
> >> +
> >> + static constexpr size_t _S_static_stride =
> >> + _LeftPaddedStorage::_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_left::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 _LeftpadMapping>
> >> + requires __mdspan::__is_left_padded_mapping<_LeftpadMapping>
> >> + && is_constructible_v<extents_type,
> >> + typename
> _LeftpadMapping::extents_type>
> >> + constexpr explicit(_S_rank > 1 && (padding_value !=
> >> dynamic_extent
> >> + || _LeftpadMapping::padding_value == dynamic_extent))
> >> + mapping(const _LeftpadMapping& __other)
> >> + : _M_storage(__other)
> >> + { }
> >> +
> >> + template<typename _RightPaddedMapping>
> >> + requires
> >> (__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
> >> + || __mdspan::__mapping_of<layout_right,
> _RightPaddedMapping>)
> >> + && (_S_rank <= 1)
> >> + && 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
> >> + : _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[0] = 1;
> >> + if constexpr (_S_rank > 1)
> >> + __ret[1] = _M_dynamic_padded_stride();
> >> + if constexpr (_S_rank > 2)
> >> + for(size_t __i = 2; __i < _S_rank; ++__i)
> >> + __ret[__i] = __ret[__i - 1] * _M_extent(__i - 1);
> >> + 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_leftpad(
> >> + extents(), _M_storage._M_stride,
> >> + static_cast<index_type>(std::move(__indices))...);
> >> + }
> >> +
> >> + static constexpr bool
> >> + is_always_exhaustive() noexcept
> >> + { return _LeftPaddedStorage::_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 (__r == 0)
> >> + return 1;
> >> + else
> >> + return static_cast<index_type>(
> >> + static_cast<size_t>(_M_dynamic_padded_stride()) *
> >> + static_cast<size_t>(__mdspan::__fwd_prod(extents(), 1,
> >> __r)));
> >> + }
> >> +
> >> + template<typename _LeftpadMapping>
> >> + requires(__mdspan::__is_left_padded_mapping<_LeftpadMapping>
> >> + && _LeftpadMapping::extents_type::rank() == _S_rank)
> >> + friend constexpr bool
> >> + operator==(const mapping& __self, const _LeftpadMapping&
> __other)
> >> + noexcept
> >> + {
> >> + return __self.extents() == __other.extents()
> >> + && (_S_rank < 2 || cmp_equal(__self.stride(1),
> >> + __other.stride(1)));
> >> + }
> >> + };
> >> +#endif
> >> +
> >> template<typename _ElementType>
> >> struct default_accessor
> >> {
> >> diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/
> >> std.cc.in
> >> index 9352482cbdb..f10bab59e2c 100644
> >> --- a/libstdc++-v3/src/c++23/std.cc.in
> >> +++ b/libstdc++-v3/src/c++23/std.cc.in
> >> @@ -1869,9 +1869,11 @@ export namespace std
> >> using std::aligned_accessor;
> >> #endif
> >> using std::mdspan;
> >> - // FIXME layout_left_padded, layout_right_padded, strided_slice,
> >> - // submdspan_mapping_result, full_extent_t, full_extent,
> >> submdspan_extents,
> >> - // mdsubspan
> >> +#if __glibcxx_padded_layouts
> >> + using std::layout_left_padded;
> >> +#endif
> >> + // FIXME layout_right_padded, strided_slice,
> submdspan_mapping_result,
> >> + // full_extent_t, full_extent, submdspan_extents, mdsubspan
> >> }
> >> #endif
> >>
> >> diff --git
> >>
> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
> >>
> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
> >> index 7091153daba..edf07c983da 100644
> >> ---
> >>
> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
> >> +++
> >>
> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
> >> @@ -46,3 +46,4 @@ auto b6 = B<6, std::layout_stride,
> std::layout_left>();
> >> // { dg-error "require
> >> auto b7 = B<7, std::layout_stride, std::layout_stride>(); // {
> dg-error
> >> "required from" }
> >>
> >> // { dg-prune-output "must be representable as index_type" }
> >> +// { dg-prune-output "static assertion failed" }
> >> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
> >> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
> >> index 23c0a55dae1..891471467e1 100644
> >> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
> >> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
> >> @@ -1,11 +1,22 @@
> >> // { dg-do run { target c++23 } }
> >> #include <mdspan>
> >>
> >> +#include "padded_traits.h"
> >> #include <cstdint>
> >> #include <testsuite_hooks.h>
> >>
> >> constexpr size_t dyn = std::dynamic_extent;
> >>
> >> +#if __glibcxx_padded_layouts
> >> +template<typename Layout>
> >> + constexpr bool
> >> + is_padded_layout = is_left_padded<Layout>;
> >> +#else
> >> +template<typename>
> >> + constexpr bool
> >> + is_padded_layout = false;
> >> +#endif
> >> +
> >> template<typename Mapping, typename IndexType, size_t... Extents>
> >> constexpr void
> >> verify(std::extents<IndexType, Extents...> oexts)
> >> @@ -27,7 +38,6 @@ template<typename Mapping, typename OMapping>
> >> VERIFY(std::cmp_equal(m.stride(i), other.stride(i)));
> >> }
> >>
> >> -
> >> template<typename To, typename From>
> >> constexpr void
> >> verify_convertible(From from)
> >> @@ -40,7 +50,10 @@ template<typename To, typename From>
> >> constexpr void
> >> verify_nothrow_convertible(From from)
> >> {
> >> - static_assert(std::is_nothrow_constructible_v<To, From>);
> >> + if constexpr (is_padded_layout<typename To::layout_type>)
> >> + static_assert(std::is_constructible_v<To, From>);
> >> + else
> >> + static_assert(std::is_nothrow_constructible_v<To, From>);
> >> verify_convertible<To>(from);
> >> }
> >>
> >> @@ -57,7 +70,10 @@ template<typename To, typename From>
> >> constexpr void
> >> verify_nothrow_constructible(From from)
> >> {
> >> - static_assert(std::is_nothrow_constructible_v<To, From>);
> >> + if constexpr (is_padded_layout<typename To::layout_type>)
> >> + static_assert(std::is_constructible_v<To, From>);
> >> + else
> >> + static_assert(std::is_nothrow_constructible_v<To, From>);
> >> verify_constructible<To>(from);
> >> }
> >>
> >> @@ -196,6 +212,16 @@ namespace from_extents
> >> // ctor: mapping(mapping<OExtents>)
> >> namespace from_same_layout
> >> {
> >> + template<typename Layout, typename Extents, typename OExtents>
> >> + constexpr void
> >> + verify_convertible(OExtents exts)
> >> + {
> >> + using Mapping = typename Layout::mapping<Extents>;
> >> + using OMapping = typename Layout::mapping<OExtents>;
> >> +
> >> + ::verify_convertible<Mapping>(OMapping(exts));
> >> + }
> >> +
> >> template<typename Layout, typename Extents, typename OExtents>
> >> constexpr void
> >> verify_nothrow_convertible(OExtents exts)
> >> @@ -223,8 +249,12 @@ namespace from_same_layout
> >> verify_nothrow_convertible<Layout, std::extents<unsigned int>>(
> >> std::extents<int>{});
> >>
> >> - verify_nothrow_constructible<Layout, std::extents<int>>(
> >> - std::extents<unsigned int>{});
> >> + if constexpr (!is_padded_layout<Layout>)
> >> + verify_nothrow_constructible<Layout, std::extents<int>>(
> >> + std::extents<unsigned int>{});
> >> + else
> >> + verify_convertible<Layout, std::extents<int>>(
> >> + std::extents<unsigned int>{});
> >>
> >> assert_not_constructible<
> >> typename Layout::mapping<std::extents<int>>,
> >> @@ -234,8 +264,12 @@ namespace from_same_layout
> >> typename Layout::mapping<std::extents<int, 1>>,
> >> typename Layout::mapping<std::extents<int>>>();
> >>
> >> - verify_nothrow_constructible<Layout, std::extents<int, 1>>(
> >> - std::extents<int, dyn>{1});
> >> + if constexpr (!is_padded_layout<Layout>)
> >> + verify_nothrow_constructible<Layout, std::extents<int, 1>>(
> >> + std::extents<int, dyn>{1});
> >> + else
> >> + verify_convertible<Layout, std::extents<int, 1>>(
> >> + std::extents<int, dyn>{1});
> >>
> >> verify_nothrow_convertible<Layout, std::extents<int, dyn>>(
> >> std::extents<int, 1>{});
> >> @@ -247,8 +281,12 @@ namespace from_same_layout
> >> verify_nothrow_constructible<Layout, std::extents<int, 1, 2>>(
> >> std::extents<int, dyn, 2>{1});
> >>
> >> - verify_nothrow_convertible<Layout, std::extents<int, dyn, 2>>(
> >> - std::extents<int, 1, 2>{});
> >> + if constexpr (!is_padded_layout<Layout>)
> >> + verify_nothrow_convertible<Layout, std::extents<int, dyn, 2>>(
> >> + std::extents<int, 1, 2>{});
> >> + else
> >> + verify_nothrow_constructible<Layout, std::extents<int, dyn, 2>>(
> >> + std::extents<int, 1, 2>{});
> >> return true;
> >> }
> >>
> >> @@ -424,11 +462,24 @@ template<typename Layout>
> >> from_stride::test_all<Layout>();
> >> }
> >>
> >> +template<template<size_t> typename Layout>
> >> + constexpr void
> >> + test_padded_all()
> >> + {
> >> + test_all<Layout<0>>();
> >> + test_all<Layout<1>>();
> >> + test_all<Layout<2>>();
> >> + test_all<Layout<dyn>>();
> >> + }
> >> +
> >> int
> >> main()
> >> {
> >> test_all<std::layout_left>();
> >> test_all<std::layout_right>();
> >> +#ifdef __glibcxx_padded_layouts
> >> + test_padded_all<std::layout_left_padded>();
> >> +#endif
> >>
> >> from_left_or_right::test_all<std::layout_left, std::layout_right>();
> >> from_left_or_right::test_all<std::layout_right, std::layout_left>();
> >> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
> >> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
> >> index cbc425f6c15..236aca8bc2b 100644
> >> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
> >> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
> >> @@ -35,7 +35,8 @@ template<typename Layout, typename Int>
> >> {
> >> constexpr Int n1 = std::numeric_limits<Int>::max();
> >> constexpr size_t n2 = std::dynamic_extent - 1;
> >> - constexpr size_t n = std::cmp_less(n1, n2) ? size_t(n1) : n2;
> >> + // Allow some room for padding.
> >> + constexpr size_t n = (std::cmp_less(n1, n2) ? size_t(n1) : n2) - 4;
> >>
> >> verify_all(typename Layout::mapping<std::extents<Int, n, n, 0, n,
> >> n>>{});
> >> verify_all(typename Layout::mapping<std::extents<Int, 0, n, n,
> n>>{});
> >> @@ -73,7 +74,8 @@ template<typename Layout, typename Int>
> >> {
> >> constexpr Int n1 = std::numeric_limits<Int>::max();
> >> constexpr size_t n2 = std::dynamic_extent - 1;
> >> - constexpr Int n = std::cmp_less(n1, n2) ? n1 : Int(n2);
> >> + // Allow some room for padding.
> >> + constexpr Int n = (std::cmp_less(n1, n2) ? n1 : Int(n2)) - 4;
> >>
> >> verify_all(make_mapping<Layout>(
> >> std::extents<Int, dyn, dyn, 0, dyn, dyn>{n, n, n, n}));
> >> @@ -121,11 +123,25 @@ template<typename Layout>
> >> return true;
> >> }
> >>
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_padded_all()
> >> + {
> >> + static_assert(test_all<Layout<0>>());
> >> + static_assert(test_all<Layout<1>>());
> >> + static_assert(test_all<Layout<2>>());
> >> + static_assert(test_all<Layout<dyn>>());
> >> + return true;
> >> + }
> >> +
> >> int
> >> main()
> >> {
> >> static_assert(test_all<std::layout_left>());
> >> static_assert(test_all<std::layout_right>());
> >> static_assert(test_all<std::layout_stride>());
> >> +#ifdef __glibcxx_padded_layouts
> >> + static_assert(test_padded_all<std::layout_left_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 db15e2a48f3..5bf6bf65d3a 100644
> >> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
> >> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
> >> @@ -2,9 +2,11 @@
> >> #include <mdspan>
> >>
> >> #include "../int_like.h"
> >> +#include "padded_traits.h"
> >> #include <cstdint>
> >> #include <testsuite_hooks.h>
> >>
> >> +
> >> constexpr size_t dyn = std::dynamic_extent;
> >>
> >> template<typename Mapping>
> >> @@ -370,6 +372,37 @@ template<>
> >> }
> >> };
> >>
> >> +#if __glibcxx_padded_layouts
> >> +template<typename Layout>
> >> + requires is_left_padded<Layout>
> >> + struct TestStride2D<Layout>
> >> + {
> >> + static constexpr void
> >> + run()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
> >> + using Extents = typename Traits::extents_type<std::extents<int,
> 3,
> >> 5>>;
> >> + using Mapping = typename Layout::mapping<Extents>;
> >> + constexpr size_t padding_value = Mapping::padding_value;
> >> +
> >> + Mapping m;
> >> + size_t effective_pad = (padding_value == 0 || padding_value ==
> dyn)
> >> + ? size_t(1) : padding_value;
> >> +
> >> + constexpr auto i0 = is_left_padded<Layout> ? 0 : 1;
> >> + VERIFY(m.stride(i0) == 1);
> >> +
> >> + // The next multiple of padding_value, that's greater or equal
> >> + // to exts.extent(0) is the unique value in the range:
> >> + // [exts.extent(0), exts.extent(0) + padding_value)
> >> + // that is divisible by padding_value.
> >> + auto stride = Traits::padded_stride(m);
> >> + VERIFY((stride % effective_pad) == 0);
> >> + VERIFY(3 <= stride && std::cmp_less(stride, 3 + effective_pad));
> >> + }
> >> + };
> >> +#endif
> >> +
> >> template<typename Layout>
> >> constexpr void
> >> test_stride_2d()
> >> @@ -423,6 +456,40 @@ template<>
> >> }
> >> };
> >>
> >> +#if __glibcxx_padded_layouts
> >> +template<typename Layout>
> >> + requires is_left_padded<Layout>
> >> + struct TestStride3D<Layout>
> >> + {
> >> + static constexpr void
> >> + run()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
> >> + using Extents = typename Traits::extents_type<std::extents<int,
> 3,
> >> 5, 7>>;
> >> + using Mapping = typename Layout::mapping<Extents>;
> >> + constexpr size_t padding_value = Mapping::padding_value;
> >> +
> >> + Mapping m;
> >> + size_t effective_pad = (padding_value == 0 || padding_value ==
> dyn)
> >> + ? size_t(1) : padding_value;
> >> +
> >> + constexpr auto i0 = is_left_padded<Layout> ? 0 : 2;
> >> + VERIFY(m.stride(i0) == 1);
> >> +
> >> + // The next multiple of padding_value, that's greater or equal
> >> + // to exts.extent(0) is the unique value in the range:
> >> + // [exts.extent(0), exts.extent(0) + padding_value)
> >> + // that is divisible by padding_value.
> >> + auto stride = Traits::padded_stride(m);
> >> + VERIFY((stride % effective_pad) == 0);
> >> + VERIFY(3 <= stride && std::cmp_less(stride, 3 + effective_pad));
> >> +
> >> + constexpr auto i2 = is_left_padded<Layout> ? 2 : 0;
> >> + VERIFY(stride * 5 == m.stride(i2));
> >> + }
> >> + };
> >> +#endif
> >> +
> >> template<typename Layout>
> >> constexpr void
> >> test_stride_3d()
> >> @@ -451,7 +518,8 @@ template<typename Layout>
> >> test_has_stride_0d()
> >> {
> >> using Mapping = typename Layout::mapping<std::extents<int>>;
> >> - constexpr bool expected = std::is_same_v<Layout,
> std::layout_stride>;
> >> + constexpr bool expected = !(std::is_same_v<Layout,
> std::layout_left>
> >> + || std::is_same_v<Layout, std::layout_right>);
> >> static_assert(has_stride<Mapping> == expected);
> >> }
> >>
> >> @@ -595,16 +663,54 @@ template<typename Layout>
> >> test_has_op_eq<Layout, Layout, true>();
> >> }
> >>
> >> +#ifdef __glibcxx_padded_layouts
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_padded_all()
> >> + {
> >> + test_all<Layout<0>>();
> >> + test_all<Layout<1>>();
> >> + test_all<Layout<2>>();
> >> + test_all<Layout<5>>();
> >> + test_all<Layout<dyn>>();
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_padded_has_op_eq()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + test_has_op_eq<typename Traits::layout_same, Layout<0>, false>();
> >> + test_has_op_eq<typename Traits::layout_same, Layout<6>, false>();
> >> + test_has_op_eq<typename Traits::layout_same, Layout<dyn>, false>();
> >> + // The next one looks strange, because it's neither. Somehow, the
> >> + // conversion rules seem to be playing a critical role again.
> >> + // test_has_op_eq<typename Traits::layout_other, Layout<0>,
> false>();
> >> +
> >> + test_has_op_eq<Layout<2>, Layout<6>, true>();
> >> + test_has_op_eq<Layout<2>, Layout<dyn>, true>();
> >> + return true;
> >> + }
> >> +#endif
> >> +
> >> int
> >> main()
> >> {
> >> test_all<std::layout_left>();
> >> test_all<std::layout_right>();
> >> test_all<std::layout_stride>();
> >> +#ifdef __glibcxx_padded_layouts
> >> + test_padded_all<std::layout_left_padded>();
> >> +#endif
> >>
> >> test_has_op_eq<std::layout_right, std::layout_left, false>();
> >> test_has_op_eq<std::layout_right, std::layout_stride, true>();
> >> test_has_op_eq<std::layout_left, std::layout_stride, true>();
> >> +#ifdef __glibcxx_padded_layouts
> >> + test_padded_has_op_eq<std::layout_left_padded>();
> >> +#endif
> >> +
> >> test_has_op_eq_peculiar();
> >> return 0;
> >> }
> >> diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
> >> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
> >> new file mode 100644
> >> index 00000000000..ea9a8ef3f4b
> >> --- /dev/null
> >> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
> >> @@ -0,0 +1,675 @@
> >> +// { dg-do run { target c++26 } }
> >> +#include <mdspan>
> >> +
> >> +#include <cstdint>
> >> +#include "../int_like.h"
> >> +#include "padded_traits.h"
> >> +#include <testsuite_hooks.h>
> >> +
> >> +#include <iostream>
> >> +
> >> +constexpr size_t dyn = std::dynamic_extent;
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_representable_padded_size()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + {
> >> + using E = typename Traits::extents_type<std::extents<uint8_t, 64,
> >> 2>>;
> >> + [[maybe_unused]] typename Layout<1>::mapping<E> m1;
> >> + }
> >> +
> >> + {
> >> + using E = typename Traits::extents_type<std::extents<uint8_t, 0,
> >> 2>>;
> >> + [[maybe_unused]] typename Layout<0>::mapping<E> m1;
> >> + [[maybe_unused]] typename Layout<1>::mapping<E> m2;
> >> + [[maybe_unused]] typename Layout<128>::mapping<E> m3;
> >> + [[maybe_unused]] typename Layout<255>::mapping<E> m4;
> >> + }
> >> +
> >> + {
> >> + using E = typename Traits::extents_type<std::extents<uint8_t, 0,
> >> 2>>;
> >> + [[maybe_unused]] typename Layout<dyn>::mapping<E> m1(E{}, 0);
> >> + [[maybe_unused]] typename Layout<dyn>::mapping<E> m2(E{}, 1);
> >> + [[maybe_unused]] typename Layout<dyn>::mapping<E> m3(E{}, 128);
> >> + [[maybe_unused]] typename Layout<dyn>::mapping<E> m4(E{}, 255);
> >> + }
> >> +
> >> + {
> >> + using E = typename Traits::extents_type<std::extents<uint8_t,
> dyn,
> >> 2>>;
> >> + [[maybe_unused]] typename Layout<0>::mapping<E> m1;
> >> + [[maybe_unused]] typename Layout<1>::mapping<E> m2;
> >> + [[maybe_unused]] typename Layout<128>::mapping<E> m3;
> >> + [[maybe_unused]] typename Layout<255>::mapping<E> m4;
> >> + }
> >> + return true;
> >> + }
> >> +
> >> +template<typename Layout, typename CanonicalExtents>
> >> + constexpr void
> >> + test_default_ctor_single(auto canonical_strides)
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
> >> + using E = typename Traits::extents_type<CanonicalExtents>;
> >> + auto strides = Traits::make_expected(canonical_strides);
> >> +
> >> + typename Layout::template mapping<E> msta;
> >> + VERIFY(msta.stride(0) == strides[0]);
> >> + VERIFY(msta.stride(1) == strides[1]);
> >> + }
> >> +
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_default_ctor()
> >> + {
> >> + using E1 = std::extents<size_t, 3, 5>;
> >> + test_default_ctor_single<Layout<2>, E1>(std::array<size_t, 2>{1,
> 4});
> >> + test_default_ctor_single<Layout<dyn>, E1>(std::array<size_t, 2>{1,
> >> 3});
> >> +
> >> + using E2 = std::extents<size_t, dyn, 5>;
> >> + test_default_ctor_single<Layout<2>, E2>(std::array<size_t, 2>{1,
> 0});
> >> + test_default_ctor_single<Layout<dyn>, E2>(std::array<size_t, 2>{1,
> >> 0});
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_exts()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto exts = Traits::make_extents(std::dextents<size_t, 2>{3, 5});
> >> +
> >> + typename Layout<0>::mapping m0_sta(exts);
> >> + VERIFY(Traits::padded_stride(m0_sta) ==
> Traits::padded_extent(exts));
> >> +
> >> + typename Layout<1>::mapping m1_sta(exts);
> >> + VERIFY(Traits::padded_stride(m1_sta) ==
> Traits::padded_extent(exts));
> >> +
> >> + typename Layout<2>::mapping m2_sta(exts);
> >> + VERIFY(Traits::padded_stride(m2_sta) == 4);
> >> +
> >> + typename Layout<dyn>::mapping mdyn(exts);
> >> + VERIFY(Traits::padded_stride(mdyn) == Traits::padded_extent(exts));
> >> + return true;
> >> + }
> >> +
> >> +template<typename Layout, typename CustomPadType>
> >> + constexpr bool
> >> + test_from_pad_single()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
> >> + auto pad = 3;
> >> + auto exts = Traits::make_extents(std::dextents<size_t, 3>{pad + 1,
> 5,
> >> 7});
> >> + typename Layout::mapping m(exts, CustomPadType{pad});
> >> + VERIFY(std::cmp_equal(Traits::padded_stride(m), 2*pad));
> >> + VERIFY(m.extents() == exts);
> >> + return true;
> >> + }
> >> +
> >> +template<typename Layout>
> >> + constexpr void
> >> + test_from_pad()
> >> + {
> >> + test_from_pad_single<Layout, int>();
> >> + static_assert(test_from_pad_single<Layout, int>());
> >> +
> >> + test_from_pad_single<Layout, IntLike>();
> >> + test_from_pad_single<Layout, MutatingInt>();
> >> + test_from_pad_single<Layout, RValueInt>();
> >> +
> >> + using Extents = std::dims<3>;
> >> + using Mapping = Layout::template mapping<Extents>;
> >> + static_assert(!std::is_constructible_v<Mapping, Extents,
> >> ThrowingInt>);
> >> + static_assert(!std::is_constructible_v<Mapping, Extents,
> NotIntLike>);
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr void
> >> + test_from_pad_all()
> >> + {
> >> + test_from_pad<Layout<3>>();
> >> + test_from_pad<Layout<dyn>>();
> >> + }
> >> +
> >> +constexpr bool
> >> +is_same_mapping(const auto& lhs, const auto& rhs)
> >> +{
> >> + if (lhs.extents().rank() != rhs.extents().rank())
> >> + return false;
> >> +
> >> + if (lhs.extents() != rhs.extents())
> >> + return false;
> >> +
> >> + for (size_t i = 0; i < lhs.extents().rank(); ++i)
> >> + if (lhs.stride(i) != rhs.stride(i))
> >> + return false;
> >> + return true;
> >> +}
> >> +
> >> +enum class ConversionRule
> >> +{
> >> + Never,
> >> + Always,
> >> + Regular
> >> +};
> >> +
> >> +template<typename To, typename From>
> >> +consteval bool
> >> +should_convert(auto rule)
> >> +{
> >> + if constexpr (rule == ConversionRule::Never)
> >> + return false;
> >> + if constexpr (rule == ConversionRule::Always)
> >> + return true;
> >> + else
> >> + return std::is_convertible_v<typename From::extents_type,
> >> + typename To::extents_type>;
> >> +}
> >> +
> >> +template<typename To, typename From>
> >> + constexpr void
> >> + check_convertible(const From& m, auto conversion_rule)
> >> + {
> >> + VERIFY(is_same_mapping(m, To(m)));
> >> + constexpr bool expected = should_convert<To,
> From>(conversion_rule);
> >> + static_assert(std::is_convertible_v<From, To> == expected);
> >> + }
> >> +
> >> +template<typename LayoutTo, typename Esta, typename Edyn, typename
> Ewrong>
> >> + constexpr void
> >> + check_convertible_variants(auto msta, auto conversion_rule)
> >> + {
> >> + using LayoutFrom = decltype(msta)::layout_type;
> >> + constexpr auto cregular = std::cw<ConversionRule::Regular>;
> >> +
> >> + // There's a twist when both mappings are left-padded. There's two
> >> distinct
> >> + // ctors: a defaulted copy ctor and a constrained template that
> >> enables
> >> + // construction from left-padded mappings even if their
> layout_type is
> >> + // different. The two ctors have different rules regarding
> conversion.
> >> +
> >> + if constexpr (!std::same_as<LayoutTo, LayoutFrom>)
> >> + check_convertible<typename LayoutTo::mapping<Esta>>(msta,
> >> conversion_rule);
> >> + else
> >> + check_convertible<typename LayoutTo::mapping<Esta>>(msta,
> cregular);
> >> +
> >> + check_convertible<typename LayoutTo::mapping<Edyn>>(msta,
> >> conversion_rule);
> >> +
> >> + auto mdyn = typename LayoutFrom::mapping<Edyn>(msta);
> >> + check_convertible<typename LayoutTo::mapping<Esta>>(mdyn,
> >> conversion_rule);
> >> + if constexpr (!std::same_as<LayoutTo, LayoutFrom>)
> >> + check_convertible<typename LayoutTo::mapping<Edyn>>(mdyn,
> >> conversion_rule);
> >> + else
> >> + check_convertible<typename LayoutTo::mapping<Edyn>>(mdyn,
> cregular);
> >> +
> >> + static_assert(!std::is_constructible_v<
> >> + typename LayoutTo::mapping<Esta>, typename
> >> LayoutFrom::mapping<Ewrong>>);
> >> + };
> >> +
> >> +template<typename Layout>
> >> + constexpr void
> >> + test_from_same_1d()
> >> + {
> >> + using E1 = std::extents<int, 6>;
> >> + using E2 = std::extents<int, dyn>;
> >> + using E3 = std::extents<int, 5>;
> >> + constexpr auto cr = std::cw<ConversionRule::Regular>;
> >> +
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
> >> + auto msta = typename Traits::layout_same::mapping(E1{});
> >> + check_convertible_variants<Layout, E1, E2, E3>(msta, cr);
> >> + }
> >> +
> >> +template<typename Layout>
> >> + constexpr void
> >> + test_from_same_2d()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_typename<Layout>()>;
> >> + using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
> >> + using E2 = typename Traits::extents_type<std::extents<int, dyn,
> 5>>;
> >> + using E3 = typename Traits::extents_type<std::extents<int, 6, 6>>;
> >> + constexpr auto cr = std::cw<ConversionRule::Regular>;
> >> +
> >> + auto msta = typename Traits::layout_same::mapping(E1{});
> >> + check_convertible_variants<Layout, E1, E2, E3>(msta, cr);
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> +constexpr bool
> >> +test_from_same()
> >> +{
> >> + auto check = []<typename PaddedLayout>(PaddedLayout)
> >> + {
> >> + test_from_same_1d<PaddedLayout>();
> >> + test_from_same_2d<PaddedLayout>();
> >> + };
> >> +
> >> + check(Layout<0>{});
> >> + check(Layout<1>{});
> >> + check(Layout<2>{});
> >> + check(Layout<6>{});
> >> + check(Layout<dyn>{});
> >> +
> >> + // rank == 1 is more permissive:
> >> + test_from_same_1d<Layout<5>>();
> >> + return true;
> >> +}
> >> +
> >> +template<template<size_t> typename Layout, typename E1_, typename E2_,
> >> + typename E3_>
> >> + constexpr bool
> >> + test_from_stride_nd(auto strides_)
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using E1 = typename Traits::extents_type<E1_>;
> >> + using E2 = typename Traits::extents_type<E2_>;
> >> + using E3 = typename Traits::extents_type<E3_>;
> >> + auto strides = Traits::make_expected(strides_);
> >> +
> >> + auto check = [&strides]<typename PaddedLayout>(PaddedLayout)
> >> + {
> >> + auto exts = E1{};
> >> + constexpr auto cr = std::cw<ConversionRule::Never>;
> >> +
> >> + auto m = std::layout_stride::mapping(exts, strides);
> >> + check_convertible_variants<PaddedLayout, E1, E2, E3>(m, cr);
> >> + };
> >> +
> >> + check(Layout<0>{});
> >> + check(Layout<1>{});
> >> + check(Layout<2>{});
> >> + check(Layout<6>{});
> >> + check(Layout<dyn>{});
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_stride_2d()
> >> + {
> >> + using E1 = std::extents<size_t, 6, 5>;
> >> + using E2 = std::dims<2>;
> >> + using E3 = std::extents<size_t, 6, 6>;
> >> +
> >> + auto strides = std::array<int, 2>{1, 6};
> >> + test_from_stride_nd<Layout, E1, E2, E3>(strides);
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_stride_3d()
> >> + {
> >> + using E1 = std::extents<size_t, 6, 5, 7>;
> >> + using E2 = std::dims<3>;
> >> + using E3 = std::extents<size_t, 6, 6, 7>;
> >> +
> >> + auto strides = std::array<int, 3>{1, 6, 6*5};
> >> + test_from_stride_nd<Layout, E1, E2, E3>(strides);
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_stride()
> >> + {
> >> + test_from_stride_2d<Layout>();
> >> + test_from_stride_3d<Layout>();
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr void
> >> + test_from_samepad_0d()
> >> + {
> >> + using E1 = std::extents<uint16_t>;
> >> + using E2 = std::extents<uint8_t>;
> >> + using E3 = std::extents<uint8_t, 1>;
> >> +
> >> + typename Layout<6>::mapping<E1> msta{E1{}};
> >> +
> >> + auto check = []<typename To>(To, auto m)
> >> + {
> >> + constexpr auto cr = std::cw<ConversionRule::Always>;
> >> + check_convertible_variants<To, E1, E2, E3>(m, cr);
> >> + };
> >> +
> >> + check(Layout<6>{}, msta);
> >> + check(Layout<dyn>{}, msta);
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr void
> >> + test_from_samepad_1d()
> >> + {
> >> + using E1 = std::extents<int, 6>;
> >> + using E2 = std::extents<int, dyn>;
> >> + using E3 = std::extents<int, 6, 6>;
> >> +
> >> + typename Layout<6>::mapping<E1> msta{E1{}};
> >> + typename Layout<dyn>::mapping<E1> mdyn{E1{}};
> >> +
> >> + auto check = []<typename To>(To, auto m)
> >> + {
> >> + constexpr auto cr = std::cw<ConversionRule::Always>;
> >> + check_convertible_variants<To, E1, E2, E3>(m, cr);
> >> + };
> >> +
> >> + // Remember, for rank <= 1 the padding_value is irrelevant.
> >> + check(Layout<6>{}, msta);
> >> + check(Layout<6>{}, mdyn);
> >> + check(Layout<dyn>{}, msta);
> >> + check(Layout<dyn>{}, mdyn);
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr void
> >> + test_from_samepad_2d()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
> >> + using E2 = typename Traits::extents_type<std::extents<int, dyn,
> 5>>;
> >> + using E3 = typename Traits::extents_type<std::extents<int, 6, 6>>;
> >> +
> >> + typename Layout<6>::mapping<E1> msta{E1{}};
> >> + typename Layout<dyn>::mapping<E1> mdyn{E1{}};
> >> +
> >> + constexpr auto calways = std::cw<ConversionRule::Always>;
> >> + constexpr auto cnever = std::cw<ConversionRule::Never>;
> >> +
> >> + auto check = []<typename To>(To, auto m, auto cr)
> >> + { check_convertible_variants<To, E1, E2, E3>(m, cr); };
> >> +
> >> + check(Layout<6>{}, msta, cnever);
> >> + check(Layout<6>{}, mdyn, cnever);
> >> + check(Layout<dyn>{}, msta, calways);
> >> + check(Layout<dyn>{}, mdyn, cnever);
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_samepad()
> >> + {
> >> + test_from_samepad_0d<Layout>();
> >> + test_from_samepad_1d<Layout>();
> >> + test_from_samepad_2d<Layout>();
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_other()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using E1 = std::extents<size_t, 3>;
> >> + using E2 = std::dims<1>;
> >> + using E3 = std::extents<size_t, 5>;
> >> +
> >> + auto check = []<typename PaddedLayout>(PaddedLayout)
> >> + {
> >> + constexpr auto cr = std::cw<ConversionRule::Regular>;
> >> +
> >> + using layout_other = typename Traits::layout_other;
> >> + auto msta = typename layout_other::mapping(E1{});
> >> + check_convertible_variants<PaddedLayout, E1, E2, E3>(msta, cr);
> >> + };
> >> +
> >> +
> >> + // Remember, the padding_value has no effect for rank <= 1.
> >> + check(Layout<0>{});
> >> + check(Layout<1>{});
> >> + check(Layout<2>{});
> >> + check(Layout<5>{});
> >> + check(Layout<6>{});
> >> + check(Layout<dyn>{});
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_to_same()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
> >> + using E2 = typename Traits::extents_type<std::extents<int, dyn,
> 5>>;
> >> + using E3 = typename Traits::extents_type<std::extents<int, 6, 6>>;
> >> +
> >> + auto check = [](auto msta)
> >> + {
> >> + constexpr auto cr = std::cw<ConversionRule::Regular>;
> >> + using LayoutSame = typename Traits::layout_same;
> >> + check_convertible_variants<LayoutSame, E1, E2, E3>(msta, cr);
> >> + };
> >> +
> >> + check(typename Layout<0>::mapping(E1{}));
> >> + check(typename Layout<2>::mapping(E1{}));
> >> + check(typename Layout<6>::mapping(E1{}));
> >> + check(typename Layout<dyn>::mapping(E1{}, 0));
> >> + check(typename Layout<dyn>::mapping(E1{}, 2));
> >> + check(typename Layout<dyn>::mapping(E1{}, 6));
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_never_to_other()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using E1 = std::extents<size_t, 3>;
> >> + using E2 = std::dims<1>;
> >> +
> >> + auto check = []<typename PaddedLayout>(PaddedLayout, auto exts)
> >> + {
> >> + using LayoutOther = typename Traits::layout_other;
> >> + auto mr = typename LayoutOther::mapping(exts);
> >> + auto mlp = typename PaddedLayout::mapping<decltype(exts)>{mr};
> >> + static_assert(!std::is_constructible_v<decltype(mr),
> >> decltype(mlp)>);
> >> + };
> >> +
> >> + check(Layout<2>{}, E1{});
> >> + check(Layout<2>{}, E2{E1{}});
> >> + return true;
> >> + }
> >> +
> >> +template<typename Layout>
> >> + constexpr void
> >> + test_strides()
> >> + {
> >> + auto check = [](auto exts)
> >> + {
> >> + auto m = typename Layout::mapping(exts);
> >> + using IndexType = typename decltype(m)::index_type;
> >> + constexpr size_t rank = decltype(m)::extents_type::rank();
> >> +
> >> + auto strides = m.strides();
> >> + static_assert(std::same_as<decltype(strides),
> >> + std::array<IndexType, rank>>);
> >> + VERIFY(strides.size() == rank);
> >> + for (size_t i = 0; i < strides.size(); ++i)
> >> + VERIFY(strides[i] == m.stride(i));
> >> + };
> >> +
> >> + check(std::extents());
> >> + check(std::extents(0));
> >> + check(std::extents(3));
> >> + check(std::extents(3, 5, 7));
> >> + check(std::extents(3, 0, 7));
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_strides_all()
> >> + {
> >> + test_strides<Layout<0>>();
> >> + test_strides<Layout<1>>();
> >> + test_strides<Layout<3>>();
> >> + test_strides<Layout<dyn>>();
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr void
> >> + test_exhaustive_0d()
> >> + {
> >> + auto exts = std::extents<int>{};
> >> +
> >> + auto check = [](auto m)
> >> + {
> >> + static_assert(m.is_always_exhaustive());
> >> + VERIFY(m.is_exhaustive());
> >> + };
> >> +
> >> + check(typename Layout<0>::mapping(exts));
> >> + check(typename Layout<1>::mapping(exts));
> >> + check(typename Layout<2>::mapping(exts));
> >> + check(typename Layout<dyn>::mapping(exts));
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> +constexpr void
> >> + test_exhaustive_1d()
> >> + {
> >> + auto check_dyn_and_sta = []<typename PaddedLayout>(PaddedLayout)
> >> + {
> >> + auto check = [](auto exts)
> >> + {
> >> + auto m = typename PaddedLayout::mapping(exts);
> >> + static_assert(m.is_always_exhaustive());
> >> + VERIFY(m.is_exhaustive());
> >> + };
> >> +
> >> + check(std::extents(4));
> >> + check(std::extents<int, 4>{});
> >> + };
> >> +
> >> + check_dyn_and_sta(Layout<1>{});
> >> + check_dyn_and_sta(Layout<2>{});
> >> + check_dyn_and_sta(Layout<6>{});
> >> + check_dyn_and_sta(Layout<dyn>{});
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr void
> >> + test_exhaustive_3d()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto exts_dyn = Traits::make_extents(std::extents(4, 5, 7));
> >> + auto exts_sta = Traits::make_extents(std::extents<int, 4, 5, 7>{});
> >> + auto ctrue = std::cw<true>;
> >> + auto cfalse= std::cw<false>;
> >> +
> >> + auto check = [](auto m, auto static_expected, auto
> runtime_expected)
> >> + {
> >> + static_assert(m.is_always_exhaustive() == static_expected);
> >> + VERIFY(m.is_exhaustive() == runtime_expected);
> >> + };
> >> +
> >> + check(typename Layout<0>::mapping(exts_sta), ctrue, true);
> >> + check(typename Layout<0>::mapping(exts_dyn), cfalse, true);
> >> + check(typename Layout<1>::mapping(exts_sta), ctrue, true);
> >> + check(typename Layout<1>::mapping(exts_dyn), cfalse, true);
> >> + check(typename Layout<2>::mapping(exts_sta), ctrue, true);
> >> + check(typename Layout<2>::mapping(exts_dyn), cfalse, true);
> >> + check(typename Layout<6>::mapping(exts_dyn), cfalse, false);
> >> + check(typename Layout<6>::mapping(exts_sta), cfalse, false);
> >> + check(typename Layout<dyn>::mapping(exts_sta), cfalse, true);
> >> + check(typename Layout<dyn>::mapping(exts_dyn, 2), cfalse, true);
> >> + check(typename Layout<dyn>::mapping(exts_dyn, 3), cfalse, false);
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_exhaustive()
> >> + {
> >> + test_exhaustive_0d<Layout>();
> >> + test_exhaustive_1d<Layout>();
> >> + test_exhaustive_3d<Layout>();
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_op_eq()
> >> + {
> >> + // The generic cases are handled in layouts/mapping.cc. Here we
> check
> >> + // special cases related to non exhaustive layouts.
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> +
> >> + auto exts_sta = Traits::make_extents(std::extents<size_t, 6, 5,
> 7>{});
> >> + auto exts_dyn = std::dims<3>(exts_sta);
> >> + auto exts_other = Traits::make_extents(std::extents<size_t, 7, 5,
> >> 7>{});
> >> +
> >> + auto m1 = typename Layout<0>::mapping(exts_sta);
> >> + auto m2 = typename Layout<7>::mapping(exts_sta);
> >> +
> >> + VERIFY(m1 == typename Layout<0>::mapping(exts_sta));
> >> + VERIFY(m1 == typename Layout<1>::mapping(exts_sta));
> >> + VERIFY(m1 == typename Layout<2>::mapping(exts_sta));
> >> + VERIFY(m1 == typename Layout<6>::mapping(exts_sta));
> >> + VERIFY(m1 != typename Layout<7>::mapping(exts_sta));
> >> + VERIFY(m1 == typename Layout<dyn>::mapping(exts_sta));
> >> + VERIFY(m1 != typename Layout<dyn>::mapping(exts_sta, 7));
> >> +
> >> + VERIFY(m1 == typename Layout<0>::mapping(exts_dyn));
> >> + VERIFY(m1 == typename Layout<1>::mapping(exts_dyn));
> >> + VERIFY(m1 == typename Layout<2>::mapping(exts_dyn));
> >> + VERIFY(m1 == typename Layout<6>::mapping(exts_dyn));
> >> + VERIFY(m1 != typename Layout<7>::mapping(exts_dyn));
> >> + VERIFY(m1 == typename Layout<dyn>::mapping(exts_dyn));
> >> + VERIFY(m1 != typename Layout<dyn>::mapping(exts_dyn, 7));
> >> +
> >> + VERIFY(m2 == typename Layout<7>::mapping(exts_sta));
> >> + VERIFY(m2 == typename Layout<dyn>::mapping(exts_sta, 7));
> >> + VERIFY(m2 == typename Layout<7>::mapping(exts_dyn));
> >> + VERIFY(m2 == typename Layout<dyn>::mapping(exts_dyn, 7));
> >> +
> >> + VERIFY(m2 != typename Layout<7>::mapping(exts_other));
> >> + VERIFY(m2 != typename Layout<dyn>::mapping(exts_other, 7));
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_required_span_size_overflow()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using Extents = std::dextents<uint8_t, 2>;
> >> + auto exts = Traits::make_extents(Extents{64, 2});
> >> + auto strides = Traits::make_expected(std::array<uint8_t, 2>{1,
> 128});
> >> + auto ms = std::layout_stride::mapping(exts, strides);
> >> + auto m = typename Layout<dyn>::mapping<Extents>(ms);
> >> + VERIFY(is_same_mapping(m, ms));
> >> + VERIFY(m.required_span_size() == ms.required_span_size());
> >> + return true;
> >> + }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_all()
> >> + {
> >> + test_representable_padded_size<std::layout_left_padded>();
> >> + test_default_ctor<Layout>();
> >> + test_from_exts<Layout>();
> >> + test_from_stride<Layout>();
> >> + test_from_samepad<Layout>();
> >> + test_from_same<Layout>();
> >> + test_from_other<Layout>();
> >> + test_to_same<Layout>();
> >> + test_never_to_other<Layout>();
> >> + test_strides_all<Layout>();
> >> + test_exhaustive<Layout>();
> >> + test_op_eq<Layout>();
> >> + test_required_span_size_overflow<Layout>();
> >> + return true;
> >> + }
> >> +
> >> +int
> >> +main()
> >> +{
> >> + test_all<std::layout_left_padded>();
> >> + static_assert(test_all<std::layout_left_padded>());
> >> +
> >> + test_from_pad_all<std::layout_left_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
> >> new file mode 100644
> >> index 00000000000..29f12aa4de2
> >> --- /dev/null
> >> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc
> >> @@ -0,0 +1,324 @@
> >> +// { dg-do compile { target c++26 } }
> >> +#include <mdspan>
> >> +
> >> +#include "padded_traits.h"
> >> +#include <cstdint>
> >> +
> >> +constexpr size_t dyn = std::dynamic_extent;
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_extens_representable_sta()
> >> + {
> >> + using E1 = std::extents<uint8_t, 8, 128>;
> >> + auto m = typename Layout<dyn>::mapping(E1{}); // { dg-error
> "required
> >> from" }
> >> + return true;
> >> + }
> >>
> +static_assert(test_from_extens_representable_sta<std::layout_left_padded>());
> >> // { dg-error "from here" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_extents_representable_padded_size()
> >> + {
> >> + using E1 = std::extents<uint8_t, 8, 128>;
> >> + using E2 = std::dextents<uint8_t, 2>;
> >> +
> >> + auto m = typename Layout<dyn>::mapping(E2{E1{}}); // { dg-error
> >> "expansion of" }
> >> + (void) m;
> >> + return true;
> >> + }
> >>
> +static_assert(test_from_extents_representable_padded_size<std::layout_left_padded>());
> >> // { dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_extents_representable_stride()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using E1 = typename Traits::extents_type<std::extents<uint8_t, dyn,
> >> 1>>;
> >> + auto m = typename Layout<128>::mapping(E1{129}); // { dg-error
> >> "expansion of" }
> >> + (void) m;
> >> + return true;
> >> + }
> >>
> +static_assert(test_from_extents_representable_stride<std::layout_left_padded>());
> >> // { dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_pad_representable_stride()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto exts = Traits::make_extents(std::dextents<uint8_t, 2>(129,
> 2));
> >> + auto m = typename Layout<dyn>::mapping(exts, 128); // { dg-error
> >> "expansion of" }
> >> + return true;
> >> + }
> >>
> +static_assert(test_from_pad_representable_stride<std::layout_left_padded>());
> >> // { dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_pad_representable_padded_size()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto exts = Traits::make_extents(std::dextents<uint8_t, 2>(64, 2));
> >> + auto m = typename Layout<dyn>::mapping(exts, 128); // { dg-error
> >> "expansion of" }
> >> + return true;
> >> + }
> >>
> +static_assert(test_from_pad_representable_padded_size<std::layout_left_padded>());
> >> // { dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_left()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using LayoutSame = typename Traits::layout_same;
> >> + auto exts = Traits::make_extents(std::extents<uint8_t, 6, dyn>{4});
> >> + auto ml = typename LayoutSame::mapping(exts);
> >> +
> >> + typename Layout<4>::mapping<decltype(exts)> m(ml); // { dg-error
> >> "expansion of" }
> >> + return true;
> >> + }
> >> +static_assert(test_from_left<std::layout_left_padded>()); // { dg-error
> >> "required from here" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_left_bad_runtime_stride()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto exts = Traits::make_extents(std::extents<uint8_t, dyn, dyn>{6,
> >> 4});
> >> + auto ml = typename Traits::layout_same::mapping(exts);
> >> +
> >> + typename Layout<4>::mapping<decltype(exts)> m(ml); // { dg-error
> >> "expansion of" }
> >> + (void) m;
> >> + return true;
> >> + }
> >>
> +static_assert(test_from_left_bad_runtime_stride<std::layout_left_padded>());
> >> // { dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_left_representable_extents()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto exts = Traits::make_extents(std::extents<uint16_t, dyn,
> dyn>{8,
> >> 128});
> >> + auto ml = typename Traits::layout_same::mapping(exts);
> >> +
> >> + typename Layout<8>::mapping<std::extents<uint8_t, dyn, dyn>> m(ml);
> >> // { dg-error "expansion of" }
> >> + return true;
> >> + }
> >>
> +static_assert(test_from_left_representable_extents<std::layout_left_padded>());
> >> // { dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout, size_t PaddingValue>
> >> + constexpr bool
> >> + test_pad_overflow()
> >> + {
> >> + auto exts = std::extents<uint8_t, dyn>{4};
> >> + auto n = size_t(1) << 9;
> >> + auto m = typename Layout<PaddingValue>::mapping(exts, n);
> >> + (void) m;
> >> + return true;
> >> + }
> >> +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" }
> >> +
> >> +template<template<size_t> typename Layout, size_t PaddingValue>
> >> + constexpr bool
> >> + test_from_pad_negative()
> >> + {
> >> + auto exts = std::extents(4);
> >> + auto m = typename Layout<PaddingValue>::mapping(exts, -1);
> >> + (void) m;
> >> + return true;
> >> + }
> >> +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" }
> >> +
> >> +template<template<size_t> typename Layout, size_t Pad>
> >> + constexpr bool
> >> + test_static_pad_same()
> >> + {
> >> + using Extents = std::extents<int, dyn>;
> >> + using Mapping = typename Layout<Pad>::mapping<Extents>;
> >> + auto exts = Extents{4};
> >> + auto m = Mapping(exts, Pad + 1); // { dg-error "expansion of"
> }
> >> + (void) m;
> >> + return true;
> >> + }
> >> +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" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_stride_wrong_stride0()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto e = Traits::make_extents(std::extents{3, 5});
> >> + auto s = Traits::make_expected(std::array<int, 2>{2, 7});
> >> + auto ms = std::layout_stride::mapping(e, s);
> >> + auto m = typename Layout<dyn>::mapping<decltype(e)>(ms); // {
> >> dg-error "expansion of" }
> >> + (void) m;
> >> + return true;
> >> + }
> >>
> +static_assert(test_from_stride_wrong_stride0<std::layout_left_padded>());
> >> // { dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_stride_wrong_stride1()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto e = Traits::make_extents(std::extents(3, 5));
> >> + auto s = Traits::make_expected(std::array<int, 2>{1, 3});
> >> + auto ms = std::layout_stride::mapping(e, s);
> >> + auto m = typename Layout<2>::mapping<decltype(e)>(ms); // {
> dg-error
> >> "expansion of" }
> >> + (void) m;
> >> + return true;
> >> + }
> >>
> +static_assert(test_from_stride_wrong_stride1<std::layout_left_padded>());
> >> // { dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_stride_wrong_stride2()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto e = Traits::make_extents(std::extents(3, 5, 7));
> >> + auto s = Traits::make_expected(std::array<int, 3>{1, 4, 21});
> >> + auto ms = std::layout_stride::mapping(e, s);
> >> + auto m = typename Layout<dyn>::mapping<decltype(e)>(ms); // here
> (not
> >> implemented)
> >> + (void) m;
> >> + return true;
> >> + }
> >>
> +static_assert(test_from_stride_wrong_stride2<std::layout_left_padded>());
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_stride_oversized()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto exts = Traits::make_extents(std::extents<uint16_t, dyn,
> dyn>{3,
> >> 6});
> >> + auto s = Traits::make_expected(std::array<uint16_t, 2>{1, 128});
> >> + auto ms = std::layout_stride::mapping(exts, s);
> >> +
> >> + using Mapping = typename
> Layout<dyn>::mapping<std::dextents<uint8_t,
> >> 2>>;
> >> + Mapping m(ms); // { dg-error "expansion of" }
> >> + (void) m;
> >> + return true;
> >> + }
> >> +static_assert(test_from_stride_oversized<std::layout_left_padded>());
> //
> >> { dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_samepad_dyn()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto e = Traits::make_extents(std::extents(3, 5));
> >> + auto mlp = typename Layout<dyn>::mapping(e);
> >> + auto m = typename Layout<2>::mapping<decltype(e)>(mlp); // {
> dg-error
> >> "expansion of" }
> >> + (void) m;
> >> + return true;
> >> + }
> >> +static_assert(test_from_samepad_dyn<std::layout_left_padded>()); // {
> >> dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_samepad_sta()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + auto e = Traits::make_extents(std::extents{3, 5});
> >> + auto mlp = typename Layout<3>::mapping(e);
> >> + auto m = typename Layout<2>::mapping<decltype(e)>(mlp); // {
> dg-error
> >> "expansion of" }
> >> + (void) m;
> >> + return true;
> >> + }
> >> +static_assert(test_from_samepad_sta<std::layout_left_padded>()); // {
> >> dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_from_samepad_oversized()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using E1 = typename Traits::extents_type<std::extents<uint16_t, 8,
> >> 128>>;
> >> + using E2 = typename Traits::extents_type<std::extents<uint8_t, dyn,
> >> dyn>>;
> >> + auto mlp = typename Layout<dyn>::mapping<E1>(E1{});
> >> + auto m = typename Layout<dyn>::mapping<E2>(mlp); // { dg-error
> >> "expansion of" }
> >> + (void) m;
> >> + return true;
> >> + }
> >> +static_assert(test_from_samepad_oversized<std::layout_left_padded>());
> //
> >> { dg-error "expansion of" }
> >> +
> >> +template<template<size_t> typename Layout, size_t RunId>
> >> + constexpr bool
> >> + test_to_same_not_exhaustive()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using E1 = typename Traits::extents_type<std::extents<int, 6, 5>>;
> >> + using E2 = typename Traits::extents_type<std::extents<int, dyn,
> 5>>;
> >> +
> >> + [[maybe_unused]] auto msta = typename Layout<7>::mapping(E1{});
> >> + if constexpr (RunId == 0)
> >> + {
> >> + auto m = typename Traits::layout_same::mapping<E1>(msta); // {
> >> dg-error "required from" }
> >> + (void) m;
> >> + }
> >> + if constexpr (RunId == 1)
> >> + {
> >> + auto m = typename Traits::layout_same::mapping<E2>(msta); // {
> >> dg-error "expansion of" }
> >> + (void) m;
> >> + }
> >> +
> >> + [[maybe_unused]] auto mdyn = typename
> Layout<dyn>::mapping(E2{E1{}},
> >> 7);
> >> + if constexpr (RunId == 2)
> >> + {
> >> + auto m = typename Traits::layout_same::mapping<E1>(mdyn); // {
> >> dg-error "expansion of" }
> >> + (void) m;
> >> + }
> >> + if constexpr (RunId == 3)
> >> + {
> >> + auto m = typename Traits::layout_same::mapping<E2>(mdyn); // {
> >> dg-error "expansion of" }
> >> + (void) m;
> >> + }
> >> + return true;
> >> + }
> >> +static_assert(test_to_same_not_exhaustive<std::layout_left_padded,
> 0>());
> >> // { dg-error "expansion of" }
> >> +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" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_statically_bad_padding_value1()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + constexpr auto N = std::numeric_limits<size_t>::max() - 1;
> >> + using Extents = typename Traits::extents_type<std::extents<size_t,
> N,
> >> 0>>;
> >> + typename Layout<10>::mapping<Extents> m; // { dg-error "required
> >> from" }
> >> + return true;
> >> + }
> >>
> +static_assert(test_statically_bad_padding_value1<std::layout_left_padded>());
> >> // { dg-error "required from" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_statically_bad_padding_value2()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using Extents = typename Traits::extents_type<std::extents<uint8_t,
> >> 255, 0>>;
> >> + typename Layout<2>::mapping<Extents> m; // { dg-error "required
> from"
> >> }
> >> + return true;
> >> + }
> >>
> +static_assert(test_statically_bad_padding_value2<std::layout_left_padded>());
> >> // { dg-error "required from" }
> >> +
> >> +template<template<size_t> typename Layout>
> >> + constexpr bool
> >> + test_statically_oversized()
> >> + {
> >> + using Traits =
> >> LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
> >> + using Extents = typename Traits::extents_type<std::extents<uint8_t,
> >> 127, 2>>;
> >> + typename Layout<2>::mapping<Extents> m; // { dg-error "required
> from"
> >> }
> >> + return true;
> >> + }
> >> +static_assert(test_statically_oversized<std::layout_left_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" }
> >> +// { dg-prune-output "called in a constant expression" }
> >> +// { dg-prune-output "no matching function" }
> >> +// { dg-prune-output "static assertion failed" }
> >> +// { dg-prune-output "__glibcxx_assert_fail()" }
> >> +// { dg-prune-output "must be compatible with other.stride" }
> >> +// { dg-prune-output "padding_value is dynamic_extent" }
> >> +// { dg-prune-output "_S_rank <= 1" }
> >> diff --git
> >> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h
> >> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h
> >> new file mode 100644
> >> index 00000000000..1f0169d7c02
> >> --- /dev/null
> >> +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h
> >> @@ -0,0 +1,63 @@
> >> +#ifndef TEST_MDSPAN_PADDED_TRAITS_H
> >> +#define TEST_MDSPAN_PADDED_TRAITS_H
> >> +
> >> +#if __glibcxx_padded_layouts
> >> +enum class PaddingSide
> >> +{
> >> + Left
> >> +};
> >> +
> >> +template<typename Layout>
> >> + constexpr static bool is_left_padded = false;
> >> +
> >> +template<size_t PaddingValue>
> >> + constexpr static bool
> >> is_left_padded<std::layout_left_padded<PaddingValue>> = true;
> >> +
> >> +struct DeducePaddingSide
> >> +{
> >> + template<template<size_t> typename Layout>
> >> + constexpr static PaddingSide
> >> + from_template()
> >> + { return PaddingSide::Left; }
> >> +
> >> + template<typename Layout>
> >> + constexpr static PaddingSide
> >> + from_typename()
> >> + { return PaddingSide::Left; }
> >> +};
> >> +
> >> +template<PaddingSide Side>
> >> + struct LayoutTraits;
> >> +
> >> +template<>
> >> + struct LayoutTraits<PaddingSide::Left>
> >> + {
> >> + using layout_same = std::layout_left;
> >> + using layout_other = std::layout_right;
> >> +
> >> + template<typename Extents>
> >> + using extents_type = Extents;
> >> +
> >> + template<typename Extents>
> >> + constexpr static extents_type<Extents>
> >> + make_extents(const Extents& exts)
> >> + { return exts; }
> >> +
> >> + template<typename T, size_t N>
> >> + constexpr static std::array<T, N>
> >> + make_expected(const std::array<T, N>& expected)
> >> + { return expected; }
> >> +
> >> + template<typename Mapping>
> >> + constexpr static auto
> >> + padded_stride(const Mapping& m)
> >> + { return m.stride(1); }
> >> +
> >> + template<typename Extents>
> >> + constexpr static auto
> >> + padded_extent(const Extents& exts)
> >> + { return exts.extent(0); }
> >> + };
> >> +
> >> +#endif
> >> +#endif
> >> --
> >> 2.50.1
> >>
> >>
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250926/5e558517/attachment-0001.htm>
More information about the Libstdc++
mailing list