On Sun, May 18, 2025 at 10:12 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> > --- > You do not seem to be testing strides method. > .../mdspan/layouts/class_mandate_neg.cc | 19 + > .../23_containers/mdspan/layouts/ctors.cc | 99 ++++ > .../23_containers/mdspan/layouts/mapping.cc | 72 ++- > .../23_containers/mdspan/layouts/stride.cc | 494 ++++++++++++++++++ > 4 files changed, 683 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 137cf8f06a9..d1998f4eae3 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 > @@ -17,7 +17,26 @@ template<typename Layout> > typename Layout::mapping<extents_type> m3; // { dg-error "required > from" } > }; > > +template<size_t Count, typename Layout, typename OLayout> > + struct B // { dg-error "expansion of" } > + { > + using Extents = std::extents<uint8_t, dyn, dyn, Count>; > + using OExtents = std::extents<uint16_t, n, 4, Count>; > + > + using Mapping = typename Layout::mapping<Extents>; > + using OMapping = typename Layout::mapping<OExtents>; > + > + Mapping m{OMapping{}}; > + }; > + > 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_right> blr; // { dg-error > "required here" } > +B<2, std::layout_left, std::layout_stride> bls; // { dg-error > "required here" } > + > +B<3, std::layout_right, std::layout_left> brl; // { 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 e3e25528f33..19a6c8853e9 100644 > --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc > @@ -302,12 +302,111 @@ 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() > { > 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/mapping.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc > index 7cbb284492c..6a74c4d3c61 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_like<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; > } > > @@ -106,6 +109,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() > @@ -288,6 +324,15 @@ 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]); > + } > + > template<typename Layout> > constexpr void > test_stride_2d(); > @@ -310,6 +355,16 @@ 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]); > + } > + > template<typename Layout> > constexpr void > test_stride_3d(); > @@ -334,6 +389,18 @@ 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]); > + } > + > template<typename Layout> > constexpr bool > test_stride_all() > @@ -355,7 +422,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); > } > > @@ -496,8 +563,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..acb1f8060fe > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc > @@ -0,0 +1,494 @@ > +// { 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() > +{ > + using M1 = std::layout_stride::mapping<std::extents<int, 3>>; > + test_ctor_default_stride<M1>(); > + > + using M2 = std::layout_stride::mapping<std::extents<int, 3, 5, 7>>; > + test_ctor_default_stride<M2>(); > + 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; > + > + 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 > + { > + 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; > + } > + > + 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<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); > + } > + > +constexpr void > +test_is_exhaustive_zero_1d() > +{ > + std::extents<int, 0> extents; > + test_is_exhaustive(extents, std::array{1}, true); > + > + // Another case of exhaustive, but the formula prescribed by the > standard > + // doesn't allow recognizing it as exhaustive. (However, the > implementation > + // does.) > + test_is_exhaustive(extents, std::array{2}, true); > +} > + > +constexpr void > +test_is_exhaustive_zero_3d() > +{ > + std::extents<int, 3, 0, 7> extents; > + > + // This is exhaustive, and the current implementation recognizes it as > such, > + // but the standard requires returning `false`. > + 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); > + > + // Technically invalid, but the same mapping object can be constructed > via > + // the default ctor (which uses layout_right to create the zeros in the > + // strides). This case is unabiguously exhaustive. > + test_is_exhaustive(extents, std::array{0, 1, 1}, true); > + > + // Unabiguously exhaustive. > + 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 Mapping = std::layout_stride::mapping<std::extents<int, 0, 2>>; > + Mapping m1(std::extents<int, 0, 2>{}, std::array<int, 2>{1, 5}); > + Mapping m2(std::extents<int, 0, 2>{}, std::array<int, 2>{1, 5}); > + Mapping m3(std::extents<int, 0, 2>{}, std::array<int, 2>{5, 1}); > + > + VERIFY(m1 == m2); > + VERIFY(m1 != m3); > +} > + > +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 > >