https://gcc.gnu.org/g:bfd41adc6178abb55d2a019f0d7e755ee097f548
commit r16-4288-gbfd41adc6178abb55d2a019f0d7e755ee097f548 Author: Luc Grosheintz <[email protected]> Date: Mon Sep 29 08:00:19 2025 +0200 libstdc++: Implement std::layout_right_padded [PR110352]. 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. Reviewed-by: Tomasz KamiĆski <[email protected]> Signed-off-by: Luc Grosheintz <[email protected]> Diff: --- 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 + .../23_containers/mdspan/layouts/padded_neg.cc | 28 +++ .../23_containers/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 7f14ca613f33..6714b19a8843 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<typename _RightPaddedMapping> + requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping> + && is_constructible_v<extents_type, + typename _RightPaddedMapping::extents_type> + constexpr + explicit(!is_convertible_v<typename _RightPaddedMapping::extents_type, + extents_type>) + mapping(const _RightPaddedMapping& __other) noexcept + : mapping(__other.extents(), __mdspan::__internal_ctor{}) + { + constexpr size_t __rank = extents_type::rank(); + constexpr size_t __ostride_sta = __mdspan::__get_static_stride< + _RightPaddedMapping>(); + + if constexpr (__rank > 1) + { + 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( + 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 { @@ -1825,6 +1909,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) + : _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; } + + 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 // __glibcxx_padded_layouts template<typename _ElementType> diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in index f10bab59e2ce..c1b4e4c88b76 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 8cba8094abcc..27065a0dfc6e 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 05188432f144..8840d07879cc 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 10ce622523d7..d1486e4e11c8 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 d43b84ef875b..cf4821a3c74f 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 f0dbfe9d9c62..a758f74287f2 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 9171d8c1ce1d..788ae82fcc49 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
