Ah, sorry I got confused in the review suggestions, and latter when checking the code. What I meant is:
Because the incoming strided_layout is required to be unique, that implies that for each of strides are greater or equal to the extents. As a consequence, other.required_span_size() is always greater than equal to size of index_space, so we can have static assert like: static_assert(__mdspan::__representable_size<_OExtents, index_type>, "other.required_span_size() must be representable as index_type"); In here: if constexpr (cmp_greater( numeric_limits<typename _StridedMapping::index_type>::max(), numeric_limits<index_type>::max())) { static_assert(__mdspan::__representable_size<_OExtents, index_type>, "other.required_span_size() must be representable as index_type") __glibcxx_assert(!cmp_less(numeric_limits<index_type>::max(), __other.required_span_size())); } On Wed, Jun 4, 2025 at 1:09 PM Luc Grosheintz <luc.groshei...@gmail.com> wrote: > > > On 6/3/25 15:24, Tomasz Kaminski wrote: > > On Fri, May 30, 2025 at 6:44 PM Luc Grosheintz <luc.groshei...@gmail.com > > > > wrote: > > > >> Implements the tests for layout_stride and for the features of the other > >> two layouts that depend on layout_stride. > >> > >> libstdc++-v3/ChangeLog: > >> > >> * testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc: > Add > >> tests for layout_stride. > >> * testsuite/23_containers/mdspan/layouts/ctors.cc: Add test for > >> layout_stride and the interaction with other layouts. > >> * testsuite/23_containers/mdspan/layouts/mapping.cc: Ditto. > >> * testsuite/23_containers/mdspan/layouts/stride.cc: New test. > >> > >> Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> > >> --- > >> > > LTGM. Only one comment regarding the tests that we could add. > > > >> .../mdspan/layouts/class_mandate_neg.cc | 3 + > >> .../23_containers/mdspan/layouts/ctors.cc | 99 ++++ > >> .../23_containers/mdspan/layouts/empty.cc | 1 + > >> .../23_containers/mdspan/layouts/mapping.cc | 75 ++- > >> .../23_containers/mdspan/layouts/stride.cc | 526 ++++++++++++++++++ > >> 5 files changed, 703 insertions(+), 1 deletion(-) > >> create mode 100644 > >> libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc > >> > >> 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 6469fa601e9..6862ed0c0ae 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 > >> @@ -31,9 +31,12 @@ template<size_t Count, typename Layout, typename > >> OLayout> > >> > >> A<std::layout_left> a_left; // { dg-error > "required > >> from" } > >> A<std::layout_right> a_right; // { dg-error > "required > >> from" } > >> +A<std::layout_stride> a_stride; // { dg-error > "required > >> from" } > >> > >> B<1, std::layout_left, std::layout_left> bll; // { dg-error > "required > >> here" } > >> +B<2, std::layout_left, std::layout_stride> bls; // { dg-error > "required > >> here" } > >> > > With the message that we added to static assert to layout_stride > > constructor: > > >> "other.required_span_size() must be representable as index_type" > > I believe you could add here: > > B<2, std::layout_stride, std::layout_left> > > And similarly for layout_right. > > I've tried (even before) and always failed miserably. Only good news > is that the final > > // { dg-prune-output "must be representable as index_type" } > > isn't superfluous. I seem like the only string I can match against > is the one associated with that line of code, in this case that's > > mdspan:773: error: static assertion failed: The size of OtherExtents > must be representable as index_type > [ ... ] > class_mandate_neg.cc:40: note: synthesized method 'constexpr B<4, > std::layout_right, std::layout_stride>::B()' first required here > > I unsure why you're saying that we added the message: > > "other.required_span_size() must be representable as index_type" > > to a static_assert, we added it to a __glibcxx_assert. The tests here > are designed to trigger different assertions. > > "A" triggers: > > template<typename _Extents> > class layout_*::mapping > { > public: > // ... > > static_assert(__mdspan::__representable_size<extents_type, > index_type>, > "The size of extents_type must be representable as index_type"); > > > "B" triggers: > > template<typename _OExtents> > constexpr explicit > mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept > : _M_extents(__oexts) > { > static_assert(__mdspan::__representable_size<_OExtents, index_type>, > "The size of OtherExtents must be representable as index_type"); > > We don't have tests that make __glibcxx_assert's fail. We could probably > do it with constexpr variables with "dynamic" extents. > > > > >> > >> B<3, std::layout_right, std::layout_right> brr; // { dg-error > "required > >> here" } > >> +B<4, std::layout_right, std::layout_stride> brs; // { dg-error > "required > >> here" } > >> > >> // { dg-prune-output "must be representable as index_type" } > >> diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc > >> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc > >> index b0e03161874..695e887ca87 100644 > >> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc > >> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc > >> @@ -323,6 +323,104 @@ namespace from_left_or_right > >> } > >> } > >> > >> +// ctor: mapping(layout_stride::mapping<OExtents>) > >> +namespace from_stride > >> +{ > >> + template<typename Mapping> > >> + constexpr auto > >> + strides(Mapping m) > >> + { > >> + constexpr auto rank = Mapping::extents_type::rank(); > >> + std::array<typename Mapping::index_type, rank> s; > >> + > >> + if constexpr (rank > 0) > >> + for(size_t i = 0; i < rank; ++i) > >> + s[i] = m.stride(i); > >> + return s; > >> + } > >> + > >> + template<typename Layout, typename Extents, typename OExtents> > >> + constexpr void > >> + verify_convertible(OExtents oexts) > >> + { > >> + using Mapping = typename Layout::mapping<Extents>; > >> + using OMapping = std::layout_stride::mapping<OExtents>; > >> + > >> + constexpr auto other = OMapping(oexts, > >> strides(Mapping(Extents(oexts)))); > >> + if constexpr (std::is_same_v<Layout, std::layout_right>) > >> + ::verify_nothrow_convertible<Mapping>(other); > >> + else > >> + ::verify_convertible<Mapping>(other); > >> + } > >> + > >> + template<typename Layout, typename Extents, typename OExtents> > >> + constexpr void > >> + verify_constructible(OExtents oexts) > >> + { > >> + using Mapping = typename Layout::mapping<Extents>; > >> + using OMapping = std::layout_stride::mapping<OExtents>; > >> + > >> + constexpr auto other = OMapping(oexts, > >> strides(Mapping(Extents(oexts)))); > >> + if constexpr (std::is_same_v<Layout, std::layout_right>) > >> + ::verify_nothrow_constructible<Mapping>(other); > >> + else > >> + ::verify_constructible<Mapping>(other); > >> + } > >> + > >> + template<typename Layout> > >> + constexpr bool > >> + test_ctor() > >> + { > >> + assert_not_constructible< > >> + typename Layout::mapping<std::extents<int>>, > >> + std::layout_stride::mapping<std::extents<int, 1>>>(); > >> + > >> + assert_not_constructible< > >> + typename Layout::mapping<std::extents<int, 1>>, > >> + std::layout_stride::mapping<std::extents<int>>>(); > >> + > >> + assert_not_constructible< > >> + typename Layout::mapping<std::extents<int, 2>>, > >> + std::layout_stride::mapping<std::extents<int, 1>>>(); > >> + > >> + verify_convertible<Layout, > std::extents<int>>(std::extents<int>{}); > >> + > >> + verify_convertible<Layout, std::extents<unsigned int>>( > >> + std::extents<int>{}); > >> + > >> + // Rank == 0 doesn't check IndexType for convertibility. > >> + verify_convertible<Layout, std::extents<int>>( > >> + std::extents<unsigned int>{}); > >> + > >> + verify_constructible<Layout, std::extents<int, 3>>( > >> + std::extents<int, 3>{}); > >> + > >> + verify_constructible<Layout, std::extents<unsigned int, 3>>( > >> + std::extents<int, 3>{}); > >> + > >> + verify_constructible<Layout, std::extents<int, 3>>( > >> + std::extents<unsigned int, 3>{}); > >> + > >> + verify_constructible<Layout, std::extents<int, 3, 5>>( > >> + std::extents<int, 3, 5>{}); > >> + > >> + verify_constructible<Layout, std::extents<unsigned int, 3, 5>>( > >> + std::extents<int, 3, 5>{}); > >> + > >> + verify_constructible<Layout, std::extents<int, 3, 5>>( > >> + std::extents<unsigned int, 3, 5>{}); > >> + return true; > >> + } > >> + > >> + template<typename Layout> > >> + constexpr void > >> + test_all() > >> + { > >> + test_ctor<Layout>(); > >> + static_assert(test_ctor<Layout>()); > >> + } > >> +} > >> + > >> template<typename Layout> > >> constexpr void > >> test_all() > >> @@ -330,6 +428,7 @@ template<typename Layout> > >> default_ctor::test_all<Layout>(); > >> from_extents::test_all<Layout>(); > >> from_same_layout::test_all<Layout>(); > >> + from_stride::test_all<Layout>(); > >> } > >> > >> int > >> diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc > >> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc > >> index dc2a95ebbe6..d550c0a8e84 100644 > >> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc > >> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc > >> @@ -64,5 +64,6 @@ main() > >> { > >> static_assert(test_all<std::layout_left>()); > >> static_assert(test_all<std::layout_right>()); > >> + static_assert(test_all<std::layout_stride>()); > >> 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 4dc0db66865..963c804a369 100644 > >> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc > >> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc > >> @@ -12,6 +12,7 @@ template<typename Layout, typename Extents> > >> { > >> using M = typename Layout::mapping<Extents>; > >> static_assert(std::__mdspan::__is_extents<typename > M::extents_type>); > >> + static_assert(std::__mdspan::__mapping_alike<M>); > >> static_assert(std::copyable<M>); > >> static_assert(std::is_nothrow_move_constructible_v<M>); > >> static_assert(std::is_nothrow_move_assignable_v<M>); > >> @@ -30,6 +31,8 @@ template<typename Layout, typename Extents> > >> > >> static_assert(M::is_always_unique() && M::is_unique()); > >> static_assert(M::is_always_strided() && M::is_strided()); > >> + if constexpr (!std::is_same_v<Layout, std::layout_stride>) > >> + static_assert(M::is_always_exhaustive() && M::is_exhaustive()); > >> return true; > >> } > >> > >> @@ -105,6 +108,39 @@ template<typename Layout> > >> { return exts; } > >> }; > >> > >> +template<> > >> + struct MappingFactory<std::layout_stride> > >> + { > >> + template<typename Extents> > >> + static constexpr std::layout_stride::mapping<Extents> > >> + create(Extents exts) > >> + { > >> + if constexpr (Extents::rank() == 0) > >> + { > >> + auto strides = std::array<size_t, 0>{}; > >> + return std::layout_stride::mapping(exts, strides); > >> + } > >> + else if constexpr (Extents::rank() == 1) > >> + { > >> + auto strides = std::array<size_t, 1>{2}; > >> + return std::layout_stride::mapping(exts, strides); > >> + } > >> + else if constexpr (Extents::rank() == 2) > >> + { > >> + size_t m = exts.extent(1); > >> + auto strides = std::array<size_t, 2>{3*m, 2}; > >> + return std::layout_stride::mapping(exts, strides); > >> + } > >> + else if constexpr (Extents::rank() == 3) > >> + { > >> + size_t n = exts.extent(0); > >> + size_t m = exts.extent(1); > >> + auto strides = std::array<size_t, 3>{3*m, 2, 11*m*n}; > >> + return std::layout_stride::mapping(exts, strides); > >> + } > >> + } > >> + }; > >> + > >> template<typename Layout> > >> constexpr void > >> test_linear_index_3d() > >> @@ -280,6 +316,16 @@ template<typename Layout> > >> VERIFY(m.stride(0) == 1); > >> } > >> > >> +template<> > >> + constexpr void > >> + test_stride_1d<std::layout_stride>() > >> + { > >> + std::array<int, 1> strides{13}; > >> + std::layout_stride::mapping m(std::extents<int, 3>{}, strides); > >> + VERIFY(m.stride(0) == strides[0]); > >> + VERIFY(m.strides() == strides); > >> + } > >> + > >> template<typename Layout> > >> constexpr void > >> test_stride_2d(); > >> @@ -302,6 +348,17 @@ template<> > >> VERIFY(m.stride(1) == 1); > >> } > >> > >> +template<> > >> + constexpr void > >> + test_stride_2d<std::layout_stride>() > >> + { > >> + std::array<int, 2> strides{13, 2}; > >> + std::layout_stride::mapping m(std::extents<int, 3, 5>{}, strides); > >> + VERIFY(m.stride(0) == strides[0]); > >> + VERIFY(m.stride(1) == strides[1]); > >> + VERIFY(m.strides() == strides); > >> + } > >> + > >> template<typename Layout> > >> constexpr void > >> test_stride_3d(); > >> @@ -326,6 +383,19 @@ template<> > >> VERIFY(m.stride(2) == 1); > >> } > >> > >> +template<> > >> + constexpr void > >> + test_stride_3d<std::layout_stride>() > >> + { > >> + std::dextents<int, 3> exts(3, 5, 7); > >> + std::array<int, 3> strides{11, 2, 41}; > >> + std::layout_stride::mapping<std::dextents<int, 3>> m(exts, > strides); > >> + VERIFY(m.stride(0) == strides[0]); > >> + VERIFY(m.stride(1) == strides[1]); > >> + VERIFY(m.stride(2) == strides[2]); > >> + VERIFY(m.strides() == strides); > >> + } > >> + > >> template<typename Layout> > >> constexpr bool > >> test_stride_all() > >> @@ -347,7 +417,7 @@ template<typename Layout> > >> test_has_stride_0d() > >> { > >> using Mapping = typename Layout::mapping<std::extents<int>>; > >> - constexpr bool expected = false; > >> + constexpr bool expected = std::is_same_v<Layout, > std::layout_stride>; > >> static_assert(has_stride<Mapping> == expected); > >> } > >> > >> @@ -488,8 +558,11 @@ main() > >> { > >> test_all<std::layout_left>(); > >> test_all<std::layout_right>(); > >> + test_all<std::layout_stride>(); > >> > >> 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>(); > >> test_has_op_eq_peculiar(); > >> return 0; > >> } > >> diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc > >> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc > >> new file mode 100644 > >> index 00000000000..c8af5c61254 > >> --- /dev/null > >> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc > >> @@ -0,0 +1,526 @@ > >> +// { dg-do run { target c++23 } } > >> +#include <mdspan> > >> + > >> +#include <testsuite_hooks.h> > >> + > >> +constexpr size_t dyn = std::dynamic_extent; > >> + > >> +template<typename MappingStride> > >> + constexpr void > >> + test_ctor_default_stride() > >> + { > >> + using Extents = typename MappingStride::extents_type; > >> + MappingStride actual; > >> + typename std::layout_right::mapping<Extents> expected; > >> + > >> + constexpr auto rank = MappingStride::extents_type::rank(); > >> + if constexpr (rank > 0) > >> + for(size_t i = 0; i < rank; ++i) > >> + VERIFY(actual.stride(i) == expected.stride(i)); > >> + } > >> + > >> +constexpr bool > >> +test_ctor_default_stride_all() > >> +{ > >> + test_ctor_default_stride< > >> + std::layout_stride::mapping<std::extents<int, 3>>>(); > >> + > >> + test_ctor_default_stride< > >> + std::layout_stride::mapping<std::extents<int, 3, 5, 7>>>(); > >> + > >> + test_ctor_default_stride< > >> + std::layout_stride::mapping<std::dextents<int, 3>>>(); > >> + > >> + test_ctor_default_stride< > >> + std::layout_stride::mapping<std::extents<int, 0, 5, 7>>>(); > >> + > >> + test_ctor_default_stride< > >> + std::layout_stride::mapping<std::extents<int, 3, dyn, dyn>>>(); > >> + > >> + test_ctor_default_stride< > >> + std::layout_stride::mapping<std::extents<int, dyn, dyn, 3>>>(); > >> + return true; > >> +} > >> + > >> +struct IntLikeA > >> +{ > >> + operator int() > >> + { return 0; } > >> +}; > >> + > >> +struct IntLikeB > >> +{ > >> + operator int() noexcept > >> + { return 0; } > >> +}; > >> + > >> +struct NotIntLike > >> +{ }; > >> + > >> +template<typename E, typename E_arg, typename T, size_t N, bool > Expected> > >> +constexpr void > >> +test_stride_constructible() > >> +{ > >> + static_assert(std::is_nothrow_constructible_v< > >> + std::layout_stride::mapping<E>, E_arg, std::span<T, N>> == > >> Expected); > >> + static_assert(std::is_nothrow_constructible_v< > >> + std::layout_stride::mapping<E>, E_arg, std::array<T, N>> == > >> Expected); > >> + > static_assert(!std::is_constructible_v<std::layout_stride::mapping<E>, > >> + E_arg>); > >> +} > >> + > >> +constexpr void > >> +test_stride_constructible_all() > >> +{ > >> + using E0 = std::extents<int>; > >> + using E1 = std::extents<int, 2>; > >> + using E2 = std::extents<int, dyn>; > >> + > >> + test_stride_constructible<E0, E0, int, 0, true>(); > >> + test_stride_constructible<E0, E0, IntLikeA, 0, false>(); > >> + test_stride_constructible<E0, E0, IntLikeB, 0, true>(); > >> + test_stride_constructible<E0, E0, NotIntLike, 0, false>(); > >> + test_stride_constructible<E1, E1, int, 1, true>(); > >> + test_stride_constructible<E2, E1, int, 1, true>(); > >> + test_stride_constructible<E1, E1, int, 2, false>(); > >> + test_stride_constructible<E1, E0, int, 1, false>(); > >> +} > >> + > >> +template<typename Extents, typename Shape> > >> + constexpr void > >> + test_ctor_shape_strides(Extents exts, Shape strides) > >> + { > >> + using M = std::layout_stride::mapping<Extents>; > >> + M m(exts, strides); > >> + > >> + if constexpr (Extents::rank() > 0) > >> + for(size_t i = 0; i < exts.rank(); ++i) > >> + { > >> + VERIFY(m.stride(i) == strides[i]); > >> + VERIFY(m.extents().extent(i) == exts.extent(i)); > >> + } > >> + } > >> + > >> +constexpr bool > >> +test_ctor_shape_stride_all() > >> +{ > >> + test_ctor_shape_strides(std::extents<int>{}, std::array<int, 0>{}); > >> + test_ctor_shape_strides(std::extents<int, 2>{}, std::array<int, > 1>{3}); > >> + test_ctor_shape_strides(std::extents<int, 2, 4, 6>{}, > >> + std::array<int, 3>{20, 5, 45}); > >> + return true; > >> +} > >> + > >> +template<typename Extents, std::array<bool, 2> Strided, > >> + std::array<bool, 2> Unique, std::array<bool, 2> Exhautive, > >> + typename Extents::index_type Offset = 0> > >> + struct MappingLike > >> + { > >> + using extents_type = Extents; > >> + using index_type = typename Extents::index_type; > >> + > >> + constexpr > >> + MappingLike(extents_type extents, > >> + std::array<index_type, Extents::rank()> strides) > >> + : _extents(extents), _strides(strides) > >> + { } > >> + > >> + static constexpr bool > >> + is_always_strided() requires (Strided[0]) > >> + { return Strided[1]; } > >> + > >> + static constexpr bool > >> + is_always_unique() requires (Unique[0]) > >> + { return Unique[1]; } > >> + > >> + static constexpr bool > >> + is_always_exhaustive() requires (Exhautive[0]) > >> + { return Exhautive[1]; } > >> + > >> + constexpr Extents > >> + extents() const { return _extents; } > >> + > >> + constexpr index_type > >> + stride(size_t i) const { return _strides[i]; } > >> + > >> + template<typename... Indices> > >> + constexpr index_type > >> + operator()(Indices... indices) const > >> + { > >> + if (empty()) > >> + VERIFY(false); > >> + > >> + std::array<index_type, Extents::rank()> ind_arr{indices...}; > >> + index_type ret = Offset; > >> + for(size_t i = 0; i < Extents::rank(); ++i) > >> + ret += ind_arr[i]*_strides[i]; > >> + return ret; > >> + } > >> + > >> + private: > >> + constexpr bool > >> + empty() const > >> + { > >> + for (size_t i = 0; i < extents_type::rank(); ++i) > >> + if (_extents.extent(i) == 0) > >> + return true; > >> + return false; > >> + } > >> + > >> + Extents _extents; > >> + std::array<index_type, Extents::rank()> _strides; > >> + }; > >> + > >> + > >> +template<size_t Rank> > >> +struct ExtentLike > >> +{ > >> + using index_type = int; > >> + > >> + static constexpr size_t > >> + rank() { return Rank; } > >> +}; > >> + > >> + > >> +template<typename E1> > >> +constexpr void > >> +test_mapping_like_constructible() > >> +{ > >> + using M = std::layout_stride::mapping<E1>; > >> + using E2 = std::dextents<typename E1::index_type, E1::rank()>; > >> + using E3 = std::dextents<typename E1::index_type, E1::rank() + 1>; > >> + using E4 = ExtentLike<E1::rank()>; > >> + > >> + constexpr auto TT = std::array{true, true}; > >> + constexpr auto FT = std::array{false, true}; > >> + constexpr auto TF = std::array{true, false}; > >> + > >> + static_assert(std::is_constructible_v<M, MappingLike<E1, TT, TT, > TT>>); > >> + static_assert(std::is_constructible_v<M, MappingLike<E2, TT, TT, > TT>>); > >> + static_assert(!std::is_constructible_v<M, MappingLike<E3, TT, TT, > TT>>); > >> + static_assert(!std::is_constructible_v<M, MappingLike<E1, FT, TT, > TT>>); > >> + static_assert(!std::is_constructible_v<M, MappingLike<E1, TF, TT, > TT>>); > >> + static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, FT, > TT>>); > >> + static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, TF, > TT>>); > >> + static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, TT, > FT>>); > >> + static_assert(std::is_constructible_v<M, MappingLike<E1, TT, TT, > TF>>); > >> + static_assert(!std::is_constructible_v<M, MappingLike<E4, TT, TT, > TF>>); > >> + static_assert(!std::is_constructible_v<M, MappingLike<E4, TT, TT, > TT>>); > >> +} > >> + > >> +constexpr void > >> +test_mapping_like_constructible_all() > >> +{ > >> + test_mapping_like_constructible<std::extents<int>>(); > >> + test_mapping_like_constructible<std::extents<int, 2>>(); > >> + test_mapping_like_constructible<std::extents<int, 2, 3>>(); > >> +} > >> + > >> +template<typename E1, typename E2> > >> +constexpr void > >> +test_mapping_like_convertible() > >> +{ > >> + using M1 = std::layout_stride::mapping<E1>; > >> + using M2 = std::layout_stride::mapping<E2>; > >> + constexpr auto TT = std::array{true, true}; > >> + > >> + static_assert(!std::is_convertible_v<MappingLike<E1, TT, TT, TT>, > M1>); > >> + static_assert(!std::is_convertible_v<MappingLike<E2, TT, TT, TT>, > M1>); > >> + static_assert(!std::is_convertible_v<MappingLike<E1, TT, TT, TT>, > M2>); > >> + > >> + static_assert(std::is_convertible_v<std::layout_stride::mapping<E2>, > >> M1>); > >> + static_assert(std::is_convertible_v<std::layout_left::mapping<E2>, > M1>); > >> + static_assert(std::is_convertible_v<std::layout_right::mapping<E2>, > >> M1>); > >> + > >> + static_assert(!std::is_convertible_v<std::layout_stride::mapping<E1>, > >> M2>); > >> + static_assert(!std::is_convertible_v<std::layout_left::mapping<E1>, > >> M2>); > >> + static_assert(!std::is_convertible_v<std::layout_right::mapping<E1>, > >> M2>); > >> +} > >> + > >> +constexpr void > >> +test_mapping_like_convertible_all() > >> +{ > >> + test_mapping_like_convertible<std::extents<unsigned int>, > >> + std::extents<int>>(); > >> + test_mapping_like_convertible<std::extents<unsigned int, 2>, > >> + std::extents<int, 2>>(); > >> + test_mapping_like_convertible<std::extents<int, dyn, 3>, > >> + std::extents<int, 2, 3>>(); > >> +} > >> + > >> +template<typename Extents> > >> +constexpr void > >> +test_ctor_stride_like(Extents exts, std::array<int, Extents::rank()> > >> strides) > >> +{ > >> + auto other_right = std::layout_right::mapping(exts); > >> + auto other_left = std::layout_left::mapping(exts); > >> + auto other_stride = std::layout_stride::mapping(exts, strides); > >> + > >> + VERIFY(std::layout_stride::mapping<Extents>(other_right) == > >> other_right); > >> + VERIFY(std::layout_stride::mapping<Extents>(other_left) == > other_left); > >> + VERIFY(std::layout_stride::mapping<Extents>(other_stride) == > >> other_stride); > >> +} > >> + > >> +constexpr void > >> +test_ctor_stride_like_all() > >> +{ > >> + using E1 = std::extents<int>; > >> + auto s1 = std::array<int, 0>{}; > >> + test_ctor_stride_like(E1{}, s1); > >> + > >> + using E2 = std::extents<int, 3>; > >> + auto s2 = std::array<int, 1>{2}; > >> + test_ctor_stride_like(E2{}, s2); > >> + > >> + using E3 = std::extents<int, 3, 5, 7>; > >> + auto s3 = std::array<int, 3>{5, 1, 15}; > >> + test_ctor_stride_like(E3{}, s3); > >> +} > >> + > >> +constexpr bool > >> +test_ctor_strides_all() > >> +{ > >> + test_ctor_default_stride_all(); > >> + test_ctor_shape_stride_all(); > >> + test_ctor_stride_like_all(); > >> + return true; > >> +} > >> + > >> +// Check is_exhaustive. > >> +template<typename Extents, typename Strides> > >> + constexpr void > >> + test_is_exhaustive(Extents extents, Strides strides, bool expected) > >> + { > >> + std::layout_stride::mapping<Extents> m(extents, strides); > >> + VERIFY(m.is_exhaustive() == expected); > >> + > >> + bool always_exhaustive = extents.rank() == 0 || > >> m.required_span_size() == 0; > >> + VERIFY(m.is_always_exhaustive() == always_exhaustive); > >> + } > >> + > >> +constexpr void > >> +test_is_exhaustive_zero_1d() > >> +{ > >> + std::extents<int, 0> extents; > >> + test_is_exhaustive(extents, std::array{1}, true); > >> + test_is_exhaustive(extents, std::array{2}, true); > >> +} > >> + > >> +constexpr void > >> +test_is_exhaustive_zero_3d() > >> +{ > >> + std::extents<int, 3, 0, 7> extents; > >> + > >> + test_is_exhaustive(extents, std::array{1, 1, 1}, true); > >> + test_is_exhaustive(extents, std::array{1, 2*21, 2*3}, true); > >> + test_is_exhaustive(extents, std::array{7, 2*21, 1}, true); > >> + test_is_exhaustive(extents, std::array{1, 21, 3}, true); > >> + test_is_exhaustive(extents, std::array{7, 21, 1}, true); > >> +} > >> + > >> +constexpr void > >> +test_is_exhaustive_0d() > >> +{ > >> + std::extents<int> extents; > >> + test_is_exhaustive(extents, std::array<int, 0>{}, true); > >> +} > >> + > >> +constexpr void > >> +test_is_exhaustive_1d() > >> +{ > >> + std::extents<int, 3> extents; > >> + test_is_exhaustive(extents, std::array{1}, true); > >> + test_is_exhaustive(extents, std::array{3}, false); > >> +} > >> + > >> + > >> +constexpr void > >> +test_is_exhaustive_3d() > >> +{ > >> + std::extents<int, 3, dyn, 7> extents(5); > >> + > >> + test_is_exhaustive(extents, std::array{1, 3, 3*5}, true); > >> + test_is_exhaustive(extents, std::array{5*7, 1, 5}, true); > >> + test_is_exhaustive(extents, std::array{7, 3*7, 1}, true); > >> + > >> + test_is_exhaustive(extents, std::array{1, 3, 2*3*5}, false); > >> + test_is_exhaustive(extents, std::array{2*5*7, 1, 2*5}, false); > >> + test_is_exhaustive(extents, std::array{2*7, 2*3*7, 2}, false); > >> +} > >> + > >> +constexpr void > >> +test_is_exhaustive_ones() > >> +{ > >> + std::extents<int, 1, 1, 3, 1> extents; > >> + test_is_exhaustive(extents, std::array{1, 1, 1, 1}, true); > >> + test_is_exhaustive(extents, std::array{1, 1, 1, 3}, true); > >> + test_is_exhaustive(extents, std::array{3, 3, 1, 3}, true); > >> + test_is_exhaustive(extents, std::array{3, 1, 1, 3}, true); > >> +} > >> + > >> +constexpr bool > >> +test_is_exhaustive_all() > >> +{ > >> + test_is_exhaustive_zero_1d(); > >> + test_is_exhaustive_zero_3d(); > >> + test_is_exhaustive_ones(); > >> + test_is_exhaustive_0d(); > >> + test_is_exhaustive_1d(); > >> + test_is_exhaustive_3d(); > >> + return true; > >> +} > >> + > >> +template<typename Extents, int Offset> > >> + using OffsetMapping = MappingLike<Extents, {true, true}, {true, > true}, > >> + {true, false}, Offset>; > >> + > >> +template<typename Extents> > >> + constexpr void > >> + test_eq(Extents exts, > >> + std::array<typename Extents::index_type, Extents::rank()> > >> left_strides, > >> + std::array<typename Extents::index_type, Extents::rank()> > >> right_strides, > >> + std::array<typename Extents::index_type, Extents::rank()> > >> padded_strides) > >> + { > >> + using DExtents = std::dextents<int, Extents::rank()>; > >> + > >> + std::layout_left::mapping<Extents> ml; > >> + std::layout_right::mapping<DExtents> mr(exts); > >> + > >> + std::layout_stride::mapping<Extents> msd; > >> + std::layout_stride::mapping<Extents> msl(exts, left_strides); > >> + std::layout_stride::mapping<Extents> msr(exts, right_strides); > >> + std::layout_stride::mapping<Extents> msp(exts, padded_strides); > >> + > >> + OffsetMapping<Extents, 0> mor{exts, right_strides}; > >> + OffsetMapping<Extents, 0> mol{exts, left_strides}; > >> + OffsetMapping<Extents, 0> mop{exts, padded_strides}; > >> + OffsetMapping<Extents, 1> moo{exts, right_strides}; > >> + > >> + VERIFY(msd == mr); > >> + VERIFY(msd == mor); > >> + VERIFY(msd != msp); > >> + VERIFY(msd != mop); > >> + > >> + VERIFY(msl == ml); > >> + VERIFY(msl == mol); > >> + VERIFY(msd != msp); > >> + VERIFY(msl != mop); > >> + > >> + VERIFY(msp == mop); > >> + VERIFY(msp != ml); > >> + VERIFY(msp != mr); > >> + > >> + VERIFY(msd != moo); > >> + } > >> + > >> +constexpr void > >> +test_eq_0d() > >> +{ > >> + using Extents = std::extents<int>; > >> + Extents exts; > >> + std::layout_left::mapping<Extents> ml; > >> + std::layout_right::mapping<Extents> mr; > >> + std::layout_stride::mapping<Extents> ms; > >> + OffsetMapping<Extents, 0> mor{exts, {}}; > >> + OffsetMapping<Extents, 1> moo{exts, {}}; > >> + > >> + VERIFY(ms == ml); > >> + VERIFY(ms == mr); > >> + VERIFY(ms == mor); > >> + VERIFY(ms != moo); > >> +} > >> + > >> +constexpr void > >> +test_eq_1d() > >> +{ > >> + using Extents = std::extents<int, 2>; > >> + auto exhaustive_strides = std::array{1}; > >> + auto padded_strides = std::array{2}; > >> + > >> + test_eq(Extents{}, exhaustive_strides, exhaustive_strides, > >> padded_strides); > >> +} > >> + > >> +constexpr void > >> +test_eq_2d() > >> +{ > >> + using Extents = std::extents<int, 1, 2>; > >> + auto left_strides = std::array{1, 1}; > >> + auto right_strides = std::array{2, 1}; > >> + auto padded_strides = std::array{2, 8}; > >> + > >> + test_eq(Extents{}, left_strides, right_strides, padded_strides); > >> +} > >> + > >> +constexpr void > >> +test_eq_zero() > >> +{ > >> + using Extents = std::extents<int, 0, 2>; > >> + using Mapping = std::layout_stride::mapping<Extents>; > >> + > >> + Extents exts; > >> + std::array<int, 2> sl{1, 5}; > >> + std::array<int, 2> sr{5, 1}; > >> + > >> + Mapping m1(exts, sl); > >> + Mapping m2(exts, sl); > >> + Mapping m3(exts, sr); > >> + OffsetMapping<Extents, 0> m4(exts, sl); > >> + > >> + VERIFY(m1 == m2); > >> + VERIFY(m1 != m3); > >> + VERIFY(m1 == m4); > >> + > >> +} > >> + > >> +constexpr bool > >> +test_eq_all() > >> +{ > >> + test_eq_0d(); > >> + test_eq_1d(); > >> + test_eq_2d(); > >> + test_eq_zero(); > >> + return true; > >> +} > >> + > >> +template<typename M1, typename M2> > >> + concept has_op_eq = requires (M1 m1, M2 m2) > >> + { > >> + { m1 == m2 } -> std::same_as<bool>; > >> + { m2 == m1 } -> std::same_as<bool>; > >> + { m1 != m2 } -> std::same_as<bool>; > >> + { m2 != m1 } -> std::same_as<bool>; > >> + }; > >> + > >> +constexpr void > >> +test_has_op_eq() > >> +{ > >> + using E1 = std::extents<int>; > >> + using E2 = std::extents<int, 2>; > >> + using E3 = std::extents<int, 1, 2>; > >> + constexpr auto FT = std::array{false, true}; > >> + > >> + static_assert(!has_op_eq< > >> + std::layout_stride::mapping<E1>, MappingLike<E1, FT, FT, FT>>); > >> + > >> + static_assert(!has_op_eq< > >> + std::layout_stride::mapping<E2>, MappingLike<E2, FT, FT, FT>>); > >> + > >> + static_assert(!has_op_eq< > >> + std::layout_stride::mapping<E3>, MappingLike<E3, FT, FT, FT>>); > >> +} > >> + > >> +int > >> +main() > >> +{ > >> + test_ctor_strides_all(); > >> + static_assert(test_ctor_strides_all()); > >> + test_mapping_like_convertible_all(); > >> + test_mapping_like_constructible_all(); > >> + test_stride_constructible_all(); > >> + test_is_exhaustive_all(); > >> + static_assert(test_is_exhaustive_all()); > >> + test_eq_all(); > >> + static_assert(test_eq_all()); > >> + test_has_op_eq(); > >> + return 0; > >> +} > >> -- > >> 2.49.0 > >> > >> > > > >