+ };
+ }
+
+ 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